Category: Development, Models and Methodologies

python: Abyss Webserver start and stop host from CLI

Reading time: 15 – 25 minutes

Petit script en python per iniciar/parar el Abyss Webserver des de la línia de comandes. Només hem de posar la URL d’on es troba la web de la consola de l’Abyss i l’ususari i el password per entrar-hi. Com que esta fet ràpid i corrents, no es suporta el pas de paràmetres per indicar si s’ha d’engegar i/o parar el servei en cada moment. Així que si algú s’anima a afegir-hi les 4 línies de codi que hi falten que me les digui, que jo encara no domino prou el python com per fer-ho en 1s i avui ja estic cansat.

import urllib2
<br>
theurl = 'http://127.0.0.1:9999'
username = 'theuser'
password = 'thepass'
<br>
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, theurl, username, password)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
<br>
data_start = "%2Fhosts%2Fhost%400%2Fstart=Start"
data_stop = "%2Fhosts%2Fhost%400%2Fstop=Stop"
<br>
data = data_start
<br>
request = urllib2.Request(theurl,data)
response = opener.open(request)
<br>
print response.readlines()

python: Autenticació HTTP de tipus basic-scheme

Reading time: 14 – 23 minutes

Com accedir a un serividor HTTP amb les pàgines protegides amb usuari i password del tipus Basic Authentication Scheme.

import urllib2
<br>
theurl = 'http://host:port'
username = 'theuser'
password = 'thepass'
<br>
# this creates a password manager
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
# because we have put None at the start it will always use this
# username/password combination
passman.add_password(None, theurl, username, password)
# create the AuthHandler
authhandler = urllib2.HTTPBasicAuthHandler(passman)
# Return an OpenerDirector instance, which chains the handlers in the
# order given Return an OpenerDirector instance, which chains the
# handlers in the order given
opener = urllib2.build_opener(authhandler)
# Install an OpenerDirector instance as the default global opener
urllib2.install_opener(opener)
# Open the URL url, which can be either a string or a Request object.
pagehandle = urllib2.urlopen(theurl)
lines =  pagehandle.readlines()
<br>
for line in lines:
    print line

L’autentació que usa l’Abyss Webserver per defecte és la del tipus explicada en aquest exemple.

python: Generar passwords d’usuaris per l’Abyss Webserver

Reading time: 15 – 24 minutes

L’Abyss Webserver guarda en un fitxer de configuració en format XML els usuaris i passwords. Doncs bé el format en que estan enmagatzemats els passwords en el fitxer XML és:

usercode = nom_usuari + ":" + plaintext_password
encoded_password = md5(base64(usercode))

Doncs bé aquí ve el petit trick de com fer això amb python:

#!/usr/bin/env python
import md5
import base64
import re
<br>
def genera_pass_abyss(usercode):
        b64usercode = base64.encodestring(usercode)
        b64usercode = re.sub('\n','',b64usercode)
        hash = md5.new(b64usercode)
        return hash.hexdigest()
<br>
user = 'usuari1'
passw = 'password1'
usercode = user + ":" + passw
print usercode
print genera_pass_abyss(usercode)

RSS 2.0 vs Atom 1.0

Reading time: 1 – 2 minutes

A IBM han escrit un article anomenat Implement news syndication using RSS and Atom (local en pdf). A part de l’interés propi del contingut de l’article pels programadors que vulguin un model UML de les classes que han de crear per exportar informació en aquests formats XML (RSS i Atom) a l’article hi ha un gràfic que m’ha ajudat molt a entendre les diferències entre RSS 2.0 i Atom. Perquè ambdós dona la sensació que són, fan i serveixen pel mateix. Doncs amb aquest gràfic podem acabar de confirmar-ho o desmentir-ho del tot.

pyGTK, Glade i SPE (Stani’s Python Editor)

Reading time: 2 – 4 minutes

SPE és l’editor que he començat a usar avui per programar en Python, concretament me l’he instal·lat per la facilitat d’acompletar les comandes especialment per accedir al binding de GKT+ (pyGTK). No és que m’hagi donat per programar en Python però porto un parell de dies liat amb el tema, ahir amb els webservices amb SOAP via SOAPpy i avui amb el pyGTK per tal de modificar una aplicació de compte enrera, concretament Countdown timer.

