Posts Tagged ‘desenvolvimento’

Pacotes Debian Por Um Mano Do Slackware

Monday, May 24th, 2010

Primeiro vamos aos esclarecimentos para tentar evitar qualquer flame. Sou usuário de Slackware ha 6 anos mais ou menos mas faz 2 anos que convivo diariamente com Debian. Esse ensaio sobre os pacotes desta última distro é feito em cima da minha experiência com as duas e não representa qualquer tipo de preconceito com a distro. Espero que leiam até o final antes de comentar ou expressar uma opinião mais acalorada. Agora vamos ao que interessa.

Estrutura Do Pacote

A estrutura de um pacote .deb pronto é simples e não tem nada complexo. E um pacote do Slackware não fica atrás. A diferença principal é que os dados do software estão em um tar separado dos arquivos que fazem o controle da instalação. Não são muitos arquivos e em resumo o principal de um pacote .deb é:

debian-binary
Arquivo de texto com a versão do binário do pacote.
control.tar.gz
Meta informação do pacote. Dependências e coisas do tipo.
data.tar ou data.tar.gz ou data.tar.bz2 ou ainda data.tar.lzma
O diretório que contém os arquivos do programa a ser instalado.

Tudo isso comprimido em um pacote ar. Acho que é o mínimo e o máximo necessário para um controle de pacotes com dependencias como no Debian.

No Slackware a estrutura é semelhante mas é basicamente um pacote tar gzip, bzip ou xz que representa o mesmo que o data.tar no pacote Debian, mas com um sub-diretório install onde estão os arquivos de controle da instalação.

Geração do Pacote e a Aberração Debianization

Ok, aqui o bixo pega. Então vou fazer em forma de comparativo entre Slackware e Debian.

No Slackware

É nois que voa bruxão

A geração de pacotes no Slackware é feita usando preferivelmente um script em shell para automatização da compilação e empacotamento chamado SlackBuild Script, é um shell script perfeitamente normal que qualquer pessoa com o mínimo de experiência no mesmo consegue dar manutenção. Em geral o que o slackbuild faz pode ser divido em duas fases:

  1. Compilação e instalação do pacote em um diretório temporário
  2. Geração do pacote com o facilitador makepkg

A primeira fase é feita usando as ferramentas disponíveis pela aplicação. Pode ser autoconf, ant ou qualquer build system. Até mesmo um chroot se faz necessário em alguns casos. A segunda parte é a normalização do pacote que consiste em compactação de man pages, strip de shared libraries, a inclusão do próprio build script como doc e dos arquivos para o diretório install/ e por fim a compactação do diretório e criação do t?z.

É importante ressaltar que nos pacotes Slackware o código fonte original não é mexido e sequer distribuido junto com os SlackBuilds na maioria dos casos. Alguns casos existem onde patches são necessários para que o pacote funcione corretamente mas estes são aconselhados somente se o programa não puder funcionar sem este ou isso representar um risco grave de segurança e estabilidade. A politica pura e simples é: Desenvolvimento é papel dos desenvolvedores e não dos empacotadores.

No Debian

Coididoido esse debian.

O documento de política de desenvolvimento do Debian é um monstro de 10 sessões com mais 10 sub-sessões cada e 7 anexos. Recomendo a leitura se quiser confirmar o que eu digo aqui. Vou resumir a forma de criação padrão de pacotes.

A mudança na forma de pensar já começa na nomenclatura do indivíduo que empacota. No Slackware é um empacotador. No Debian é um desenvolvedor.

Primeiro salva-se o código fonte original em um .orig e então pode se começar a Debianização do aplicativo. Um pacote é feito geralmente usando de 2 a 4 aplicativos facilitadores e geralmente o autoconf é o responsável pela geração do pacote. Tudo isso fica dentro do código fonte em um diretório debian/. A estrutura é complexa e é necessário um longo periodo e leitura da documentação para a compreensão do sistema de empacotamento e criação de um pacote seguindo todas as guidelines.

Na documentação em vários trechos é recomendado a edição do código fonte original para debianização do aplicativo. O que ao meu ver só maximiza as possibilidades de problema como aquele infame warning no openssl que foi silenciado por um Debian desenvolver e fez com que as chaves de milhares de servidores fossem geradas de forma previsível.

Também há uma preocupação grande mas parcialmente justificável de separar os cabeçalhos de bibliotecas em pacotes adicionais e usar a mesma estrutura para gerar mais de um pacote elevando a complexidade do sistema.

Pensamentos Finais

Não muitos, eu não gosto desse sistema e as guidelines do Debian são uma aberração pra mim. Vou tentar criar um DebBuild script para gerar pacotes Debian no estilo Slackware e posto aqui se o fizer.

Meu chefe certo dia falou que o sistema do Slackware dependia do “artista” e não era processual o suficiente. Mas lendo a guideline do Debian eu descobri que ele está errado nisso, pois a inversa é verdadeira. O sistema do Debian é justamente isso, um sistema com sub-sistemas e macro-sistemas usados para gerar coisas que no final das contas são simples, uma arquitetura digna de um arteiro e não artista.

