TileMill | prima installazione su Debian

In questo breve post volevo tenere traccia delle operazioni eseguite per installare TileMill su Debian. Sul sito si trovano i pacchetti per Ubuntu, Mac OS X e Windows…..Io uso Debian in genere (anche i due timidi serverini che gestisco) e volevo capire se era fattibile: si!

Ho seguito passo-passo le istruzioni riportate nella pagina “Building from source” e ne riassumo i passi salienti:

– controllare di avere i python development headers, libbz2, libicu, boost, icu, proj4 ed altre svariate librerie di immagini (synaptic aiuta molto);

– installare boost da sorgente (la versione pacchettizzata per Debian non è aggiornata) seguendo questi passi:

(piccolo inciso: in genere – ma questa è una mia prassi – le compilazioni le faccio all’interno di una directory chiamata “src” e per ogni pacchetto creo una subdirectory ad hoc).

creare una directory per la compilazione:

$ mkdir boost

spostarsi nella dir creata:

$ cd boost

scaricare il sorgente con:

$ wget http://voxel.dl.sourceforge.net/project/boost/boost/1.51.0/boost_1_51_0.tar.bz2

decomprimere il tar:

$ tar xjvf boost_1_51_0.tar.bz2

spostarsi nella dir ottenuta dalla decompressione:

$ cd boost_1_51_0

lanciare il comando

$ ./bootstrap.sh

poi in sequenza:

$ ./b2 stage toolset=gcc –with-thread –with-filesystem –with-python –with-regex -sHAVE_ICU=1 -sICU_PATH=/usr/ –with-program_options –with-system link=shared

$ ./b2 install toolset=gcc –with-thread –with-filesystem –with-python –with-regex -sHAVE_ICU=1 -sICU_PATH=/usr/ –with-program_options –with-system link=shared

infine autenticarsi come root ed impartire:

# ldconfig

Poi installare anche boost >= 1.47, icu, proj4, libpng, libjpeg, libtiff, libxml2, libltdl, e freetype (a meno di averle già)

– Passiamo ora all’installazione di Mapnik (motore di rendering per TileMill). Come prima creiamo una dir per la compilazione:

$ mkdir mapnik

ci spostiamo nella dir

$ cd mapnik

e scarichiamo il sorgente con:

$ wget https://github.com/downloads/mapnik/mapnik/mapnik-v2.1.0.tar.bz2

decomprimiamo:

$ tar xf mapnik-v2.1.0.tar.bz2

ci spostiamo nella nuova directory:

$ cd mapnik-v2.1.0

e lanciamo il configure:

$ ./configure (durante il configure sono stato avvisato della mancanza di alcune librerie – che mi erano sfuggite – le ho quindi installate con synaptic e poi ho reimpartito il configure)

poi il make

$ make

ed infine il make install (come root):

# make install

– E’ la volta di Node.js: compiliamo anche questo (come prima creiamo la dir di lavoro):

$ mkdir nodejs

ci spostiamo della dir nuova:

$ cd nodejs

scarichiamo il sorgente:

$ wget http://nodejs.org/dist/v${VERSION}/node-v${VERSION}.tar.gz (nel mio caso ho scaricato la versione v0.8.14 quindi la stringa “v${VERSION}” diventa “v0.8.14”)

decomprimiamo:

$ tar xf node-v0.8.14.tar.gz

ci spostiamo nella dir:

$ cd node-v0.8.14

e lanciamo configure, make e make install

$ ./configure && make

e come root:

# make install

Prima di passare all’installazione di TileMill installare un’altra dipendenza chiamata “libwebkit-dev” che si può tranquillamente installare con “apt-get install libwebkit-dev”

Ed ora passiamo a TileMill:

$ mkdir tilemill

ci spostiamo nella dir:

$ cd tilemill

scarichiamo il sorgente:

$ git clone https://github.com/mapbox/tilemill.git

poi si entra nella dir ottenuta:

$ cd tilemill

ed infine si installa tutto mediante “npm”

# npm install

<inizio NB>:La prima volta che ho lanciato “npm install” il comando è terminato con degli errori riferiti a nodejs. La causa era una versione troppo recente di nodejs avendo inizialmente installato la versione v0.9.1. Installando la v0.8.14 dopo avere rimosso la v0.9.1 tutto è andato a buon fine. La rimozione di nodejs si può fare così (fonte il mitico stackoverflow):

– lanciare il comando “which node” che dovrebbe ritornare qualcosa come “/usr/local/bin/node”

– poi ci spostiamo in /usr/local/bin/node”

– e lanciamo come root:

# rm -r bin/node bin/node-waf include/node lib/node lib/pkgconfig/nodejs.pc share/man/man1/node.1

Poi possiamo ritornare a scaricare la nuova versione di nodejs ed a ricompilare. <fine /NB>

Una volta che tutto è compilato lanciare il comando:

$ ./index.js

compare l’interfaccia di TileMill. Analogo risultato si ottiene mediante un browser puntando su “http://localhost:20009&#8221;.

Ed ecco un paio di screenshot:

Tile Mill versione desktop

Tile Mill versione web

il mio primo “hello world” con TileMill

Il Repertorio Nazionale dei Dati Territoriali

Il Repertorio Nazionale dei Dati Territoriali

Oggi inserisco un post con il link al Repertorio Nazionale dei Dati Territoriali (RNDT). Attualmente questo strumento sta muovendo i primi passi, ma il desiderio è che entri a fare parte della “cassetta degli attrezzi” di ogni geomatico e, in prospettiva, di ogni cittadino italiano. Non sono solo, ma insieme a:”