countdowntimer.png

Bàsicament el primer que he fet és modificar l’aparença de l’aplicació amb el Glade. Aquesta eina ens permet crear i editar GUI de forma senzillíssima. Arrossegant components i assignant mètodes que capturin les senyals dels components de l’aplicació, modificant els atributs dels components, etc. Realment sense tenir-ne ni idea el Glade ens crea un fitxer XML amb l’aparença d’una aplicació realment atractiva i còmode d’usar per l’usuari final.

glade.png

Tornant a l’SPE, doncs no esta malament és força còmode d’usar i té cosetes interessants, com ara la shell de python i un debuger. Però hi he trobat diversos inconvenients que em tenen una mica mosca. L’aplicació es penja moltíssim si usem el seu launcher per provar l’aplicatiu que estem desenvolupament. A més el debuger també es penja només invocar-lo. Suposo que deu ser algún problema de la instal·lació en gentoo.

spe.png

Però com a IDE també li trobo algunes mancances. Suposo que estic massa ben acostumat amb el Zend Studio. El problema esta en que jo voldria disposar d’ajuda en línia quan les opcions d’autocompletat de comandes es llencen així podria saber quina és la funció de GTK o Python que m’interessa en cada moment. Però no només no fa això sinó que la llista de funcions que dona per autocompletar sovint és reduida i no pas la llista completa de funcions suportades per l’objecte.

De fet, he trobat algún altre IDE per Python força interessant, com ara Wing IDE el problema és que és de pagament. Obviament sempre que puc uso vim. Però no vull acabar sent ni un expert de Python, ni de GTK, ni de pyGTK, ni res de tot això només sortir del pas el més ràpid possible amb aquesta necessitat i la veritat no trobo cap IDE que m’ajudi el suficient.

Qt SOAP – provant els webservices

Reading time: 1 – 2 minutes

A l’article Client SOAP genèric ja vaig parlar d’una pàgina web que a partir de la URL del WSDL ja podiem atacar el webservice d’una forma molt senzilla. El problema que té això és que quan estem dintre de la xarxa de l’empresa potser no tenim el webservice publicat a l’exterior d’internet. Doncs amb aquesta simple eina programada en Qt podem tenir una eina similar a la oferida per la pàgina web.

qtsoap.png

De moment encara no l’he provada però de ben segur ho hauré de fer aviat, així doncs si hi trobo algún inconvenient o avantatge descatbles, amplicaré aquest article sobre el Qt SOAP. Una cosa que ja he vist i que té molt bona pinta és que ens permet veure les HTTP headers de la petició i la respostes SOAP. A més podem definir el content-type de la petició cosa realment útil.

Generant RSS de les revisions de Subversion

Reading time: 2 – 2 minutes

rss.jpg

