puppet agent con variables

a veces necesitamos que una clase de puppet reciba variables desde el punto en el que se ejecuta el agente, desde el entorno. Por ejemplo, una clase de puppet encargada de comprobar si hay conectividad a un host remoto, a un puerto dado.

si antes de lanzar el agente fijamos variables de entorno con la forma FACTER_variable, luego serán visibles desde el manifest.

El problema es que este procedimiento implica “meter” el valor en la maquina de alguna forma (via ssh?), con lo que abrimos la puerta a otras vias de comprobación, mas allá de puppet agent

otra opcion, teniendo Foreman+Katello a mano es usar los smart class parameters, que se pueden definir con “matchers”, de forma que una asignacion del parametro solo aplique a un hostname (fqdn) determinado (!)

Tunebook en The Session

hace años que ando a rastras con un repertorio de flauta irlandesa que poco a poco he ido sacando. Ahora, con el spotify es tan sencillo anotar lo que se va oyendo que da pena no hacerlo. En The Session cada usuario puede hacer su playbook, y seria una buena cosa el recopilar el de los papeles, mas las anotaciones hechas por aqui, mas lo que sale del curso de OAIM

adivinen ustedes de donde salio el repertorio irlandes que tengo en papeles desde hace 12 años…? Efectivamente, era una impresion de ABC2Win del tunebook que tengo desde aquella epoca en The Session…!!!

Ha sido una pasada volver a entrar en la cuenta, y ver que seguian alli los temas…!

puppet class: check remote ports

probablemente utilizando este codigo en ruby como una funcion, seria suficiente?

aunque es mas sencillo utilizar los superpoderes de netcat:

nc -z <ip remota> <puerto remoto>

si nos devuelve 0, es que todo ha ido bien: hay alguien al otro lado escuchando. En cualquier otro caso, error.

la clase de puppet que hace el trabajo queda asi:

# check.pp

class checkport::check (

  $port         =       hiera('port'),
  $address      =       hiera('address'),

) {

#  notify { "/usr/bin/nc -z ${address} ${port}": }

  package { 'nc':
    ensure      =>      'present',
  }

  exec { 'checking remote port':
    command     =>      "/usr/bin/nc -z ${address} ${port}",
    require     =>      Package['nc'],
  }

}

Aunque si queremos comprobar varios puertos, mejor seria agrupar los datos en un hash, e iterar sobre ellos. Al viejo estilo:

# check.pp

class checkport::check (


) {

  $remotes      =       hiera_hash('remotes')

#  notify { "/usr/bin/nc -z ${address} ${port}": }
  notify { "destino: ${remotes} ": }

  package { 'nc':
    ensure      =>      'present',
  }

  define comprobador() {
    $remotes    =       $checkport::check::remotes
    $puerto     =       $remotes[$name]

    notify { "checking ${name} ${puerto}": }

    exec { "checking ${name}":
      command   =>      "/usr/bin/nc -z -w 2 ${name} ${puerto}",
#      command  =>      "/bin/echo '/usr/bin/nc -z ${name} ${puerto} \n' >>/tmp/exec.txt",
      require   =>      Package['nc'],
    }
  }


  $indexes = keys($remotes)

  comprobador { $indexes: }

}

Un hash de ejemplo seria:

---
remotes:
  172.17.0.2:
    80
  172.17.0.1:
    80

 

primera aproximacion al juego de sensores, mas punto de rocio

leyendo en el sensor de temperatura SEN118A2B,

y escribiendo el estado en la pantalla LCD.

calcular el punto de rocio es relativamente sencillo.

con un transformador que saca 1A bajamos la temperatura de la zona fria desde 27 a 19 grados, con un ventilador y un disipador de CPU pequeño. Sin disipador el lado caliente sube hasta 70 grados, por lo menos. Sin disipador, la zona fria apenas baja 2 grados: el calor de la zona caliente se desborda. Es imprescindible ventilar, refrigerar la zona caliente.

el sketch que controla sensor y pantalla es:

// LCD
#include <Wire.h>
#include <MatrixOrbitali2c.h>
#include <stdlib.h>
MatrixOrbitali2c lcd(0x2B);