QGIS web client | hyperlink

Una delle cose “cool” (come dicono gli americani) di un web gis è la possibilità di consultare gli attributi di un oggetto e magari essere reindirizzati ad altro link o file o pagina web per approfondire o avere maggiori informazioni sull’attributo selezionato.
Ad oggi QGIS web client offre due modi per consultare gli attributi: mediante il “fumetto” o “tooltip” o cliccando sull’oggetto dopo avere attivato il pulsante di consultazione attributi e “leggendo” i dati nel frame di destra che compare.
Se però vogliamo creare un hyperlink cliccabile non possiamo farlo con il tooltip in quanto si sposta allo spostarsi del mouse. A questo riguardo Andreas Neumann sta lavorando per fare in modo che il fumetto sia in pieno stile Openlayers. Qui si trova l’issue in merito.
Ma chiedendo in lista qgis-user è arrivato un provvidissimo suggerimento di Bernhard Ströbl (che ringrazio vivamente). Bernahrd ha suggerito di creare una VIEW (in database PostgreSQL/PostGIS) contenente un campo “link” formattato in pieno stile html. Ho provato e funziona! Riporto di seguito un esempio testato.

pc=# CREATE OR REPLACE VIEW prp_view AS SELECT “Denominazi” AS denominazione, tipo, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione1 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta prima approvazione</a>’::TEXT AS link1, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione2 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta seconda approvazione</a>’::TEXT AS link2, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione3 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta terza approvazione</a>’::TEXT AS link3, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione4 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta quarta approvazione</a>’::TEXT AS link4, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione5 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta quinta approvazione</a>’::TEXT AS link5, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione6 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta sesta approvazione</a>’::TEXT AS link6, the_geom, gid FROM sua;

In questo modo cliccando sulla voce relativa (“prima approvazione”, “seconda approvazione” e così via) che compare nel frame di destra si apre il file PDF in questione.

QGIS web client | search

Questo post tratta nuovamente Qgis web client: in particolare come viene gestita la ricerca delle feature.

Seguendo la doc disponibile in rete (e all’interno del pacchetto) al punto 6 si parla dello script python per la gestione della ricerca. Tutto sembra ok. Tuttavia la doc illustra come creare una tabella per la ricerca; ma una tabella puo’ diventare “statica” nel momento in cui i dati del database (nel nostro caso PostgreSQL/PostGIS) vengono aggiornati. In questo caso una view diventa l’ideale in quanto “dinamica” anche se i tempi di ricerca possono risultare superiori rispetto ad una tabella.

Calando il tutto nel concreto del nostro applicativo facciamo alcune considerazioni. Dispongo di un DB con molti strati informativi. Nel progetto “.qgs” in questione ci sono tre layer sui quali vorrei eseguire la ricerca: uno relativo agli edifici, uno relativo alle strade ed uno relativo alle particelle catastali. Il primo step consiste nella creazione di una view per la ricerca delle strade. Ecco come viene definita:

#= CREATE OR REPLACE VIEW search_particella AS SELECT ‘Foglio’ || “Foglio” || ‘,’ || ‘Mappale’ || “Mappale” AS searchstring, ‘Foglio’||”Foglio”||’, ‘||’Mappale’||”Mappale”::TEXT AS displaytext, ’03_particella’::TEXT AS search_category, the_geom, ‘MULTIPOLYGON’::TEXT AS geometry_type, to_tsvector(“Foglio”||’, ‘||”Mappale”::TEXT) AS searchstring_tsvector FROM particella;

Una seconda view è stata creata per la ricerca sugli edifici:

#= CREATE OR REPLACE VIEW search_schede_a AS SELECT codfoto AS searchstring, codfoto::TEXT AS displaytext, ’01_schede_a’::TEXT AS search_category, the_geom, ‘MULTIPOLYGON’::TEXT AS geometry_type, to_tsvector(codfoto::TEXT) AS searchstring_tsvector FROM schede_a;

Ed infine per le strade:

#= CREATE OR REPLACE VIEW search_strade AS SELECT nome AS searchstring, nome::TEXT AS displaytext, ’02_strade’::TEXT AS search_category, the_geom, ‘MULTILINESTRING’::TEXT AS geometry_type, to_tsvector(nome::TEXT) AS searchstring_tsvector FROM view_grafo_union_nome;

Altra considerazione importante: potendo gestire e pubblicare piu’ progetti (.qgs) differenti diventa essenziale fare in modo che ad ogni progetto possa essere abbinata una certa configurazione per la ricerca. Questo è possibile personalizando il file “search.wsgi” che si trova in “…/qgis-web-client/wsgi”. Basta rinominarlo in modo che richiami il progetto abbinato (es: “search_stradario.wsgi” per una progetto che pubblica lo stradario) e modificando la riga 18 secondo le proprie necessità. Esempio:

“…….
searchtables = [‘search_strade‘]; # enter your default searchtable(s) here # aggiungere qui ‘a mano’ i nomi delle tabella di ricerca
searchtablesstring = ”;
…”

Come si puo’ vedere abbiamo indicato qui il nome della tabella (nel nostro caso una VIEW) da usare per effettuare la ricerca. Se volessimo utilizzare piu’ tabelle (o VIEW) basta aggiungerle separandole con una virgola. Nel nostro caso potrebbe diventare:

“…….
searchtables = [‘search_strade‘, ‘search_particella‘]; # enter your default searchtable(s) here # aggiungere qui ‘a mano’ i nomi delle tabella di ricerca
searchtablesstring = ”;
…”

Non dimenticare poi che bisogna modificare anche il corrispondente file “GlobalOptions.js” relativo. Nel mio caso ho creato un file per ognuno dei progetti. Per esempio per il progetto dello stradario ho creato un “GlobalOptionsStradario.js” (ed un “getSearchGeom_stradario.js”) all’interno del quale alla righe 14 e 15 ho indicato il path ai file da utilizzare per la search.

“….

var searchBoxQueryURL = “/qgis-web-client/wsgi/search_stradario.wsgi?query=”; // “/wsgi/search.wsgi?query=”;
var searchBoxGetGeomURL = “/qgis-web-client/wsgi/getSearchGeom_stradario.wsgi”; // “/wsgi/getSearchGeom.wsgi”;

…..”

Allego snapshot che mostra la ricerca di un mappale; digitando semplicemente il numero del foglio (21) e ponendo una virgola subito dopo compariranno i mappali già filtrati per foglio. Cliccando su quello di interesse l’area geografica verrà portata alla sua boundingbox.

ricerca in qgis web client

QGIS web client | tooltip

Qgis web client è un framework webgis che consente di pubblicare un progetto Qgis (file con estensione .qgs) as is.

Tra le funzionalità presenti troviamo la possibilità di visualizzare come tooltip (una specie di “fumetto” dinamico che aggiorna i dati a seconda dell’oggetto su cui “insiste” il mouse) i dati delle feature.

Tuttavia attualmente non è possibile impostare quali attributi visualizzare; è necessario creare un nuovo campo chiamato proprio “tooltip” e popolarlo con i dati che si vogliono vedere. Nel mio esempio faccio riferimento a dati di alcuni edifici (memorizzati in tabella Postgis). Dopo avere creato il campo suddetto lo popoliamo:

=# UPDATE schede_a SET tooltip=’scheda: ‘ || codfoto || ‘ , tipologia: ‘ || tipologia_edilizia || ‘ , destinazione: ‘ || destusopre || E’\r\n’ || ‘volume: ‘ || volume_ft || ‘ , ‘ || ‘altezza: ‘ || altezza_media || ‘ , epoca: ‘ || epoca_costruzione || E’\r\n’ || ‘<img src=’ || ‘”‘ ||  immagine ||  ‘”‘ || ‘>’;

Analizziamo la stringa.

schede_a è il nome della tabella;

– poi si esegue un UPDATE sul campo “tooltip” popolandolo con note descrittive (le parti fra ‘apici singole’ unite (con il doppio pipe “||“) ai valori dei campi indicati (codfoto, tipologia_edilizia, destusopre,…..).

– la stringa E’\r\n consente di andare a capo. Questo è molto utile se i dati da visualizzare sono molti evitando di avere un “fumetto” troppo esteso in larghezza e di difficile lettura;

– l’ultima parte ‘<img src=’ || ‘”‘ ||  immagine ||  ‘”‘ || ‘>’ (in realtà un pezzo di condice html) consente di caricare e visualizzare una foto dell’edificio stesso; il campo “immagine” contiene il path (sul server di archiviazione) all’immagine da aprire.

Allego piccolo snapshot:

tooltip con visualizzazione dati di un edificio e relativa immagine

Una nota che potrebbe tornare utile: così facendo (creare un campo tootlip come “aggregazione” di piu’ campi) succede che nel tempo e’ necessario aggiornare di volta in volta i valori. Per evitare di doverlo fare manualmente si potrebbe creare un trigger che ad ogni INSERT o UPDATE dei record aggiorni di conseguenza tooltip. Altrimenti si potrebbe creare una VIEW che pesca tutti i valori della tabella edifici (escluso tooltip) aggiungendo il campo tooltip stesso in maniera “dinamica”. Ecco riportato il comando SQL per la creazione della VIEW che è stata poi caricata nel progetto QGIS.

#= SELECT schede_a.gid, schede_a.”KP”, schede_a.codfoto, schede_a.immagine, schede_a.codviaana4, schede_a.via1, schede_a.numciv1, schede_a.codviaana1, schede_a.via2, schede_a.numciv2, schede_a.codviaana2, schede_a.via3, schede_a.numciv3, schede_a.codviaana3, schede_a.via4, schede_a.numciv4, schede_a.destusopre, schede_a.utilizzazione, schede_a.epoca_costruzione, schede_a.altezza_media, schede_a.condizioni_fisiche, schede_a.tipologia_edilizia, schede_a.qual_stor_amb, schede_a.note, schede_a.fonte, schede_a.rilevatore, schede_a.dens_allog_utiliz, schede_a.dens_allog_nonutiliz, schede_a.tipo_mod, schede_a.data_mod, schede_a.link, schede_a.num_provv_orig, schede_a.num_provv_def, schede_a.volume_ft, schede_a.alloggi_occupati, schede_a.alloggi_nonoccupati, schede_a.superf_coperta, schede_a.alloggi_totali, schede_a.tipo_provv_orig, schede_a.tipo_provv_def, schede_a.the_geom, schede_a.anno, schede_a.”time”, schede_a.forever, ((((((((((((((((((‘scheda: ‘::text || schede_a.codfoto::text) || ‘ , tipologia: ‘::text) || schede_a.tipologia_edilizia::text) || ‘ , destinazione: ‘::text) || schede_a.destusopre::text) || ‘
‘::text) || ‘volume: ‘::text) || schede_a.volume_ft) || ‘ , ‘::text) || ‘altezza: ‘::text) || schede_a.altezza_media) || ‘ , epoca: ‘::text) || schede_a.epoca_costruzione::text) || ‘
‘::text) || ‘<img src=’::text) || ‘::text AS tooltip
FROM schede_a;