Quan treballes en un projecte on hi ha més d’una persona treballant contra un repositori de codi és molt bona idea poder-se sindicar via RSS a les noves revisions que es van publicant del codi i als comentaris associats a aquestes revisions. De fet, aconseguir això amb subversion no és gens difícil. Jo fins ara ho he fet amb el WebSVN (port del ViewCVS. A més gràcies al trac també podem obtenir aquests RSS i moltes més funcionalitats. Però tot això ja us ho he explicat. En alguns casos però ens pot interessar publicar aquests RSS sense haver de tenir programes orientats a altres funcionalitats sinó únicament aprofitar les extencions WebDAV/DAV_SVN per publicar els RSS. Això és el que ens expliquen a l’article HOWTO: Adding an RSS feed to a Subversion Server (local).

De fet, el que planteja aquest article és força senzill. Simplement usa un generador d’RSS a partir de les revisions de l’SVN, l’script esta fet en python i després li diem al subversion que després de cada commit que es fassi al repositori es genir un nou fitxer RSS. Així doncs el tema no té cap misteri però va bé tenir-ho en un howto per si mai fa falta.

Phalanger: the PHP Language Compiler for .NET Framework

Reading time: 2 – 2 minutes

dotNet.jpg

Ja coneixia aquesta solució però mai recordava el nom que tenia, de fet, encara no l’he pogut provar mai però pel que he vist a la web en principi qualsevol dels nostres codis fets en PHP hauria de poder-se compilar en bytecode perquè pogués correr en un servidor web ASP.NET.

Penseu el senzill que serà doncs, usar codi des de .NET que haguem fet amb PHP o alrevés, si ja disposem de classes implementades en C# O VB.NET les podrem usar tranquilament des de PHP.

Llàstima que no m’hagi posat mai ni en .NET ni mono ni res de res. A més dubto que ho fassi perquè no és la meva feina, però per alguns codis que tinc fets a la feina en PHP em seria una gran avantatge poder-los fer corre directament sobre infraestructures complemtament windows, així no hauria de portar els codis de PHP a llenguatges més complexos per tal de fer-los corre en servidors 2000 o 2003 amb ISS i .NET.

Per ampliar més informació us recomano la web de Phalanger és força completa i té molta documentació si algú proba mai el compilador que m’avisi ja que hi estic molt interessant però em suposaria molta feina provar-lo amb la infraestructura que tinc montada ara mateix. A més no tinc ni idea de .NET.

symfony: protegint els entorns de desenvolupament, integració i producció

Reading time: 7 – 12 minutes

A l’article symfony: entorns de desenvolupament, integració i producció es pot entendre el perquè de treballar amb aquests tres espais de noms (environment) així doncs el que es preten explicar és:

  • Impedir accés a les aplicacions en entorns de ‘dev’ i ‘int’ des de llocs no controlats. O sigui, que una IP d’internet no pugui executar myapp_dev.php o myapp_int.php però encanvi una IP de la xarxa del desenvolupador si que pugui.
  • Impedir accés a aplicacions de backend des de l’entorn de producció. Si hem desenvolupat alguna aplicació per tal de fer el manteniment de l’aplicació principal, una part d’administració o backend aquesta no sigui accessible des d’IPs no controlades.
  • Separar el fitxer de configuració config/cofnig.php per cada un dels entorns. Així podem definir constants o d’altres tasques de forma particular per cada un dels entorns.

Per tal d’aconseguir aquests objectius he creat el fitxer config/config.lib.php:

<?php
/**
 * Comproba si la IP amb la que s'accedeix a l'aplicació permet connectar en aquest environment
 *
 * @param string $env nom de l'environment
 * @param array $ips ips des de les que podem accedir a l'environment
 * @param string $clientip ip del client que vol accedir al recurs
 */
function envCorrecte ($env,$ips,$clientip)
	{
	if (SF_ENVIRONMENT==$env)
	{
		$acces=0;
			foreach($ips as $ip)
		{
			$ipclient=substr($clientip,0,strlen($ip));
				if ($ipclient==$ip)
			{
				$acces=1;
				}
		}
		if ($acces==0)
			{
			echo "You are not in '".$env."' environment! (".$ipclient."<>".$ip.")";
				exit;
		}
	}
}
/**
 * Comproba si l'aplicació amb la que s'accedeix al projecte és publica o no
 *
 * @param array $apps llista d'aplicacions no públiques
 * @param array $ips llista d'IP amb les que es pot accedir a les apps no públiques
 * @param string $clientip ip del client que vol accedir al recurs
 */
function appCorrecte ($apps,$ips,$clientip)
	{
	// solucionem problema de la clau '0'
    	$apps_aux[0]='';
		$apps = $apps_aux + $apps;
	//
	if (array_search(SF_APP,$apps)!=false)
		{
		$acces=0;
		foreach($ips as $ip)
			{
			$ADR=$HTTP_SERVER_VARS['REMOTE_ADDR'];
			$ipclient=substr($clientip,0,strlen($ip));
				if ($ipclient==$ip)
			{
				$acces=1;
				}
		}
		if ($acces==0)
		{
				echo "Keep away! ".SF_APP." is not a public application!";
			exit;
		}
		}
}
?>

Llavors des del fitxer config/config.php cal que cridem aquesta petita llibreria de funcions que he creat. La resta és més que lògica, aquí en teniu un exemple:

<?php
include("config.lib.php");
/**
 * Controlem accés als 'environments' de 'env' i 'int'
 */
$ip_dev=array("10.138.0.","192.168.");
$ip_int=array("10.138.0.","192.168.");
envCorrecte('env',$ip_env,$HTTP_SERVER_VARS['REMOTE_ADDR']);
envCorrecte('int',$ip_int,$HTTP_SERVER_VARS['REMOTE_ADDR']);
/**
 * Controlem accés a les 'apps' d'ús privat
 */
$ip_apps=array("10.138.0.","192.168.","w.x.y.z");
$apps=array('myapp_1','myapp_2','myapp_n');
appCorrecte($apps,$ip_apps,$HTTP_SERVER_VARS['REMOTE_ADDR']);
/**
 * Carreguem el fitxer de configuració propi de l'"environment".
 */
include("config.".SF_ENVIRONMENT.".php");
/**
 * Part comú en els 3 entorns
 */
?>

Com podeu veure el codi és molt senzill i la potència i el dinamisme, excepcionals.

Aquest codi també l’he publicat com un snippet a Access control to environment and applications and custom global config file for an environment.

symfony: entorns de desenvolupament, integració i producció

Reading time: 3 – 4 minutes

Al desenvolupar un projecte de software m’agrada treballar en 3 entorns. Mentre s’esta desenvolupant el projecte esta bé tenir un espai de variables (o entorn de noms) a l’aplicació que correspongui als ajustaments del servidor de desenvolupament (normalment una màquina pròpia), per exemple, els path, urls, dades de la bbdd, etc. tot això ha d’estar el màxim separat possible del codi per tal de poder crear les configuracions pels entorns d’integració i producció.

L’entorn d’integració és una màquina en l’entorn de desenvolupament del client, amb les característiques el més semblants possibles a l’entorn de producció. O sigui, les dades de configuració de l’espai de noms han d’apuntar a serveis si pot ser de la mateixa versió que l’entorn de producció. Així podem provar l’aplicació i millores de l’aplicació abans de passar-la a producció. Finalment hem de tenir l’entorn de noms per producció amb les dades de treball.

Per tal de suportar tot això symfony suporta en moltíssims fitxers de configuració la possibilitat de definir l’environment, en el cas que plantejo, ‘dev’, ‘int’ i ‘prod’. En el front controller de cada aplicació podem definir aquest entorn de noms així després s’accedirà a la part dels fitxers de configuració que pertoca.

Per exemple, si mirem el fixer config/databases.yml on symfony defineix els sistemes de BBDD que usa la nostre aplicació en cada un dels environments podriem tenir algo així:

dev:
  nombbdd:
    class:           sfPropelDatabase
    param:
      phptype:       mysql
      hostspec:      localhost
      database:      nombbdd
      username:      userbbdd
      password:      passbbdd
int:
  nombbdd:
    class:          sfPropelDatabase
    param:
      phptype:      oracle
      username:     nombbdd
      password:     nombbdd
      hostspec:     hostint
      database:     NULL
prod:
  nombbdd:
    class:          sfPropelDatabase
    param:
      phptype:      oracle
      username:     nombbdd
      password:     nombbdd
      hostspec:     hostprod
      database:     NULL

Al cridar el front controller és quan symfony diu amb quin environment treballarem, per exemple, per una aplicació anomenada myapp podriem tenir aquests tres front controllers un per cada entorn:

Entorn de desenvolupament web/myapp_dev.php:

<?php
define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/..'));
define('SF_APP',         'myapp');
define('SF_ENVIRONMENT', 'dev');
define('SF_DEBUG',       true);
#
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
#
sfContext::getInstance()->getController()->dispatch();
?>

Entorn de integració web/myapp_int.php:

<?php
define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/..'));
define('SF_APP',         'myapp');
define('SF_ENVIRONMENT', 'int');
define('SF_DEBUG',       true);
#
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
#
sfContext::getInstance()->getController()->dispatch();
?>

Entorn de producció web/myapp.php:

<?php
define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/..'));
define('SF_APP',         'myapp');
define('SF_ENVIRONMENT', 'prod');
define('SF_DEBUG',       false);
#
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
#
sfContext::getInstance()->getController()->dispatch();
?>

Com es pot veure, tan desenvolupament com integració ens mostraran informació de debug i producció amagarà els missatges d’error i reportarà sempre l’error “internal server error”. A més podem veure que tots tres entorns criden el mateix fitxer de configuració global config/config.php.

Si voleu més informació sobre aquest tema us recomano els següents enllaços de la documentació de symfony:

Scroll to Top