// sensor de temperatura
#include <math.h>
#define ThermistorPIN 0  // Analog Pin 0
float vcc = 4.91; 
float pad = 46000; 
float thermr = 10000; 
float Thermistor(int RawADC) {
  long Resistance;  
  float Temp;  // Dual-Purpose variable to save space.
  Resistance=((1024 * pad / RawADC) - pad); 
  Temp = log(Resistance); 
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + 
         (0.0000000876741 * Temp * Temp * Temp));
  Temp = Temp - 273.15;  // Convert Kelvin to Celsius                      
  return Temp;    // Devolver temperatura
}

// sensor de humedad y temperatura
#include <DHT.h>
#define DHTPIN 2     // what pin we're connected to
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);
float tF;
float dP;
float dPF;

void setup() {
  Serial.begin(9600);
  lcd.begin(4,20);
  dht.begin();
}

void loop() {

  float h = dht.readHumidity();
  float t = dht.readTemperature();
  if (isnan(t) || isnan(h)) {
//    Serial.println("Failed to read from DHT");
  } else {
//    Serial.print("Humidity: ");
//    Serial.print(h);
//    Serial.print(" %\t");
//    Serial.print("Temperature: ");
//     Serial.print(t);
//     Serial.print(" *C ");
    tF=((t*9)/5)+32;
//    Serial.print(tF);
//    Serial.print(" *F ");
//    Serial.print(" \t"); 
//    Serial.print("Dew Point: ");
//    Serial.print(dewPointFast(t, h));
//    Serial.print(" *C ");
  dP=(dewPointFast(t, h));
  dPF=((dP*9)/5)+32;
//  Serial.print(dPF);
//  Serial.print(" *F");
//  Serial.print(" \t");
//  Serial.print("Heat Index: ");
//  Serial.print(heatIndex(tF,h));
//  Serial.println(" *F");
  }  
  float temp;
  float celsius;
  celsius = Thermistor(analogRead(ThermistorPIN)); 
//  Serial.print("Celsius: "); 
//  Serial.print(celsius,1);  // display Celsius        
//  Serial.println("LCD Clear");
  lcd.clear();
//  Serial.println("Hello World");
  lcd.print("Temp sonda: ");
  lcd.print(celsius);
  lcd.print("\n");
  lcd.print("Temp aire: ");
  lcd.print(t);
  lcd.print("\n");
  lcd.print("Hum aire: ");
  lcd.print(h);
  lcd.print("\n");
  lcd.print("DewPoint: ");
  lcd.print(dewPointFast(t, h));
  lcd.print("\n");
  delay(1000);
}

// delta max = 0.6544 wrt dewPoint()
// 6.9 x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
 double a = 17.271;
 double b = 237.7;
 double temp = (a * celsius) / (b + celsius) + log(humidity*0.01);
 double Td = (b * temp) / (a - temp);
 return Td;
}
double heatIndex(double tempF, double humidity)
{
  double c1 = -42.38, c2 = 2.049, c3 = 10.14, c4 = -0.2248, c5= -6.838e-3, c6=-5.482e-2, c7=1.228e-3, c8=8.528e-4, c9=-1.99e-6  ;
  double T = tempF;
  double R = humidity;
  double A = (( c5 * T) + c2) * T + c1;
  double B = ((c7 * T) + c4) * T + c3;
  double C = ((c9 * T) + c8) * T + c6;
  double rv = (C * R + B) * R + A;
  return rv;
}

water harvest

Un proyecto con tecnologia, aire, agua y luz.

Se trata de validar la hipotesis de la obtencion de agua a partir de la condensación de la humedad del aire enfriado por debajo del punto de rocio gracias a un medio líquido refrigerado usando el efecto peltier con energia solar. Todo gobernado por la inteligencia de un arduino y los datos de un puñado de sensores. Y conectado a internet para obetener datos meteorologicos (prediccion, punto de rocio) y volcar métricas de estado (humedad relativa, temperatura, temperatura del medio refrigerante, …)

mas notas:

water harvest, ya puestos

Si tenemos acceso a internet desde alguna parte de la inteligencia local, puede que sea posible variar las condiciones del automata para adaptarse a las condiciones locales, a partir de informacion sacada de sitios como este. Aunque igual es matar moscas a cañonazos, porque el punto de rocio se puede calcular a partir de temperatura del aire y humedad relativa.