QGIS | time manager

Ho provato un altro plugin di QGIS: time-manager.

E’ un plugin che consente di creare mappe “animate” in base a dati “temporizzati”. Nel mio test specifico ho provato a creare un’animazione che rappresenti l’evoluzione storica dell’edificato.

Avevo a disposizione lo SHP degli edifici contenente anche i dati relativi all’epoca di costruzione. Non si tratta di valori annui ma di range abbastanza dilazionati. Ma è risultato comunque molto utile e di impatto.

Ecco una gif animata (creata con GIMP) che ne è scaturita: appena riesco argomento meglio :-). E’ necessario cliccare sull’immagine per visualizzare l’animazione.

evoluzione storica dell’edificato elaborata con il plugin “time-manager” di QGIS (cliccare sull’immagine per visualizzare l’animazione)

Ma vediamo come è stata realizzata questa immagine.

Lo SHP di partenza contiene i poligoni degli edifici con alcuni attributi collegati tra i quali un campo “epoca_costruzione” che assume i seguenti valori:

– ante 1900;

– 1901-1935;

– 1936-1955;

– 1956-1982;

– 1983-1994;

– 1995-2012.

Ho applicato una vestizione “categorized” su questo campo costruendo una pseudo rampa colore che va dal giallo “timido” al rosso acceso.

Assieme allo SHP degli edifici, con la stessa suddivisione di epoca, avevo a disposizione anche le aree di circolazione; anche per queste ho tematizzato la vestizione in base all’epoca di costruzione.

Ho aggiunto altri due campi alla tabella degli attributi: un campo chiamato “time” di tipo stringa ed un campo chiamato “forever” anch’esso di tipo stringa (il tutto mediante il plugin “table-manager”).

Poichè il time-manager necessita di un campo che contenga dati temporali da fare scorrere nella “barra del tempo” del plugin stesso ho popolato il campo “time” a seconda dell’epoca di costruzione traducendo range di alcuni anni in dati annuali fittizi (utili al plugin per renderizzare). In particolare ho seguito questo schema:

epoca  ante 1900 corrisponde a time=2007-01-01

epoca 1901-1935 corrisponde a time=2008-01-01

epoca 1936-1955 corrisponde a time=2009-01-01

epoca 1956-1982 corrisponde a time=2010-01-01

epoca 1983-1994 corrisponde a time=2011-01-01

epoca 1995-2012 corrisponde a time=2012-01-01

Mentre il campo “forever” è stato popolato in maniera uguale per tutti con valore “2014-01-01“. Questo valore torna utile per indicare il momento finale del rendering.

finestra di lavoro in QGIS con evidenziati gli attributi dello SHP edifici

A questo punto si passa alla configurazione del time-manager. Cliccando su “Settings” si apre la finestra di impostazioni nella quale selezionare i layer da utilizzare nel rendering. Quando si seleziona un layer viene chiesto di indicare quale campo considerare per la variabile tempo (nel nostro caso “time”) e quale campo considerare per avere una deadline; nel mio caso avevo creato il campo “forever”. Una volta impostato la finestra di configurazione appare così:

Finestra di configurazione del time-manager

Impostato tutto. “Accendere” il plugin cliccando sul pulsante a sinistra del tasto “Settings” (il pulsante diventa verde). Quindi cliccare sul tasto “play” in basso a sinistra e vedremo scorrere l’animazione sul map canvas. Volendo salvare i fotogrammi basta cliccare sul tasto “Export Video“; ci verrà chiesto di indicare il percorso (directory) in cui salvare tutte le immagini.

Queste possono essere “montate” mediante il tool mencoder. Nel mio caso ho impartito il seguente comando (dopo essermi spostato nella directory contenente i frame da elaborare):

$ mencoder mf://*.PNG -mf fps=1 -o evoluzione_storica.avi -ovc lavc -lavcopts vcodec=mpeg4

ottenendo dopo qualche secondo il video in formato .avi.

Non potendo caricare sul blog (non ho il pacchetto che consente l’upload di video :-)) ho creato una GIF animata con GIMP.

La procedura è molto semplice. Una volta avviato GIMP andare su File -> Apri come livelli e selezionare tutti i fotogrammi in ordine di numerazione. Quindi salvare in formato GIF (nelle ultime versioni di GIMP non si esegue un “salva” ma un “esporta” in quanto il “salva” riguarda solo il formato nativo di GIMP). Al momento del salvataggio viene chiesto anche il tempo di permaneza di ogni fotogramma (impostato a 3000 millisecondi) e spuntare l’opzione “Come animazione“.

Ed infine un’altra animazione realizzata in base all’evoluzione storica degli ultimi 10 anni circa (dal 2001 al 2011).

legenda evoluzione edificato

postgis | ST_Reverse()

Un piccolo e breve post su una funzione di Postgis molto utile per invertire l’ordine di digitalizzazione dei vertici di un oggetto. Nel caso specifico si fa riferimento ad oggetti lineari. La funzione è (brevemente) documentata qui. Ed ecco un esempio pratico per invertire il senso di 3 linee identificate mediante il loro gid:

#= UPDATE nome_tabella_linee SET the_geom = ST_Reverse(the_geom) WHERE gid IN (8,128,46);

I valori dei “gid” indicati sono puramente esemplificativi.

slony | replicare db postgresql (postgis)

Ho provato a buttarmi (finalmente dico io) su Slony. Si tratta di un sistema per replicare uno o più database da un server postgresql su un altro o piu’ server (anche remoti).

Ho fatto un piccolo test (per ora) cercando di replicare il db spaziale (con estensione postgis) della carta tecnica regionale numerica su un altro server.

Su entrambi i server gira Debian stable (ad oggi “squeeze”) ed hanno rispettivamente gli IP: 192.168.1.71 e 100.0.4.231.

Creiamo il database (vuoto) sul server slave con il comando:

$ su

# su postgres

# psql

=# CREATE DATABASE ctr_new_slave OWNER sit template=template_gis;

e lo strutturiamo come “ctr_new” (db master):

$ pg_dump -s -U postgres -h localhost ctr_new | psql -U postgres -h 100.0.4.71 ctr_new_slave

Quest’ultimo comando è stato impartito dal server master.

Installare slony via apt-get:

# apt-get install slony1-2-bin postgresql-8.4-slony1-2

Il database (già presente) deve avere abilitato il linguaggio procedurale plpgsql. Essendo un db creato mediante un “template_gis” che già incorpora questo linguaggio non ho dovuto fare niente. In caso di nuovo db ricordarsi invece di abilitarlo con:

(come utente postgres) # createlang plpgsql nome_db

Una prerogativa per il funzionamento di slony è che ogni tabella del db abbia una chiave primaria (notare che possono essere replicate anche solo alcune tabelle specificandole nel file di configurazione che vedremo dopo).

Configurazione degli script altperl

Ci sono diversi modi per configurare e manovrare slony: in questo esempio useremo gli script altperl (si tratta di script in perl appunto).

ci spostiamo della directory “/etc/slony/” e copiamo al suo interno il file di configurazione di esempio che si trova in “/usr/share/doc/slony1-2-bin/examples/slon_tools.conf-sample.gz” (dopo averlo decompresso e averne fatto una copia chiamata slon_tools.conf)

(come root):

# cd /etc/slony

# cp /usr/share/doc/slony1-2-bin/examples/slon_tools.conf .

modifichiamo il file con nano:

# nano slon_tools.conf

riporto il file:

======================================================

# $Id: slon_tools.conf-sample,v 1.8.2.4 2009-08-17 22:21:38 devrim Exp $
# Author: Christopher Browne
# Copyright 2004-2009 Afilias Canada
# Revised extensively by Steve Simms

# Keeping the following three lines for backwards compatibility in
# case this gets incorporated into a 1.0.6 release.
#
# TODO: The scripts should check for an environment variable
# containing the location of a configuration file.  That would
# simplify this configuration file and allow Slony-I tools to still work
# in situations where it doesn’t exist.
#
if ($ENV{“SLONYNODES”}) {
    require $ENV{“SLONYNODES”};
} else {

    # The name of the replication cluster.  This will be used to
    # create a schema named _$CLUSTER_NAME in the database which will
    # contain Slony-related data.
    $CLUSTER_NAME = ‘replication’;

    # The directory where Slony should record log messages.  This
    # directory will need to be writable by the user that invokes
    # Slony.
    $LOGDIR = ‘/var/log/slony1’;

    # SYNC check interval (slon -s option)
    # $SYNC_CHECK_INTERVAL = 1000;

    # Which node is the default master for all sets?
    $MASTERNODE = 1;

    # Which debugging level to use?  [0-4]
    $DEBUGLEVEL = 2;

    # Include add_node lines for each node in the cluster.  Be sure to
    # use host names that will resolve properly on all nodes
    # (i.e. only use ‘localhost’ if all nodes are on the same host).
    # Also, note that the user must be a superuser account.

    add_node(node     => 1,
         host     => ‘192.168.1.71’,
         dbname   => ‘ctr_new’,
         port     => 5432,
         user     => ‘postgres’,
             password => ”);

    add_node(node     => 2,
         host     => ‘100.0.4.71’,
         dbname   => ‘ctr_new_slave’,
         port     => 5432,
         user     => ‘postgres’,
             password => ”);

}

# The $SLONY_SETS variable contains information about all of the sets
# in your cluster.