PS IMPORTANTE

Eu falo aqui da forma de geração de pacotes recomendada e ensinada pelo documento abaixo. NÃO estou considerando outras formas, se existirem, de gerar pacotes Debian. Como por exemplo a utilização de um script sh ou CDBS.

Referências

deb (file format) From Wikipedia, the free encyclopedia

Debian Policy Manual From Debian.org

PS.  gentil correção do caio:

[11:39] <caio1982> guax: debian-binary nao eh a versao do pacote, seu animal, eh a versao dos binarios do debian (.debs em geral distribuidos em “formato debian”, nao sao backward compatible pra sempre)

PS2. adição do caio: http://build-common.alioth.debian.org/cdbs-doc.html

Visual Web JSF

Monday, October 26th, 2009

Tudo que tenho a dizer sobre o Visual Web JSF está representado nesta imagem:

Sabe das coisas esse capitão.

Sabe das coisas esse capitão.

Call Flow Diagram

Sunday, October 11th, 2009

I was trying to define what information was relevant in a implementation of a Call Detail Record (CDR). Then i realized i need to represent all the possible scenarios a call can perform inside a PBX, so i can determine the relevant data i should store to make reports and even what pieces of the call must be recorded.

I searched for a diagram that could represent the call flow in a more intuitive way. I didn’t found something that was easy and clear enough for me. So i sketched some small diagrams and developed the following diagram structure that i will use on my documentation about telephony. I am still accepting better suggestions about representing calls in a more clear way.

update: why? Sometimes we need to draw things to our boss and clients to understand, people usually don’t have the same data abstraction skills that you have on seeing a lot of CDR’s rows and messages as audio streams flowing through dialplan logic. I had a good experience to explain what happened to calls using this. So i’m sharing. =)

Basic Call Representation

The first call we can represent is the most basic and common case on telephony. A calls B and that’s everything that happens.

A simple call that connects A to B

A simple call that connects A to B

As you see those two elements represent communication end-points that we can say are physical channels that comes and goes out from the PBX. Could represent a persons phone or a PSTN or a trunk with another PBX.

The number on the connection line determinate the order the calls were placed on the system. So we can use a dashed line to represent calls that were not answered by our called party (B). By now we have the basic call redirection scenario where the first destination does not answer so the call is made with C instead of B.

Sequence

B don't answer and the call overflowed to C

Another way a call can walk between end-points is when one of these points transfer its party. When this happens we need to keep track of who made the transfer. That is represented by the curved arrow that shows who transfer to who and in what moment.

B transfer A to C.

B transfer A to C.

Note that transfer can make a communication channel as well between B and C during the transfer operation, the attended transfer. In this cases you can represent it textually, since most of people don’t care about that conversation.

Not all the times calls fallow an specific order. We have situations where many end-points are talking in the same time in the same call, in a conference for example. Conferences are the most common way to unite two calls that starts independently and when it appear in complex scenarios we will need a more complete way to represent the time sequence of call placing, but i will let this for later work. For now we can just represent the connections on a special element and say that all the connections happened at the same time.

A conference between A, B, C and N more end-points.

A conference between A, B, C and N more end-points.

Applications and Contextualization

PBX’s are known for give some intelligence in call routing. This is the ability to use applications that apply one specific logic on the calls. These can be queues, call groups or even the Interactive Voice Response systems (IVR’s). The main difference between them is that some may answer the call and make data transmission to the connection party. When the application answer the call is easy to represent it as and special end-point, as we did with conferences. When just routing is involved we need to contextualize a group of calls in the scenario so we can determine the actions taken by the app. We can see those two cases in the next diagram.

Contextualization

Call Contexts

Approach Issues

One concern i have with this representation is that it could be a little confuse in a first moment about how the call flowed. I didn’t made the diagram in a standard way by considering that i am not taking a peer point of view, but the macro view of the call flow. In a simpler approach it would be ignored for example in a conference what was the path taken by the other participants, since the most common way to someone to get into a conference is to be transfered to the number that represents it.

I understand some misconceptions can happen since i am trying to represent something that is dynamic in a static view which is the call states along a time period. A snapshot of the PBX in any moment will only show a simple call.

PS. English corrections will be appreciated.

Magia Negra das Threads em Python

Thursday, September 17th, 2009
Python Threads

Python Threads

Certo dia estava eu a pensar sobre a vida o universo e tudo mais e antes que 42 viesse a minha mente foi pedido que eu implementasse um disparador de SMS’s. Para isso eu precisava fazer disparos simultâneos em X canais gsm. Requisito óbvio: preciso de threads. PHP, a linguagem que usamos para quase tudo na aplicação não tem um suporte bom a threads então fui atrás de outra linguagem para o fazer.

Python atravessou meu caminho e nas minhas brincadeiras com a cobra (ui!) eu apanhei, jesus sabe que eu apanhei dessa pseudo-linguagem medonha e caracu (eu xinguei de coisa pior enquanto era humilhado pela até então ignorância na linguagem). Eu apanhei por que o mau costume de só ter usado Java (pausa para uivos e pedras….) para trabalhar com threads me deixou preguiçoso e mau acostumado a uma declaração bem mais simples de sincronismo entre métodos, bastava um synchronized e tudo estava funcionando.