Sabiendo el punto de rocio, sabemos hasta que temperatura tenemos que bajar el medio liquido para enfriar el serpentin donde el aire se condensa… O un poco mas, para facilitar el transito…

Pythonista, licensing

 

#
#
# Copyright 2016 xxx xxxx
#
# This file is part of xxxxxx.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##################

Pythonista, argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--debug',
                        help='show debug messages',
                        action='store_true')
    parser.add_argument('-v', '--version',
                        help='show version info',
                        action='version',
                        version=VERSION)
    parser.add_argument('-s','--serial',
                        action='store',
                        help = 'serial port')
    parser.add_argument('-p','--port',
                        action='store',
                        help = 'carbon server port')
    parser.add_argument('-c','--carbon',
                        action='store',
                        help = 'carbon server')
    args = parser.parse_args()

    if args.debug:
        logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',level=logging.DEBUG)
    else:
        logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',level=logging.ERROR)

    if args.serial:
        global SERIAL_PORT
        SERIAL_PORT = args.serial
    if args.port:
        global CARBON_PORT
        CARBON_PORT = args.port
    if args.carbon:
        global CARBON_SERVER
        CARBON_SERVER = args.carbon

mas en el tutorial oficial

pythonista, checklist

checklist a incorporar en todo script python, para avanzar en un proceso de modernizacion (!)

# to-do: 
# - licensing (aqui)
# - from print to logger (aqui)
# - 4 indentation (aqui)
# - de commands.getoutput a Popen (aqui)
# - unspaghetti (parentesis y salto de linea)
# - utf8 (aqui)
# - argparse, ayuda y argumentos (aqui)
# - string interpolation, not concatenation (aqui)
# - no import *
# - review variable names _, english
# - de string.find a in (aqui)
# - review unspanish
# - +=
# - function docstrings
# - try: except: in imports

Pythonista, logging y loglevels

el 99% de los PRINTs de los scripts son mensajes de log, en diferentes LOGLEVELS.

Para una primera iteracion solo usamos salida estandar por terminal (no fiechero)

  • en cada caso diferenciar el loglevel al que pertenecen
  • inicializar el logging:
logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s', level=logging.DEBUG)
  • sustituir todos los print por logging

 

Pythonista, de commands.getoutput a Popen

hace 8 años que se deprecó commands, y el japones seguia alerta en su isla desierta, sin saber que la guerra ya habia terminado.

pasos:

  • partimos de un comando en un string
  • el resultado es la salida, como string, para ser procesado por quien siga
  • pasar el string del comando por shlex.split:
    args = shlex.split(comando)
    proceso = Popen(args, stdout=PIPE, stderr=PIPE, shell=False)
    salida, error = proceso.communicate()
    if proceso.returncode !=0:
        print("mal")

    Despues hay que atender al contenido de proceso.returncode, si es distinto de cero, algo ha ido mal

  • para dos comandos unidos por pipe:
mensaje = "sensor.medida.temp {} {}".format( t, int(time()))
logging.debug(mensaje)
comando1 = ['echo ',  mensaje ]
comando2 = [ 'nc', '-q0', CARBON_SERVER, CARBON_PORT]
proc1 = Popen(comando1, stdout=PIPE, shell=False)
proc2 = Popen(comando2, stdin=proc1.stdout, stdout=PIPE, shell=False)
logging.debug(proc2.communicate()[0]
  • habiendo importado lo necesario:
from subprocess import Popen, PIPE

Spinoza: filosofía práctica – Gilles Deleuze

El tirano necesita para triunfar la tristeza de espíritu, de igual modo que los ánimos tristes necesitan a un tirano para propagarse y satisfacerse. Lo que los une, de cualquier forma, es el odio a la vida, el resentimiento contra la vida. La Ética dibuja el retrato del hombre del resentimiento, para quien toda felicidad es una ofensa y que hace de la miseria o la impotencia su única pasión.

Spinoza: filosofía práctica – Gilles Deleuze

Spinoza denuncia sin cansancio en toda su obra tres figuras ejemplares distintas: el hombre de pasiones tristes, el hombre que se sirve de estas pasiones tristes, que las necesita para asentar su poder, y, finalmente, el hombre a quien entristece la condición humana, las pasiones del hombre en general