$SLONY_SETS = {

    # A unique name for the set
    “set1” => {

    # The set_id, also unique
    “set_id” => 1,

    # Uncomment the following line to change the origin
    # (a.k.a. master) for the set.  The default is $MASTERNODE.
    #
    # “origin” => 1,

    # If this is set to 1, table and sequence names will be folded to lower-case
    # to match the way that PostgreSQL handles unquoted names.
    # For example, CREATE TABLE ACCOUNT(…) actually turns into CREATE TABLE account(…);
    # unless you put quotes around the table name
    # Slony always quotes object names, so you may get a mis-match between the table-name
    # as PostgreSQL understands it, and as Slony represents it.
    # default value is 0
    #
    # foldCase => 0,

    # The first ID to use for tables and sequences that are added
    # to the replication cluster.  This must be unique across the
    # cluster.
    #
    # TODO: This should be determined automatically, which can be
    # done fairly easily in most cases using psql.  create_set
    # should derive it, and give an option to override it with a
    # specific value.
    “table_id”    => 1,
    “sequence_id” => 1,

    # This array contains a list of tables that already have
    # primary keys.
        “pkeyedtables” => [
               ‘public.aree_ter’,
               ‘public.astefer’,
               ‘public.asteflu’,
               ‘public.astevia’,
               ‘public.cam_fabb’,
               ‘public.curve’,
               ‘public.discont’,
               ‘public.ele_div’,
               ‘public.err_l’,
               ‘public.fabbr_l’,
               ‘public.fabbric’,
               ‘public.ferrovie’,
               ‘public.geometry_columns’,
               ‘public.idrogr_a’,
               ‘public.idrograf’,
               ‘public.infras_a’,
               ‘public.infrastr’,
               ‘public.inquadra’,
               ‘public.lim_amm’,
               ‘public.limamm_a’,
               ‘public.nodofer’,
               ‘public.nodoflu’,
               ‘public.nodovia’,
               ‘public.opere’,
               ‘public.punti_q’,
               ‘public.sim_disc’,
               ‘public.sim_elem’,
               ‘public.sim_fabb’,
               ‘public.sim_idro’,
               ‘public.sim_infr’,
               ‘public.sim_oper’,
               ‘public.sim_vege’,
               ‘public.sim_viab’,
               ‘public.spatial_ref_sys’,
               ‘public.testi’,
               ‘public.veget_a’,
               ‘public.vegetaz’,
               ‘public.viab_a’,
               ‘public.viabilit’,
               ],

    # For tables that have unique not null keys, but no primary
    # key, enter their names and indexes here.
    #”keyedtables” => {
    #    ‘table3’ => ‘index_on_table3’,
    #    ‘table4’ => ‘index_on_table4’,
    #},

    # If a table does not have a suitable key or set of keys that
    # can act as a primary key, Slony can add one.
    #
    # Note: The Slony development team does not recomment this
    # approach — you should create your own primary keys instead.
    # “serialtables” => [“table5”],

    # Sequences that need to be replicated should be entered here.
    #”sequences” => [‘sequence1’,
    #        ‘sequence2’,
    #        ],
    },

};

# Keeping the following three lines for backwards compatibility in
# case this gets incorporated into a 1.0.6 release.
#
# TODO: The scripts should check for an environment variable
# containing the location of a configuration file.  That would
# simplify this configuration file and allow Slony tools to still work
# in situations where it doesn’t exist.
#
if ($ENV{“SLONYSET”}) {
    require $ENV{“SLONYSET”};
}

# Please do not add or change anything below this point.
1;

======================================================

Ho modificato il file di esempio togliendo le parti relative a “keyedtables” e “serialtables” e inserendo i nomi delle tabelle (con relativo schema) da replicare. Inoltre ho lasciato inalterate le impostazioni per “$CLUSTER_NAME = ‘replication’;” e “$LOGDIR = ‘/var/log/slony1’;”. La prima identificherà con un prefisso un nuovo schema nei due db e l’altra indica dove salvare i file di log.

Configurazione di slonik

Una volta editato il file di configurazione possiamo usalro per generare gli script da passare al modulo “slonik” (siamo sempre all’interno della  cirectory “/etc/slony/”).

# slonik_init_cluster > initcluster

# slonik_create set 1 > createset

# slonik_subscribe_set 1 2 > subscribeset

In questo modo vengono creati 3 file ognuno dei quali contiene il codice per impostare un cluster e farlo partire.

Accendere i motori

Ora possiamo fare partire il tutto:

# slonik < initcluster

che dovrebbe produrre un output simile a questo:

<stdin>:10: Set up replication nodes
<stdin>:13: Next: configure paths for each node/origin
<stdin>:16: Replication nodes prepared
<stdin>:17: Please start a slon replication daemon for each node

Può succedere che compaiano dei messaggi di errore (nel mio caso avevo scritto alcuni nomi di tabelle sbagliate nel file slon_tools.conf). In questo caso correggere il file suddetto, rimuovere i tre script creati con “# rm initcluster createset subscribset“, poi entrare dei due db “ctr_new” e “ctr_new_slave” e rimuovere lo schema “_replication” con “=# DROP SCHEDA -replication CASCADE;“. Infine ripartire con la creazione degli script di configurazione.

Avviamo slon sul server 1:

# slon_start 1

Invoke slon for node 1 – /usr/bin/slon -p /var/run/slony1/node1.pid -s 1000 -d2 replication ‘host=192.168.1.71 dbname=ctr_new user=postgres port=5432’ >>/var/log/slony1/node1-ctr_new.log 2>&1 </dev/null &
Slon successfully started for cluster replication, node node1
PID [5815]
Start the watchdog process as well…

e avviamo slon sul server 2:

# slon_start 2
Invoke slon for node 2 – /usr/bin/slon -p /var/run/slony1/node2.pid -s 1000 -d2 replication ‘host=100.0.4.71 dbname=ctr_new_slave user=postgres port=5432’ >>/var/log/slony1/node2-ctr_new_slave.log 2>&1 </dev/null &
Slon successfully started for cluster replication, node node2
PID [5879]
Start the watchdog process as well…

Ora creiamo cluster e subscribe

# slony < createset