Python ao contrário de Java não é nada thread-safe. Todas as chamadas simples podem ser desastrosas se mexem com recursos compartilhados entre as threads.

Sincronizando

Já que a python não é thread-safe temos que assumir essa responsabilidade no lugar da linguagem e sincronizar as chamadas com Locks, Semáforos e afins. Não é o fim do mundo, mas que é chato, é. Se quizermos por exemplo fazer a inserção de dados no banco de dados e ter o resultado disso logo após cada insert devemos sincronizar os inserts e commits já que o componente MySQLdb não faz esse controle para nós.

class Inserter(object):
    def __init__(self, lck,db):
        self.lock = lck;
        self.db = db
 
    def insert(self, insert):
        cursor = self.db.cursor()
        try:
            self.lock.acquire()
            cursor.execute(insert)
            cursor.execute("commit")
        finally:
            self.lock.release()

Queue

Outro componente muito útil quando se utiliza threads são as Filas. Filas são fifos (first-in first-out) que enfileiram ações que você gostaria que fossem executadas em paralelo por threads ou que simplesmente sejam executadas em determinada ordem.

# Importamos o módulo
from Queue import Queue
 
def run(self):
        while True:
            try:
                self.lock.acquire();
                if self.fila.empty():
                    break
                item = self.fila.get()
            finally:
                self.lock.release()
 
            self.printer.imprime(item)

Uma nota sobre Filas é que não se deve usar um if not queue.empty() e depois tentar dar um queue.get() já que no tempo entre esses dois acessos aos métodos outra thread pode pegar o ultimo elemento. É necessário que você simplesmente pegue o elemento e trate a exceção ou use Lock nessa parte do método.

ps. estranho, mas python implementa LIFO (pilha) no modulo Queue. :P

CDR no Asterisk, nada bom :(

Thursday, August 20th, 2009

O Call Detail Record no Asterisk PBX é feito por um modulo homônimo que aceita diversos backends para persistencia dos dados em SGDB’s, csv, odbc, etc. Sua força está na sua simplicidade quanto ao uso, já vem por padrão no Asterisk e funciona muito bem para a maioria dos casos. Mas nem tudo são flores, dentre seus problemas mais graves estão: inconsistencia na gravação do status da ligação em transferencias cegas, ligações que deveriam ser ANSWER estão NOANSWER. Nenhuma confiabilidade nos dados de transferencia assistida. O campo ‘uniqueidNÃO É UNICO.

Asterisk sobre Você

Asterisk sobre Você

Ainda há o fato da tabela do banco de dados ter uma estrutura travada e não mapeavel, o que faz com que a customização da mesma seja um processo doloroso e até mesmo inviável.

O que fazer? Fazer um só pra você horas. Todo bom nerd que se prese acha sabe que pode fazer melhor. Então vamos ver como poderemos criar nosso próprio cdr com ajudinha de alguns AGI’s.

Um script AGI que você executa após cada tentativa de Dial() e que grava automaticamente informações como DIALSTATUS, BILLSEC, DUURATION se mostra mais eficiente já que pode-se adaptar a gravação do log conforme a sua estrutura de controle de ligações.

Até ai tudo bem, podemos fazer o controle de ligações simples com as informações que eu bem entender, mas ainda nos resta as ligações que passam por filas de atendimento e ligações que são transferidas.

Filas: Aqui temos um problema, a forma nativa de executar um AGI dentro da app_queue não é satisfatória já que ela executa o script somente quando a ligação é atendida pelo membro da fila. Assim perdemos o status das primeiras ligações caso elas tenham sido recusadas e as informações são as mesmas que colcoar o agi para executar depois da execução do Queue() no dialplan.

Podemos nesse caso, implementar uma Queue via AGI ou Monitorar o Queue log em busca dessas informações.

A solução mais elegante ao meu ver é modificar a aplicação do Queue para que ao invés de implementar o dial diretamente seja possível direcionar para um contexto, assim é possível monitorar todo o comportamento da ligação e da fila em geral. (entra na TODO list)

Transferencias: As transferencias é um problema simples de resolver, ao setar a variavel global TRANSFER_CONTEXT para um contexto qualquer você consegue executar seu AGI lá dentro e resolver esse problema, com um pouco de esforço ainda se pode gerar uma estrutura complexa e bonita com árvore de chamada para não perder os dados da ligação geral e ainda ter o status da ligação primária.

Sempre há a possibilidade de se esperar pela próxima versão, não testei a versão 1.6 do asterisk ainda. Mas até onde fui informado ela teria solucionado esses bugs. Mas ainda sobra a rigidez estrutural.

update: encontrei uma boa discussão sobre o assunto e sobre esses problemas em uma lista de discussão da Digium: http://lists.digium.com/pipermail/asterisk-dev/2008-November/035305.html

update2: nessa discussão tem uma documentação que resume algumas coisas e explana outras, vale a leitura: http://svn.digium.com/svn/asterisk/team/murf/RFCs/