<stdin>:16: Subscription set 1 created
<stdin>:17: Adding tables to the subscription set
<stdin>:21: Add primary keyed table public.aree_ter
<stdin>:25: Add primary keyed table public.astefer
<stdin>:29: Add primary keyed table public.asteflu
<stdin>:33: Add primary keyed table public.astevia
<stdin>:37: Add primary keyed table public.cam_fabb
<stdin>:41: Add primary keyed table public.curve
<stdin>:45: Add primary keyed table public.discont
<stdin>:49: Add primary keyed table public.ele_div
<stdin>:53: Add primary keyed table public.err_l
<stdin>:57: Add primary keyed table public.fabbr_l
<stdin>:61: Add primary keyed table public.fabbric
<stdin>:65: Add primary keyed table public.ferrovie
<stdin>:69: Add primary keyed table public.geometry_columns
<stdin>:73: Add primary keyed table public.idrogr_a
<stdin>:77: Add primary keyed table public.idrograf
<stdin>:81: Add primary keyed table public.infras_a
<stdin>:85: Add primary keyed table public.infrastr
<stdin>:89: Add primary keyed table public.inquadra
<stdin>:93: Add primary keyed table public.lim_amm
<stdin>:97: Add primary keyed table public.limamm_a
<stdin>:101: Add primary keyed table public.nodofer
<stdin>:105: Add primary keyed table public.nodoflu
<stdin>:109: Add primary keyed table public.nodovia
<stdin>:113: Add primary keyed table public.opere
<stdin>:117: Add primary keyed table public.punti_q
<stdin>:121: Add primary keyed table public.sim_disc
<stdin>:125: Add primary keyed table public.sim_elem
<stdin>:129: Add primary keyed table public.sim_fabb
<stdin>:133: Add primary keyed table public.sim_idro
<stdin>:137: Add primary keyed table public.sim_infr
<stdin>:141: Add primary keyed table public.sim_oper
<stdin>:145: Add primary keyed table public.sim_vege
<stdin>:149: Add primary keyed table public.sim_viab
<stdin>:153: Add primary keyed table public.spatial_ref_sys
<stdin>:157: Add primary keyed table public.testi
<stdin>:161: Add primary keyed table public.veget_a
<stdin>:165: Add primary keyed table public.vegetaz
<stdin>:169: Add primary keyed table public.viab_a
<stdin>:173: Add primary keyed table public.viabilit
<stdin>:176: Adding sequences to the subscription set
<stdin>:177: All tables added

Ed infine:

# slony < subscribeset

<stdin>:4: NOTICE:  subscribe set: omit_copy=f
<stdin>:4: NOTICE:  subscribe set: omit_copy=f
CONTEXT:  SQL statement “SELECT  “_replication”.subscribeSet_int( $1 ,  $2 ,  $3 ,  $4 ,  $5 )”
funzione PL/pgSQL “subscribeset” linea 68 a PERFORM
<stdin>:10: Subscribed nodes to set 1

Tutto è partito: se andiamo a vedere i file di log in “/var/log/slony/” vediamo cio’ che accade.

Per fare un test ho provato a caricare la stessa tabella (spaziale) in QGIS (la stessa tabella del db master e dello slave). Modificando (aggiunto un elemento geometrico) la tabella e facendo un refresh si notano quasi istantaneamenete i cambiamenti replicati anche nel db slave!

Ogni commento è benvenuto.

qualche tips su django

Rimozione django

Per rimuovere django installato da sorgenti (nel caso si voglia installare una versione piu’ recente, per esempio) basta trovare la directory “django” e cancellarla. Per trovarla impartire il comando:

sit@debian:~$ python -c “import sys; sys.path = sys.path[1:]; import django; print(django.__path__)”

che nel mio caso restituisce:

[‘/usr/lib/pymodules/python2.6/django’]

MD_PYTHON ERROR in django

Dopo un blocco inaspettato del server (durante un processo di rsync) il gestionale django installato riportava il seguente errore:

MOD_PYTHON ERROR

…………..

…………..

Import Error: Could not import settings ‘my_app.settings’ (Is it on sys.psth? Does it have syntax error?): No module named myapp.settings

Dopo avere cercato in rete ho trovato che la causa di questo messaggio potrebbe essere:

– file di configurazione di apache errato;

– sys.path sbagliato;

– permessi non corretti su cartelle e files del progetto (permessi che inibiscono all’utente www-data di leggere i file di settings);

– bug nel codice django.

Prima di procedere ho provato a replicare l’aplicativo sul portatile (compreso db postgresql colllegato) e tutto funzionava a modino (NB: stesso SO Debian stable).

Quindi ho confrotato il file di configurazione di apache (/etc/apache2/apache2.conf”) e sono identici; quindi il problema non sta li;

ho confrontato il sys.path delle due macchine: per farlo ho lanciato una shell python, poi:

>>> import os, sys

>>> print sys.path

ed i risultati sono identici: quindi anche la seconda ipotesi e’ scartata.

Anticipo che il bug nel codice django e’ da escludere a priori visto che sul portatile gira senza problemi. Rimangono da verificare i permessi sulle cartelle del progetto.

Infatti confrontando i listati di “ls -l” sulle due macchine si nota che la directory “/home/user/” ha dei permessi differenti (nel server e’ inibita la lettura a tutti. Molto probabilmente durnate l’operazione di rsync lanciato da root ha modificato i diritti di accesso durante; il blocco del server causato da un down temporaneo della rete ha messo in lock anche le directory interessate). Cambiando questa impostazione con:

$ chmod 751 -R /home/user/

tutto e’ andato a posto

Da Postgresql 8.3 e Postgis 1.3.3 a Posgresql 8.4.11 e Postgis1.5.1 su Debian stable

Con questo post volevo tenere traccia della procedura di aggiornamento e migrazione dati da Postgresql 8.3 e Postgis 1.3.3 a Posgresql 8.4.11 e Postgis1.5.1.

Ho seguito questa utilissima pagina wiki

Sul nostro server “girano” attualmente Postgresql 8.3 e Postgis 1.3.3.

1- Facciamo dapprima il backup dei database presenti (il comando va lanciato per ogni db presente nel cluster).

$ PGUSER=postgres pg_dump -Fc nome_db > /percorso/alla/dir/di/dump/nome_db.dmp

NB: pg_dump con l’opzione -Fc crea un archivio compresso (un tar compresso con gzip, ovvero un tar.gz).

Nel caso si trattasse di db non spaziale e’ sufficiente dare:

$ PGUSER=postgres pg_dump -c nome_db > /percorso/alla/dir/di/dump/nome_db.sql

2- Stoppiamo Postgresql-8.3 (come root):

# /etc/init.d/postgresql stop 8.3

3- Installiamo Postgresql-8.4 e Postgis-1.5

# aptitude install postgresql-8.4 postgresql-8.4-postgis

A questo punto (non ricordo purtroppo tutte le fasi che ho percorso) al comando di stop de nuovo postgresql-8-4 compariva un errore. Ho provato a reinstallarlo ma a questo punto ottengo:

# Error: move_conffile: required configuration file /var/lib/postgresql/8.4/main/postgresql.conf does not exists.

Decido allora di reinstallare tutto ma succede il fattaccio. Non si riesce piu’ a lanciare postgresql-8-3. Il messaggio d’errore diceva che non esiste piu’ la directory “/var/lib/postgresql/8.3/main” panic…..praticamente mi e’ sparito tutto il cluster di postgresql-8.3, fumato!

Ok, pero’ i backup li ho e decido di fare un purge profondo prima di ripartire. Cerco tutti i pacchetti relativi a Postgresql.

# dpkg -l | grep postg

e rimuovo tutto con:

# aptitude purge postgresql-8.3 postgresq-8.4 postgresql-client-8.3 postgresql-client-8.4 postgresql-client-common postgresql-common postgresql

Rimuovo anche tutte le directory di sistema:

# rm -r /etc/postgresql/

# rm -r /etc/postgresql-common/

# rm -r /var/lib/postgresql/

poi togliamo manualmente l’utente “postgres” dal file “/etc/passwd” (mediante “# nano /etc/passwd” e modificando il file eliminado la riga di interesse).

Quindi reinstallo tutto con:

# aptitude install postgresql-8.4 postgresql-8.4-postgis (che si tira dietro anche tutte le dipendenze del caso)

A questo punto possiamo recuperare i dump fatti. Per fare questo ci viene in aiuto uno script in perl che si installa con postgis-1.5 (new_postgis_restore.pl).

Prima si devono ricreare i database vuoti (con lo stesso nome di quello di partenza). Essendo tutti db spaziali creiamo dapprima un template spaziale che chiamiamo “template_gis” e lo useremo poi per creare ogni db.

Come utente postgres creiamo anche gli utenti dei db stessi:

$ su

# su postgres

(come utente postgres) # psql template1; (si entra in un db qualsiasi per creare gli utenti)

=# CREATE USER nome_utente WITH PASSWORD ‘secret’ CREATEDB CREATEUSER;

Creo il nuovo database che diventaera’ il template (sempre come utente postgres):

=# CREATE DATABASE template_gis template=template0;

Usciamo dal db (<CTRL>d) e (sempre come utente postgres) importiamo in esso le funzioni spaziali:

# psql -f /usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql -d template_gis

poi

# psql -d template_gis -f /usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql

A questo punto rientriamo in template1:

# psql template1;

e facciamo in modo che il nuovo db sia un template usabile in futuro:

# UPDATE pg_database SET datistemplate=’t’ WHERE datname=’template_gis’;

ok, ora possiamo creare tutti i nostri db in base a questo template.

# CREATE DATABASE nome_db template=template_gis OWNER nome_utente; (questo va fattoper ogni db)

Quindi popoliamo i db con lo script perl citato prima (come utente normale):

$ /usr/share/postgresql/8.4/utils/new_postgis_restore.pl  /percorso/alla/dir/di/dump/nome_db.dmp | psql nome_db

Vedremo scorrere sul terminale una serie di istruzioni (il db si sta popolando). Fatto.

Alla fine (nel mio caso) ricordarsi di modificare i file “/etc/postgresql/8.4/main/postgresql.conf” e “/etc/postgresql/8.4/main/pg_hba.conf”.

Per il primo decommentare la riga relativa a “listen_addresses” e inserire l’asterisco al posto di “localhost” come riportato:

#——————————————————————————
# CONNECTIONS AND AUTHENTICATION
#——————————————————————————

# – Connection Settings –

listen_addresses = ‘*’                  # what IP address(es) to listen on;

………………

Per il secondo (nella parte finale del file):

# Database administrative login by UNIX sockets
local   all         postgres                          ident

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD

# “local” is for Unix domain socket connections only
local   all         all                               trust
# IPv4 local connections:
host    all         all         127.0.0.1/32          trust
host    all         all         0.0.0.0/0             trust
# IPv6 local connections:
host    all         all         ::1/128               trust

altrimenti non sono consentiti connessioni da altri client (nel primo file) e l’esecuzione di pg_dumpall (nel secondo file)