Showing posts with label Linux. Show all posts
Showing posts with label Linux. Show all posts

Thursday, December 6, 2012

PHP + OpenOffice|LibreOffice = EXCEL & PDF Generator

To use OpenOffice from command-line to convert files is like this:

soffice -invisible -convert-to xls myfile.xml

In this case convert a xml file to xls. If you want a PDF file just change to:

soffice -invisible -convert-to pdf myfile.doc

You can use any kind of files supported by OpenOffice as input, and can define the parameter -convert-to to any format supported by Open Office.

I will now just talk about xml to xls, because is very most trick. And to PDF is simple like that above, nothing more to say about it.

To generate a xml valid to Open Office is not easy because the character encode, in my case portuguese iso-8859-15. I had a nightmare, but at end was more simple than seemed.

I save my data in DB utf8_encode then I have to use this function stringToExcelXML to decode and convert to XML special characters format.

Below my PHP code that build the XML compatible with OpenOffice and MSOffice:


error_reporting(E_ALL);
include '../include/config.php';

try {
 $rows = MySQL::Create('SELECT * FROM `Client` WHERE `Name` LIKE ?name ORDER BY `Name`')
  ->Parameter('name', '%'.$_GET['name'].'%', 'string')
  ->Query();
} catch(MySQLException $ex) {
 echo $ex->getMessage();
}

$outputFileName = 'export_'. date ('Ymd_His');

function stringToExcelXML($string){
    $string = htmlspecialchars(utf8_decode($string));
    $string = str_replace("\x01", "\x20", $string);
    return $string;
}

$f = fopen('../export/'. $outputFileName .'.xml', "w");
fwrite($f, '<?xml version="1.0" encoding="iso-8859-15"?>'. chr(13));
fwrite($f, '<?mso-application progid="Excel.Sheet"?>'. chr(13));
fwrite($f, '<Workbook');
fwrite($f, '   xmlns="urn:schemas-microsoft-com:office:spreadsheet"');
fwrite($f, '   xmlns:o="urn:schemas-microsoft-com:office:office"');
fwrite($f, '   xmlns:x="urn:schemas-microsoft-com:office:excel"');
fwrite($f, '   xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"');
fwrite($f, '   xmlns:html="http://www.w3.org/TR/REC-html40">'. chr(13));
fwrite($f, '  <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">'. chr(13));
fwrite($f, '    <Author>Candidatures</Author>'. chr(13));
fwrite($f, '    <LastAuthor>Candidatures</LastAuthor>'. chr(13));
fwrite($f, '    <Created>'. date('Y-m-d\TH:i:s\Z') .'</Created>'. chr(13));
fwrite($f, '    <Company>Candidatures</Company>'. chr(13));
fwrite($f, '    <Version>1</Version>'. chr(13));
fwrite($f, '  </DocumentProperties>'. chr(13));
fwrite($f, '  <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">'. chr(13));
fwrite($f, '    <WindowHeight>6795</WindowHeight>'. chr(13));
fwrite($f, '    <WindowWidth>8460</WindowWidth>'. chr(13));
fwrite($f, '    <WindowTopX>120</WindowTopX>'. chr(13));
fwrite($f, '    <WindowTopY>15</WindowTopY>'. chr(13));
fwrite($f, '    <ProtectStructure>False</ProtectStructure>'. chr(13));
fwrite($f, '    <ProtectWindows>False</ProtectWindows>'. chr(13));
fwrite($f, '  </ExcelWorkbook>'. chr(13));
fwrite($f, '  <Styles>'. chr(13));
fwrite($f, '    <Style ss:ID="Default" ss:Name="Normal">'. chr(13));
fwrite($f, '      <Alignment ss:Vertical="Bottom" />'. chr(13));
fwrite($f, '      <Borders />'. chr(13));
fwrite($f, '      <Font />'. chr(13));
fwrite($f, '      <Interior />'. chr(13));
fwrite($f, '      <NumberFormat />'. chr(13));
fwrite($f, '      <Protection />'. chr(13));
fwrite($f, '    </Style>'. chr(13));
fwrite($f, '    <Style ss:ID="s21">'. chr(13));
fwrite($f, '      <Font x:Family="Swiss" ss:Bold="1" />'. chr(13));
fwrite($f, '    </Style>'. chr(13));
fwrite($f, '  </Styles>'. chr(13));
fwrite($f, '  <Worksheet ss:Name="Clients">'. chr(13));
fwrite($f, '    <Table ss:ExpandedColumnCount="2" ss:ExpandedRowCount="'. (isset($rows) ? count($rows) : 0) .'"');
fwrite($f, '         x:FullColumns="1" x:FullRows="1">'. chr(13));
fwrite($f, '      <Row>'. chr(13));
fwrite($f, '        <Cell ss:StyleID="s21">'. chr(13));
fwrite($f, '          <Data ss:Type="String">Id</Data>'. chr(13));
fwrite($f, '        </Cell>'. chr(13));
fwrite($f, '        <Cell ss:StyleID="s21">'. chr(13));
fwrite($f, '          <Data ss:Type="String">Name</Data>'. chr(13));
fwrite($f, '        </Cell>'. chr(13));
fwrite($f, '      </Row>'. chr(13));
if (isset($rows)) {
  foreach($rows as $row) {
    fwrite($f, '      <Row>'. chr(13));
    fwrite($f, '        <Cell ss:StyleID="s21">'. chr(13));
    fwrite($f, '          <Data ss:Type="String">'. $row['Id'] .'</Data>'. chr(13));
    fwrite($f, '        </Cell>'. chr(13));
    fwrite($f, '        <Cell ss:StyleID="s21">'. chr(13));
    fwrite($f, '          <Data ss:Type="String">'. stringToExcelXML($row['Name']) .'</Data>'. chr(13));
    fwrite($f, '        </Cell>'. chr(13));
    fwrite($f, '      </Row>'. chr(13));
  }
}
fwrite($f, '    </Table>'. chr(13));
fwrite($f, '    <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">'. chr(13));
fwrite($f, '      <Print>'. chr(13));
fwrite($f, '        <ValidPrinterInfo />'. chr(13));
fwrite($f, '        <HorizontalResolution>600</HorizontalResolution>'. chr(13));
fwrite($f, '        <VerticalResolution>600</VerticalResolution>'. chr(13));
fwrite($f, '      </Print>'. chr(13));
fwrite($f, '      <Selected />'. chr(13));
fwrite($f, '      <Panes>'. chr(13));
fwrite($f, '        <Pane>'. chr(13));
fwrite($f, '          <Number>3</Number>'. chr(13));
fwrite($f, '          <ActiveRow>5</ActiveRow>'. chr(13));
fwrite($f, '          <ActiveCol>1</ActiveCol>'. chr(13));
fwrite($f, '        </Pane>'. chr(13));
fwrite($f, '      </Panes>'. chr(13));
fwrite($f, '      <ProtectObjects>False</ProtectObjects>'. chr(13));
fwrite($f, '      <ProtectScenarios>False</ProtectScenarios>'. chr(13));
fwrite($f, '    </WorksheetOptions>'. chr(13));
fwrite($f, '  </Worksheet>'. chr(13));

fclose($f);

$excelFile = '../export/'. $outputFileName .'.xls';

while (true) {
  sleep(1);
  if (file_exists($excelFile)) {
    sleep(100);
    break;
  }
}

header('Content-Disposition: attachment; filename='. $outputFileName .'.xls');
header('Content-Type: application/octet-stream');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-length: '. filesize($excelFile));
ob_clean();
flush();
readfile($excelFile);
unlink($excelFile);

exit();
?>

Attention with worksheet name <Worksheet ss:Name="Clients"> and the number of columns <Table ss:ExpandedColumnCount="2" ... and the encoding="iso-8859-15".

This block of code below will wait the OpenOffice finish the creation of file XLS.

$excelFile = '../export/'. $outputFileName .'.xls';

while (true) {
  sleep(1);
  if (file_exists($excelFile)) {
    sleep(100);
    break;
  }
}

This service made with shell script need still running all time to build XLSs using OpenOffice:

/var/www/services/openoffice_to_xls/openoffice_to_xls.sh
#!/bin/bash

cd /var/www/htdocs/export

while true
do
  for f in `ls *.xml`
  do
    sleep 1
    echo "$f"
    soffice -invisible -convert-to xls "$f"
    sleep 15
    chmod a+rwx *.xls
    rm -f "$f"
  done
  sleep 1
done

Turn the core.sh file as executable:

chmod +x /var/www/services/openoffice_to_xls/core.sh

A start script will be useful:

/var/www/services/openoffice_to_xls/start.sh
#!/bin/bash

rm -f /var/www/services/openoffice_to_xls/nohup.out
nohup /var/www/services/openoffice_to_xls/core.sh &

Turn the start.sh file as executable:

chmod +x /var/www/services/openoffice_to_xls/start.sh

Now just start the service:

/var/www/services/openoffice_to_xls/start.sh

All of this is very trick and to works with MSOffice 2010 and OpenXML... and to this work exists the PHPExcel that is much more elegant:

phpexcel.codeplex.com

But to build office legacy files perhaps these tricks will be useful to do workarounds.

Have fun and good nightmares.

Thursday, July 29, 2010

Automate Command-line Programs

I had to automate a command-line program. Then I did this script like a sample that do auto control to vi.

This way is possible control any kind of command-line program.

#!/bin/python

import subprocess
import time
import threading

class ProcessRunner(threading.Thread):
def run(self):
self.process = subprocess.Popen(["vi /tmp/xpto > /tmp/viOutput"], shell = True, bufsize = 1000, stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.STDOUT)

pr = ProcessRunner()
pr.start()

time.sleep(1)

pr.process.stdin.write("i\n")
pr.process.stdin.flush()

time.sleep(1)

pr.process.stdin.write("Content xpto... :P\n")
pr.process.stdin.flush()

time.sleep(1)

pr.process.stdin.write(chr(27))
pr.process.stdin.flush()

time.sleep(1)

pr.process.stdin.write(":wq\n")
pr.process.stdin.flush()


If is necessary read some content from program output, you can put the output in a temp file, in this case goes to /tmp/viOutput. See with attention the line of the subprocess.Popen. Another way is use the pr.process.stdout but it dont work fine for me.

The command pr.process.stdin.write(chr(27)) write the "character" ESC, like the keyboard key.

Thursday, February 4, 2010

NC (NetCast) vs Printers (Impressoras)

Sobrou para mim configurar as novas impressoras Samsung SCX-6345N no Solaris, e como é óbvio e uma grande pena não tem drivers, ou pelo menos que funcione bem, pois apesar de haver um driver PPD supostamente para o LP em Solaris, não funcionou nem a pau.

Fiz tudo o possível para fazer funcionar estas impressoras em Solaris via LP, pois era uma situação de urgência fazer o sistema da Reuters (Kondor) utilizar as novas impressoras.

Após muitas tentativas e alguns e-mails trocados com o suporte da Samsung, e até um programa da Samsung para instalar a impressora em modo gráfico (X11) que "configuraria automaticamente" o LP, também não funcionou. E após também de muitas folhas de erros e cabeçalho de jobs terem sido impressos sem nunca sair o conteúdo desejado. Após tudo isto e um pouco mais... o suporte da Samsung recomendou eu usar o comando:

# cat testprint.ps | nc -w 2 192.168.193.191 9100


Fiquei sético, mas como não havia muito mais a fazer, lá fui eu experimentar isto, e para a minha surpresa... não é que funcionou!

Por acaso eu já tinha pensado nisto, em abrir uma conexão com a impressora direto e mandar o conteúdo PostScript e ver se ela imprimia ou se ficava maluca. Mas não sabia que existia um comando simples para isto.

O comando NC (NetCast) não vem no Solaris 10, por isso fui ao Sunfreeware.com pegar o pacote:

http://www.sunfreeware.com/programlistsparc10.html#nc

Depois é só instalar o pacote:

#pkgadd -d nc-110-sol10-sparc-local.gz


Na configuração da impressora no Kondor (Reuters) ficou apenas assim:

nc -w 2 192.168.193.191 9100


Portanto é executar o nc passando o IP e a PORTA da impressora. O -w 2 apenas quer dizer que tem o timeout de 2 segundos.

A desvantagem desta solução é que perde-se o controle das impressoras com o LP, ou seja, para o Solaris é como se elas não existissem. Então a administração LP e a configuração das impressoras no /etc/lp e os comandos ("lpstat -a", "enable PRINTER" e "disable PRINTER"), tudo isto passa a servir para nada! :D

Como para nos a solução do NC (NetCast) é suficiente, passamos a trabalhar assim.

NC (NetCast)

netcat is a simple unix utility which reads and writes data across network connections, using TCP or UDP protocol. It is designed to be a reliable "back-end" tool that can be used directly or easily driven by other programs and scripts. At the same time, it is a feature-rich network debugging and exploration tool, since it can create almost any kind of connection you would need and has several interesting built-in capabilities. Netcat, or "nc" as the actual program is named, should have been supplied long ago as another one of those cryptic but standard Unix tools.

http://www.computerhope.com/unix/nc.htm

Esta solução de imprimir diretamente para uma impressora de rede usando o NC (NetCast) também é válida para Linux e Unix em geral.

Monday, May 18, 2009

SUDO + PHP - Executando comandos como Root no PHP

É preciso saber qual é o usuário de execução do PHP:

<?php echo exec("whoami"); ?>


Editar o /etc/sudoers, este arquivo tem que ter permissões apenas de leitura, não pode ficar com permissões de escrita, por isso antes de editar o arquivo dê permissões de escrita:

# chmod u+w /etc/sudoers


Depois de editar, tire a permissão de escrita:

# chmod u-w /etc/sudoers


Então adicionar no /etc/sudoers no fim do arquivo:

%USUARIO_DO_PHP ALL= NOPASSWD: /CAMINHO/DO/COMANDO


Se não colocar no fim do arquivo pode ter outra regra depois que anule esta nova regra.

No PHP é só executar o comando com o SUDO:

<?php echo exec("sudo /CAMINHO/DO/COMANDO.sh"); ?>


Caso não tenha sucesso, verifique os logs de segurança:

# tail -n 100 /var/log/secure


Se tiver esta mensagem de erro:

May 18 16:56:41 SERVIDOR sudo: USUARIO_DO_PHP : sorry, you must have a tty to run sudo ; TTY=unknown ; PWD=/PASTA/DO/PHP ; USER=root ; COMMAND=/CAMINHO/DO/COMANDO


Então é preciso ir no /etc/sudoers e comentar a seguinte linha que contém o "Defaults requiretty", assim:

# Defaults requiretty


Assim deverá funcionar.

Friday, March 13, 2009

Ubuntu, iniciando o Compiz & NVIDIA com Antialiasing

Para por configurar o Compiz no arranque do Gnome, vá em:

System -> Preferências -> Sessões


E adicione o Compiz:

Nome: Compiz
Comando: compiz --replace &
Comentário: Desktop 3D


Fica assim o Compiz configurado para sempre iniciar no arranque do Gnome.

Depois de configurar a qualidade de antialiasing e outras configurações em:

Systema -> Administração -> NVIDIA X Server Settings

Fazer as devidas configurações, principalmente a do "Antialiasing Settings".

Para que o Gnome carregue as configurações do driver no arranque da sessão, edite o arquivo:

/usr/share/xsessions/gnome.desktop


A linha do parâmetro "Exec", para:

Exec="nvidia-settings -l && /usr/bin/gnome-session"


Assim sempre que o Gnome iniciar ele vai aplicar as configurações do driver e rodar o Compiz.

Wednesday, February 4, 2009

Compilando a última versão do WINE no Ubuntu

Para quem não sabe, o WINE permite rodar aplicações Windows em Linux/BSDs sem precisar de uma cópia do Windows. Basicamente, com ele é possível rodar a maioria dos programas desenvolvidos para Windows no Linux.

WINE quer dizer: Wine Is Not an Emulator! O WINE não é um emulador por que ele não emula a arquitetura de processadores do Windows, o Intel x86, ele simplismente consegue executar os binários do Windows na arquitetura em que esta rodando, como uma ponte entre os binários do Windows e o sistema nativa em que ele esta rodando (Linux/BSDs) independente da arquitetura do processador.

O Ubuntu tem o WINE disponível no repositório oficial, mas nunca é a versão mais resente, e como estão sempre melhorando para rodar melhor os programas Windows, convém mante-lo atualizado.

O WINE pode consumir bastante recursos da máquina, dependendo das aplicações que ele vai rodar (jogos por exemplo).

Por estas e outras o melhor é estar sempre com a versão mais recente e compilado para ter melhor desempenho.

Antes de mais, instalar as dependências do WINE:


$ sudo apt-get build-dep wine


Mas estas dependências não são completas, por isso veja em:

http://wiki.winehq.org/Recommended_Packages

E baixe e execute o arquivo de script de dependências correspondente a sua versão do Ubuntu, no meu caso:


$ wget http://winezeug.googlecode.com/svn/trunk/install-wine-deps.sh
$ chmod +x install-wine-deps.sh
$ sudo ./install-wine-deps.sh


Fazer o download da última versão do arquivo de source (.tar.bz2) do WINE em:

http://www.winehq.org/

Extrair o arquivo baixado. Através da console entrar dentro da pasta de sources do WINE e fazer:


$ ./configure


Se no final do "./configure" obtiver o seguinte warning:

configure: WARNING: No OpenGL library found on this system.
OpenGL and Direct3D won't be supported.


Então os links simbólicos da libGL não devem estar corretas, analise com:


$ ls /usr/lib/libGL* -o


É preciso que o link simbólico /usr/lib/libGL.so -> /usr/lib/libGL.so.XXX.XX esteja a apontar para a versão mais recente, onde "XXX.XX" é a identificação da versão mais alta, ou seja a mais recente, da libGL. Caso exista o link simbólico remova-o:


$ sudo rm /usr/lib/libGL.so


E agora crie o link simbólico para a versão mais recente que tiver:


$ sudo ln -s /usr/lib/libGL.so.XXX.XX /usr/lib/libGL.so


Tem que ser feito o ./configure outra vez, e agora sem o warning:


$ ./configure


Dependências e configurações feitas com sucesso, agora só falta compilar e instalar:


$ make depend && make
$ sudo make install


Pronto! Será criado menus para o WINE no menu de programas, e através da console é só executar:


$ wine ARQUIVO_EXECUTAVEL_DO_WINDOWS.exe


Para ver a lista dos programas suportados e a nível da qualidade de execução:

http://appdb.winehq.org/

Tuesday, February 3, 2009

Virtualização para servidores com VirtualBox

O que não falta agora é soluções de virtualização.

Mas a mais simples e com excelente performance na minha opinião é com o VirtualBox, dá para fazer tudo que é preciso com muita simplicidade e rapidez.

Para virtualização em desktop o VirtualBox já vem reinando a algum tempo.

E para servidor, muitos não apostam por que simplismente não sabem que é possível, mas dá! E não é preciso ter ambiente gráfico, usando o VRDP pode-se administrar a máquina remotamente. Mas convém ter o ambiente gráfico, tudo fica muito mais fácil, e hoje em dia não vejo por que não ter ambiente gráfico no servidor, pois o que não falta é ambientes gráficos levezinhos que nem afetam a performance do servidor.

Existe uma solução para máquinas virtuais usando OpenSolaris e VirtualBox, chamda xVM Server:
http://xvmserver.org/
http://www.sun.com/software/products/xvmserver/index.xml

Mas como já tenho o CentOS redondinho, agora é tarde.

Bem, então eu resolvi fazer de tudo para ter o VirtualBox trabalhando no servidor com o Windows 2003 Server em máquina virtual dentro do VirtualBox no CentOS 5.

Melhor impossível, ficou perfeito, excelente performance, fácil administração, todos serviços funcionando lindamente.

Vamos ao que interessa. Basicamente CentOS 5 com o VirtualBox instalado, com a máquina virtual para o Windows Server 2003 instalada e configurada, isto é moleza e o que não falta é tutoriais pela net ensinando como fazer isto com screenshots e tudo, e o VirtualBox é muito intuitivo. Por isso este não é o âmbito aqui.

Agora a parte mais complicada, que tive que pesquisar bastante, para fazer com que o CentOS comunicasse com o Windows Server. O que me ajudou mais a desvendar isto foi este script:

http://www.savvyadmin.com/virtualbox-host-interface-networking-with-nat/

Mas como nem tudo é perfeito, este script não serve no CentOS, é preciso algumas alterações.

Então em primeiro lugar, configurar o IP da máquina virtual, ir no Windows 2003 Server e configurar o TCP/IP assim:

IP address: 192.168.20.201
Subnet mask: 255.255.255.0
Default gateway: 192.168.20.1



Feito isto, ir no CentOS e criar uma interface de rede virtual:


# /usr/bin/VBoxTunctl -u root


Depois disto, pode verificar com o "/sbin/ifconfig -a" se aparece o tap0. Pronto ai esta a nossa interface de rede virtual.

É preciso configurar no VirtualBox para usar a nova interface de rede virtual, a tap0. Ir nos "Settings" da máquina virtual, em "Network", no "Attached to", mudar para "Host Interface", e selecionar a tap0. Para ir nos "Settings" tem que desligar a máquina virtual.

Settings da Máquina Virtual > Network > Attached to > Host Interface



Agora é preciso configurar a interface de rede virtual:


# /sbin/ip link set tap0 up
# /sbin/ip addr add 192.168.20.1/32 dev tap0
# /sbin/route add -host 192.168.20.201 dev tap0


Deverá conseguir "pingar" a máquina virtual:


# ping -c 1 192.168.20.201


Se for preciso rodar ASPX no servidor, ai esta a solução, só configuar no nginx para fazer proxy reverso do IIS no IP 192.168.20.201, e já vai funcionar perfeitamente.

A máquina virtual até aqui não tem acesso a internet. Para resolver isto é preciso fazer isto:


# /sbin/sysctl net.ipv4.ip_forward=1
# /sbin/iptables -t nat -A POSTROUTING --out-interface eth0 -j MASQUERADE
# /sbin/iptables -A FORWARD --in-interface tap0 -j ACCEPT


E também configurar os DNSs, primário e secundário, da máquina virtual, com os mesmos dados DNSs do CentOS, para ver os DNSs do CentOS:


# cat /etc/resolv.conf


Agora deverá ter a internet funcionando no Windows.

Podemos iniciar a máquina virtual pela linha de comando, só que ficamos sem acesso ao ambiente gráfico do VirtualBox. Para então ter acesso a máquina virtual convém configurar o VRDP no VirtualBox para acessar a máquina virtual remotamente:

Settings da Máquina Virtual > Remote Display > Enable VRDP Server

Settings da Máquina Virtual > Remote Display > Port = 3089



É importante mudar o número da porta, por que a porta do VRDP é a mesma do Terminal Services, da para trocar o número da porta do Terminal Services no regedit, mas é mais simples ai no VRDP, e assim já se evita um conflito.

Só que assim o VirtualBox vai deixar entrar qualquer um pelo VRDP sem autenticação, então convém bloquear a porta do VRDP para que ninguem fora do CentOS consiga controlar a máquina virtual:


# /sbin/iptables -A INPUT -p tcp -i eth0 --dport 3089 -j REJECT --reject-with tcp-reset

# /sbin/iptables -A INPUT -p tcp -i eth1 --dport 3089 -j REJECT --reject-with tcp-reset

# /sbin/iptables -A INPUT -p udp -i eth0 --dport 3089 -j REJECT

# /sbin/iptables -A INPUT -p udp -i eth1 --dport 3089 -j REJECT


Assim a porta do VRDP fica protegida para que ninguem que venha das interfaces de rede externas consiga conectar.

Para conectar via VRDP é só usar o tsclient:


# tsclient


No tsclient em computer colocar:

localhost:3089

E em protocol:

RDPv5

Clicar em "Connect", e pronto! Já conseguimos controlar a máquina virtual remotamente quando estivermos executando ela em background, isto será muito útil.

No Windows 2003 Server podemos ter o Terminal Services, e para acessar o terminal services através da internet ou rede temos que fazer uns ajustes, pois a porta do Terminal Services é a mesma do VRDP, então temos que mudar uma ou outra porta, como já mudamos a porta padrão do VRDP para 3089, então o Terminal Services vai funcionar bem na porta 3389.

Então para por o Terminal Services a funcionar é preciso ativar, no Windows Server:

Control Panel > System > Remote > Enable Remote Desktop on this computer



E agora é fazer NAT para a porta do Terminal Services:


# /sbin/iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 3389 -j DNAT --to 192.168.20.201:3389

# /sbin/iptables -t nat -A PREROUTING -p tcp -i eth1 --dport 3389 -j DNAT --to 192.168.20.201:3389


E assim fica o Terminal Services disponível, e o mesmo pode ser feito para outros serviços do Windows que precisam estar disponíveis externamente, como MSSQLServer.

Há outros exemplos desta configuração usando bridges, mas acho que assim fica muito mais simples.

Para iniciar a máquina virtual pela linha de comando é assim:


/usr/bin/VBoxVRDP -startvm NOME_DA_MAQUINA_VIRTUAL_NO_VIRTUALBOX


Para quando o servidor iniciar, iniciar também a máquina virtual e carregar toda configuração, coloquei os seguintes comandos no /etc/rc.local:


/usr/bin/VBoxTunctl -u root
/sbin/sysctl net.ipv4.ip_forward=1
/sbin/ip link set tap0 up
/sbin/ip addr add 192.168.20.1/32 dev tap0
/sbin/route add -host 192.168.20.201 dev tap0
/sbin/sysctl net.ipv4.ip_forward=1
/sbin/iptables -t nat -A POSTROUTING --out-interface eth0 -j MASQUERADE
/sbin/iptables -A FORWARD --in-interface tap0 -j ACCEPT
/sbin/iptables -A INPUT -p tcp -i eth0 --dport 3089 -j REJECT --reject-with tcp-reset
/sbin/iptables -A INPUT -p tcp -i eth1 --dport 3089 -j REJECT --reject-with tcp-reset
/sbin/iptables -A INPUT -p udp -i eth0 --dport 3089 -j REJECT
/sbin/iptables -A INPUT -p udp -i eth1 --dport 3089 -j REJECT
/sbin/iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 3389 -j DNAT --to 192.168.20.201:3389
/usr/bin/nohup /usr/bin/VBoxVRDP -startvm winserver > /dev/null &


Tem muita gente que acha deselegante usar o rc.local, mas eu não acho deselegante, muito pelo contrário, afinal pra que que ele serve? :P

No meu caso, em um AMD Opteron Quad-Core com 4GB de RAM, o Windows 2003 Server em máquina virtual de 512MB com o VirtualBox demora 6 segundos para estar completamente inicializado.

Thursday, November 27, 2008

Script Python para consumir Web Services em .Net

Tive um desafio a poucos dias. Que foi consumir Web Services feitos em .Net a partir de um servidor Solaris 10 via processo.

De todas as soluções possíveis que estive a ver, a melhor foi usar Python.

Encontrei este exemplo:

http://users.skynet.be/pascalbotte/rcx-ws-doc/postxmlpython.htm

Assim fiz o WebServiceGenericClientNet.py:

#!/usr/bin/python

# by eduveks

import sys, httplib, array

try:
    host = ""
    url = ""
    namespace = ""
    header = ""
    method = ""
    params = {}

    for arg in sys.argv[1:]:
        if host == "" and arg.find("host=") == 0:
            host = arg[len("host="):]
        elif url  == "" and arg.find("url=") == 0:
            url  = arg[len("url="):]
        elif namespace == "" and arg.find("namespace=") == 0:
            namespace = arg[len("namespace="):]
        elif header == "" and arg.find("header=") == 0:
            header = arg[len("header="):]
        elif method == "" and arg.find("method=") == 0:
            method = arg[len("method="):]
        elif arg.find("param_") == 0:
            params[arg[len("param_"):arg.find("=")]] = arg[arg.find("=") + 1:]

    SOAP_Request = ""
    SOAP_Request += "<soap:Envelope"
    SOAP_Request += " soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""
    SOAP_Request += " xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\""
    SOAP_Request += " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
    SOAP_Request += " xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">"
    if header != "":
        SOAP_Request += "<soap:Header>"
        SOAP_Request += header
        SOAP_Request += "</soap:Header>"
    SOAP_Request += "<soap:Body>"
    SOAP_Request += "<"+ method +" xmlns=\""+ namespace +"\">"
    for param in params.keys():
        SOAP_Request += "<"+ param +">"+ params[param] +"</"+ param +">"
    SOAP_Request += "</"+ method +">"
    SOAP_Request += "</soap:Body>"
    SOAP_Request += "</soap:Envelope>"

    http = httplib.HTTP(host)
    http.putrequest("POST", url)
    http.putheader("Host", host)
    http.putheader("User-Agent", "Python")
    http.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
    http.putheader("Content-length", "%d" % len(SOAP_Request))
    http.putheader("SOAPAction", "\""+ namespace + method +"\"")
    http.endheaders()
    http.send(SOAP_Request)

    http_response_statuscode, http_response_statusmessage, http_response_header = http.getreply()
    SOAP_Response = http.getfile().read()
    if http_response_statuscode == 200 and http_response_statusmessage == "OK":
        print SOAP_Response[SOAP_Response.find("<"+ method +"Result>") + len("<"+ method +"Result>"):SOAP_Response.find("</"+ method +"Result>")]
    else:
        print "### ERROR ###############"
        if SOAP_Response.find("<faultstring>") > -1:
            print SOAP_Response[SOAP_Response.find("<faultstring>")  + len("<faultstring>"):SOAP_Response.find("</faultstring>")]
        print "Response: ", http_response_statuscode, http_response_statusmessage
        print http_response_header
        print SOAP_Response

except:
    print "### ERROR ###############"
    for err in sys.exc_info():
        print err


Para executar o script basta dar permissões de execução e executar:

chmod +x WebServiceGenericClientNet.py
./WebServiceGenericClientNet.py host=localhost url=/HelloWorld.asmx namespace=http://tempuri.org/ method=HelloWorld param_strSay=HelloWorld


O output é:

HelloWorld


Os parâmetros do WebServiceGenericClientNet.py são:

host: Endereço do servidor
url: Endereço do web service
namespace: Namespace do web service, que pode ser encontrado vendo o WSDL, http://localhost/HelloWorld.asmx?WSDL
method: Método do web service a ser chamado
param_*NOME_DO_PARAMETRO*: Caso o método precise de parâmetros, podem ser definidos assim, atenção a ordem.

Além de usar este script no Solaris, também acabei por usar este script para chamar web services apartir do .Net/C#, pois são web services que serão atualizados constantemente, com novos métodos e talz, e em vez de ficar atualizando o WSDL, basta chamar diretamente com o script a queima-roupa, e a configuração da chamada dos web services pode ser feita a partir de configurações em base de dados. Para fazer isto no .Net/C# foi só lançar um processo assim:

System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = "C:\Python26\python.exe";
process.StartInfo.Arguments = "WebServiceGenericClientNet.py host=localhost url=/HelloWorld.asmx namespace=http://tempuri.org/ method=HelloWorld param_strSay=HelloWorld";
process.StartInfo.WorkingDirectory = "C:\Python26\";
process.Start();
string output = process.StandardOutput.ReadToEnd();

O script suporta a configuração do header, passando o argumento header=... para o script.

Para explorar e ver fácilmente os SOAPs enviados e recebidos na chamada de um web service, existe o WebServiceStudio:

Monday, September 15, 2008

Nvidia vs Ubuntu

O driver da Nvidia que vem por padrão no Ubuntu tem alguns bugs, como este:

http://www.nvnews.net/vbulletin/showthread.php?t=106790

Aqui estão os screenshots do bug:

http://home.arcor.de/cziepke/ut2004/



Para instalar o driver que resolve o problema, o NVIDIA-Linux-x86-177.13-pkg1.run, não é tão simples assim, eu pensava que era...

Baixei aqui o driver:

http://www.nvnews.net/vbulletin/showthread.php?t=118602

Consegui instalar, mas o Xorg ficou todo estragado, fiquei com a resoluão de 800x600 e o driver vesa, então procurei e encontrei a solução num forum francês:

http://forum.ubuntu-fr.org/viewtopic.php?id=249234

O que fiz então foi o seguinte:

Fiz logout, e mudei para o terminal 1 (ctrl + alt + F1), fiz o login, e matei o GDM:

# sudo killall gdm

Feito isto o Xorg deverá esta morto, verifique no terminal 7 (ctrl + alt + F7), se esta tudo preto.

Agora remova tudo que esta instalado da nvidia:

$ sudo apt-get remove --purge nvidia*

Instalar os headers do kernel e o xorg-dev:

$ sudo apt-get install build-essential linux-headers-`uname -r` xserver-xorg-dev

Faça um backup da configuração do Xorg:

$ sudo cp /etc/X11/xorg.conf /etc/X11/xorg.conf.good.backup

Agora é só instalar o driver, diga Yes para tudo:

$ sudo sh NVIDIA-Linux-x86-177.13-pkg1.run


Se durante a instalação der erro, dizendo que não consegue criar alguns arquivos, veja o caminho, provavelmente como aconteceu comigo será preciso criar a pasta:

$ sudo mkdir /usr/lib/nvidia

Depois é só voltar a executar a instalação e diga Yes para tudo mais uma vez:

$ sudo sh NVIDIA-Linux-x86-177.13-pkg1.run

Reiniciar o computador, e pronto, os gráficos deverão estar muito melhores, e o UT2004 sem bugs.

Guarde o arquivo de instalação, pois sempre que for instalado um novo kernel será preciso reinstalar o driver.

Friday, September 5, 2008

Unreal Tournament 2004 - Linux Dedicated Server

Nossa como é bom voltar a jogar UT2004 :P

Downloads

Servidor:
$ wget http://downloads.unrealadmin.org/UT2004/Server/DedicatedServer3323.zip
BonusPack:
$ wget http://downloads.unrealadmin.org/UT2004/Server/dedicatedserver3339-bonuspack.zip
Anticheater:
$ wget http://downloads.unrealadmin.org/UT2004/AntiCheat/UTSecure2K4-111.zip

Quem for jogar, convêm ter o MegaPack instalado, para evitar que fique fazendo download:

MegaPack - 12/13/05 - 205 MB

Instalação

$ unzip DedicatedServer3323.zip
$ mv UT2004-Dedicated-3323 UT2004srv
$ unzip -o dedicatedserver3339-bonuspack.zip -d UT2004srv
$ unzip -o UTSecure2K4-111.zip -d UT2004srv
$ chmod +x UT2004srv/System/ucc*

Configuração

Não apague nenhuma linha do arquivo, apenas altere as linhas indicadas abaixo.

Editar o UT2004.ini:

$ vim UT2004srv/System/UT2004.ini

Habilitar a administração web:

[UWeb.WebServer]
bEnabled=True
ListenPort=7775

Alterar o nome do servidor:

[Engine.GameReplicationInfo]
ServerName=Nome Do Teu Servidor
ShortName=Nome Servidor

Liberar para quem não tem o jogo original poder jogar, e desabilitar a verificação de keys:

[IpDrv.MasterServerUplink]
DoUplink=False
UplinkToGamespy=False
SendStats=False
ServerBehindNAT=False
DoLANBroadcast=False
bIgnoreUTANBans=True


Executar

$ cd UT2004srv/System
$ sudo ./ucc-bin server DM-Gael?game=XGame.xDeathMatch?mutator=XGame.MutQuadJump?AdminName=admin?AdminPassword=XXXXX?GamePassword=XXXXX ini=UT2004.ini log=UT2004.log -nohomedir


Os XXXXX são as senhas, a senha para entrar no servidor é a ?GamePassword=XXXXX, substitua os XXXXX por uma senha mais intuitiva do seu entender. Os parametros ?Admin* são os dados para entrar na administração web pelo endereço http://servidor:7775.

Se obtiver este erro:
./ucc-bin: error while loading shared libraries: libstdc++.so.5: cannot open shared object file: No such file or directory

Para resolver este erro é preciso fazer um link simbólico para a versão 5.* da libstdc++, que fica na pasta /usr/lib/libstdc++*, no meu caso fiz assim:

$ sudo ln -s /usr/lib/libstdc++.so.5.0.7 /usr/lib/libstdc++.so.5

Agora é só executar de novo!

Jogar

Para jogar no servidor, é só ir na lista de servidores online dentro do jogo e clicar com o botão direito e no menu que aparece ir em "Open Ip", e colocar o endereço do servidor!

Quem não tem o jogo original pode jogar no teu servidor usando este crack:

Unreal Tournament 2004 v3369 PRIVATE WINDOWS SERVER PATCH

Detalhes da Configuração

Na linha de execução tem os parâmetros:

DM-Gael?game=XGame.xDeathMatch?mutator=XGame.MutQuadJump

DM-Geal se refere ao Mapa, você pode colocar o nome de outro mapa, basta ver os mapas disponíveis em UT2004srv/Maps/*.

O game= XGame.xDeathMatch é o tipo de jogo, todos os tipos de jogos:

Assault: AS-MotherShip?game=UT2k4Assault.ASGameInfo
CTF: CTF-FaceClassic?game=XGame.xCTFGame
Bombing Run: BR-Serenity?game=XGame.xBombingRun
DoubleDomination: DOM-SunTemple?game=xGame.xDoubleDom
DeahtMatch: DM-Rankin?game=XGame.xDeathMatch
Invasion: DM-Antalus?game=SkaarjPack.Invasion
LastManStanding: DM-Morpheus3?game=BonusPack.xLastManStandingGame
Mutant: DM-Deck17?game=BonusPack.xMutantGame
Onslaught: ONS-Torlan?game=Onslaught.ONSOnslaughtGame
TeamDeathMatch: DM-Rankin?game=XGame.xTeamGame

O mutator=XGame.MutQuadJump é o mutator, pode remover isto se não quiser nenhum mutator, todos os tipos de mutators:

Arena: XWeapons.MutArena
Beserk: UnrealGame.MutBerserk
Big Head: UnrealGame.MutBigHead
Delayed Spawn: UnrealGame.MutDelayedSpawn
Float-Away Corpses: XGame.MutHeliumCorpses
InstaGib: XGame.MutInstaGib
Zoom InstaGib: XGame.MutZoomInstaGib
LowGravity: UnrealGame.MutLowGrav
No Adrenaline: XGame.MutNoAdrenaline
No Super Weapons: XWeapons.MutNoSuperWeapon
Quad Jump: XGame.MutQuadJump
AutoHealing: XGame.MutRegen
Slow Motion Deaths: XGame.MutSlomoDeath
Species Specific Stats: XGame.MutSpeciesStats
UDamage Reward: XGame.MutUDamageReward
Vampire :XGame.MutVampire
UTV2004S (UTV2004 in SeeAll mode): UTV2004s.utvMutator
UT2k3 Style Weapon Throwing/Boosting: XGame.MutFastWeapSwitch
UTClassic: UTClassic.MutUTClassic
Lightning Gun 2 Sniper Rifle: UTClassic.MutUseSniper
Sniper Rifle 2 Lightning Gun: UTClassic.MutUseLightning
Camouflage Combo (RRRR): Bonuspack.MutCrateCombo
Pint-sized combo (LLLL): Bonuspack.MutPintSizeCombo
BigWheels: Onslaught.MutBigWheels
Light Weight Vehicles: Onslaught.MutLightweightVehicles
Onslaught Weapons: Onslaught.MutOnslaughtWeapons
Jumping Vehicles: Onslaught.MutWheeledVehicleStunts
Vehicle Arena: OnslaughtFull.MutVehicleArena

Referência

DragonBe - Unreal Tournament 2004 Dedicated Server

Gentoo - UT2004 Dedicated Server Installation

LINUX; UT2004-bin: error while loading shared libraries: libstdc++.so.5

Compre o jogo orignal!

Este jogo esta barato e vale a pena ter o original.

É um excelente jogo, e é dos jogos que mais se preocupa em ter suporte nativo ao Linux, por isso também, não deixe de colaborar.

Monday, September 1, 2008

Nginx

Conheci o Nginx no forum do GUJ.com.br, depois com os resultados que o Fabio Kung postou no blog da Caelum, fiquei convencido que o Nginx seria a melhor solução para os meus problemas.

E depois que conheci o Nginx já não quero mais nada, estou extremamente satisfeito, excelente robustez.

Para instalar o Nginx fiz um artigo no VivaOLinux.com.br que ensina como fazer a instalação e os links do site e da documentação.

Consegui fazer uma configuração simples para configurar multiplos domínios virtuais, segue a configuração:


worker_processes 5;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/xml text/xhtml text/css text/js application/x-javascript application/json;
error_page 500 502 503 504 /50x.html;
server {
listen 80;
server_name _;
root /home/websites/$host;
location / {
index index.html index.htm index.jsp;
}
location ~ \.jsp$ {
proxy_pass http://localhost:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
}


Repare nesta linha:


root /home/websites/$host;


Ai em /home/websites/* eu tenho os atalhos para as pastas reais dos domínios.

Então por exemplo para acrescentar um novo domínio dominio.com:

ln -s /home/dominio.com /home/websites/dominio.com
ln -s /home/dominio.com /home/websites/www.dominio.com


Assim para configurar um novo domínio no Nginx é só adicionar um novo atalho no /home/websites neste caso.

Ativar compressão gzip:


gzip on;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/xml text/xhtml text/css text/js application/x-javascript application/json;


Para o Nginx encaminhar os JSPs para o Jetty:


location ~ \.jsp$
proxy_pass http://localhost:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}

Monday, June 9, 2008

GlassFish vs Apache

Gastei um tempinho para desvendar certos mistérios por trás desta configuração e contornar alguns problemas.

Para configurar segui o post do Jean-Francois Arcand's e da Amy Roh's.

Então vamos lá!

Primeiro no Apache, instalar o mod_jk:

apt-get install libapache2-mod-jk

Configurar o conteúdo do arquivo /etc/apache2/mods-available/jk.load:

# Modulo do mod_jk
LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so
# Arquivo de configuração
JkWorkersFile /etc/apache2/mod_jk_worker.properties
# Arquivo de log
JkLogFile /var/log/apache2/mod_jk.log
# Nível de detalhe dos logs [debug/error/info]
JkLogLevel debug
# Formato das mensagens de log
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# JkOptions indica para enviar SSL KEY SIZE
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat define o formato dos requests no Log
JkRequestLogFormat "%w %V %T"
# Envia todos jsp para o GlassFish
JkMount /*.jsp worker1
# Envia todos os acessos ao meu projeto web para o GlassFish
JkMount /WebApplication/* worker1

Na última linha, o WebApplication se refere ao nome do nosso projeto no GlassFish, coloque aqui o nome do teu projeto no GlassFish.

Agora falta configurar o /etc/apache2/mod_jk_worker.properties, com este conteúdo:

# Define 1 worker usando ajp13
worker.list=worker1
# Define as propriedades do worker1 (ajp13)
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
worker.worker1.lbfactor=50
worker.worker1.cachesize=10
worker.worker1.cache_timeout=600
worker.worker1.socket_keepalive=1
worker.worker1.socket_timeout=300

Agora vamos ao GlassFish...

No Glassfish configurar as seguintes opções da JVM:

$GLASSFISH_HOME/bin/asadmin create-jvm-options -Dcom.sun.enterprise.web.connector.enableJK=8009

E também:

$GLASSFISH_HOME/bin/asadmin create-jvm-options -Dcom.sun.enterprise.web.connector.enableJK.propertyFile=/etc/apache2/mod_jk_worker.properties

Para confirmar se ficou bem configurado, verifique o arquivo:

$GLASSFISH_HOME/domains/domain1/config/domain.xml

Procurar neste arquivo por:

<jvm-options>-Dcom.sun.enterprise.web.connector.enableJK=8009</jvm-options>
<jvm-options>-Dcom.sun.enterprise.web.connector.enableJK.propertyFile=/etc/apache2/mod_jk_worker.properties</jvm-options>

Fazer o download do apache-tomcat-5.5.16.zip, e pegar o tomcat-ajp.jar, só serve o jar desta versão, os das versões superiores não funcionam, provocam o seguinte erro no GlassFish:

Caused by: java.lang.NoSuchMethodError: org.apache.coyote.Response.getContentLengthLong()J

Depois do download, procurar o tomcat-ajp.jar dentro do zip:

apache-tomcat-5.5.16/server/lib/tomcat-ajp.jar

E copiar este jar para dentro do GlassFish:

$GLASSFISH_HOME/lib/

Também são precisos os jars commons-modeler e commons-logging, que podem ser adquiridos aqui:

http://commons.apache.org/downloads/index.html

Modeler:
http://commons.apache.org/downloads/download_modeler.cgi

Logging:
http://commons.apache.org/downloads/download_logging.cgi

Copiar estes dois jars também para dentro do:

$GLASSFISH_HOME/lib/

Feito isto, é preciso reiniciar o Apache e o GlassFish, e agora deverá estar funcionando através do Apache:

http://localhost/WebApplication

Assim através do Apache da para acessar os projetos publicados no GlassFish!

O porto 8009 que configuramos para o JK não tem nada haver com o porto web do GlassFish, o mod JK usa um protocolo próprio para comunicar com o Tomcat/AJP, e o GlassFish o que faz é inicia um novo porto usando o JK do Tomcat para poder comunicar com o mod_jk no Apache, e para testar se este porto esta funcionando pode-se usar o telnet e ver se conecta:

telnet localhost 8009

Futuramente pretendo investigar sobre Load Balancing usando o Apache e Glassfish e espero falar sobre isto.

Friday, May 9, 2008

Backup

A alguns anos fiz um sistema de backups em ShellScript e hoje configurei ele num servidor novo, e reparei como ele tem sido útil e tem resultado muito bem, resolvi partilhar.

Criar as pastas:

# mkdir /backup
# mkdir /backup/log


Criar os seguintes arquivos:

# touch /backup/backup
# touch /backup/backup.start
# touch /backup/backup.end
# touch /backup/directory
# touch /backup/run


Dar permissões de execução:

# chmod +x /backup/backup
# chmod +x /backup/backup.start
# chmod +x /backup/backup.end
# chmod +x /backup/run


Os backups diários serão guardados dentro da pasta /backup/daily. E os mensais sempre no dia 1 serão guardados dentro da pasta /backup/monthly. Não é preciso criar estas pastas, elas são criadas automaticamente.

Colar este conteúdo no arquivo /backup/backup:

#!/bin/bash
echo ""
echo -e "\e[40;32;1m Backup \e[0m"
echo ""
echo -e "\e[44;33;1m Start \e[0m"
echo ""
dir1="/backup"
dir2=$1
echo -ne "\e[34;1mcomand.begin\e[0m \e[32mstart\e[0m \e[30;5m...\e[0m"
$dir1/backup.start
echo -e "\e[31;1m end \e[0m"
echo ""
dateDay=`date "+%d"`
dateMonth=`date "+%m"`
dateYear=`date "+%Y"`
folder1=$dir1/daily/$dateDay
folder2=$dir2/daily/$dateDay
echo -ne "\e[34;1mWork Folder\e[0m $folder1 \e[32mstart\e[0m \e[30;5m...\e[0m"
rm -dfr $folder1
mkdir -p $folder1
echo -e "\e[31;1m end \e[0m"
echo ""
if [[ $dir2 != "" ]]; then
echo -ne "\e[34;1mWork Folder\e[0m $folder2 \e[32mstart\e[0m \e[30;5m...\e[0m"
rm -dfr $folder2
mkdir -p $folder2
echo -e "\e[31;1m end \e[0m"
echo ""
fi
echo -e "\e[40;31;1m BACKUP: directory \e[0m"
echo " |"
_x=0
_to=""
for i in `cat /backup/directory`; do
if [ $_x = 0 ]; then
_to=$folder1/$i.tar.gz
echo -ne " | $i \e[32mstart\e[0m \e[30;5m...\e[0m"
_x=1
else
tar -czPf $_to $i
if [[ $dir2 != "" ]]; then
cp -rf $_to $folder2
fi
echo -e "\e[31;1m end \e[0m"
_x=0
fi
done
echo " |____________________________________________________"
echo ""
echo -ne "\e[34;1mcomand.end\e[0m \e[32mstart\e[0m \e[30;5m...\e[0m"
$dir1/backup.end $folder1
echo -e "\e[31;1m end \e[0m"
if [ $dateDay = 01 ]; then
folderMonthly1=$dir1/monthly/$dateYear.$dateMonth.$dateDay
echo -ne "\e[34;1mMonthly Backup]\e[0m $folderMonthly1 \e[32mstart\e[0m \e[30;5m...\e[0m"
mkdir -p $folderMonthly1
cp -rf $folder1 $folderMonthly1
echo -e "\e[31;1m end \e[0m"
if [[ $dir2 != "" ]]; then
folderMonthly2=$dir2/monthly/$dateYear.$dateMonth.$dateDay
echo -ne "\e[34;1mMonthly Backup]\e[0m $folderMonthly2 \e[32mstart\e[0m \e[30;5m...\e[0m"
mkdir -p $folderMonthly2
cp -rf $folder2 $folderMonthly2
fi
echo ""
fi
echo ""
echo -e "\e[44;33;1m End \e[0m"
echo ""
echo -e "\e[40;32;1m by eduveks \e[0m"
echo ""


O arquivo /backup/run é o que inicia o backup e grava o output no arquivo de log, colocar o seguinte conteúdo:


#!/bin/bash
logFileName=`date "+%Y-%m-%d_%H-%M-%S"`
/backup/backup "/mnt/backupmirror" > /backup/log/$logFileName


Atenção ao "/mnt/backupmirror/backup", esta opção é para fazer uma cópia do backup para outra pasta, no meu caso sempre uso um servidor secundário para ter um espelho do backup original, e esta pasta é uma pasta montada remotamente ao outro servidor.

Os arquivos /backup/backup.start e /backup/backup.end, servem para poder colocar comandos para serem executados antes e depois do backup respectivamente, por exemplo para fazer o mount e o umount de uma partilha remota, preparando o cenário da cópia secundária. Ou ainda para parar serviços e reinicia-los no fim, por exemplo para o MySql antes de começar o backup e no fim voltar a inicializa-lo. Gravar nestes arquivos o conteúdo:


#!/bin/bash


Finalmente o arquivo /backup/directory serve para dizer as pastas que deverá ser feito backup, adicionar aqui o nome que vai ter o arquivo.tar.gz e qual a pasta que vai ser armazenada neste arquivo, no seguinte formato:


DB_NAME     /var/lib/mysql/DB_NAME
USER1       /home/USER1


Depois de tudo afinado vamos executar o backup, assim podemos ver o output:

# /backup/backup


Se tudo correu bem, o backup deverá estar em:

# /backup/daily/01/DB_NAME.tar.gz
# /backup/daily/01/USER1.tar.gz


Onde o "01" é o número do dia do mês atual.

Assim a cada dia haverá uma pasta com os backups deste dia, e no dia 1 de cada mês, o backup deste dia estará em:

# /backup/monthly/2008.05.01/01/DB_NAME.tar.gz
# /backup/monthly/2008.05.01/01/USER1.tar.gz


E executar o backup passando uma pasta para ser o espelho do backup:

# /backup/backup /tmp


Poderá reparar que também dentro do /tmp passará a ter o conteúdo do backup.

Feito o teste, voltar a ver como esta o /backup/run, verificar se esta tudo certo, e testa-lo:

# /backup/run


Dentro da pasta /backup/log deverá ter o log do backup:

# cd /backup/log
# ls
# cat 2008-05-01_11-51-53


Agora só falta configurar no crond para executar o backup, criar um arquivo no /etc/cron.daily/backup, com o seguinte conteúdo:


#!/bin/sh
/backup/run


Pronto, agora o backup irá ser executado todos os dias, e assim temos uma solução bem simples e prática para fazer backups...

Wednesday, May 7, 2008

Ubuntu 8.04 vs RaLink RT2561/RT61

Após uma longa batalha, finalmente posso desfrutar do prazer do wireless :P

Tentei durante alguns dias configurar a rede wireless, por duas vezes consegui, mas não ficou bom, e depois parou de funcionar.

O problema era que conseguia conectar, e até o ping funcionava mas muitooo lento, com 200ms, e as vezes não funcionava, e depois por mais que insistisse o DNS não funcionava e não consegui que algum site abrisse, mesmo o site do router, então começei a fazer buscas frenéticas atrás da solução, medidas de desespero.

Para começar verifique o modelo da tua placa:

$ lspci | grep RaLink
02:09.0 Network controller: RaLink RT2561/RT61 rev B 802.11g

Primeiro tentei desta forma, utilizando os drivers do Windows:

http://i-eat-noobs.blogspot.com/2007/08/get-wireless-working-in-ubuntu-704.html

http://www.ralinktech.com/ralink/Home/Support/Windows.html

Usei o PCI/mPCI/CB(RT256x/RT266x), mas como diz a descrição ao lado, vem o drive da RT61 para o Windows Vista, mesmo assim tentei, o cabextract, e o unshield e ainda com o wine, não consegui pegar o arquivo .inf que o ndiswrapper pede, por motivos de força maior deste jeito a coisa não vai e tive que ir atrás de outra solução.

Mais pesquisas, e descobri que muitos já tiveram este problema e indicavam que tinha a ver com o Driver mesmo:

http://ubuntuforums.org/showthread.php?t=550351

Além de muitos outros...

Então encontrei esta dica para instalar o driver para Linux oficial da RaLink:

http://ubuntuforums.org/showthread.php?p=4867439

http://www.ralinktech.com/ralink/Home/Support/Linux.html

Usei o RT2501PCI/mPCI/CB(RT61:RT2561/RT2561S/RT2661), a instalação não foi bem como diz na dica, foi quase, cosegui instalar e configurar, mas não consegui de nenhuma forma que funcionasse, ficou bem mais rápido as mensagens do ping mas sempre sem sucesso, e também o nm-applet não reconheceu mais o wireless, reparei que por mais que tentasse alterar a configuração da conexão, no iwconfig ficava sempre igual, nenhuma configuração era alterada. Comecei a ver que estava sem saída de novo...

Resolvi rever os passos, e se olhar melhorar para este link:

http://www.ralinktech.com/ralink/Home/Support/Linux.html

Tem lá em baixo... "The rt2x00 Open Source Project"... rt2x00 que porcaria é esta, resolvi clicar, tudo que precisava para ter esperança:

This project is a development effort to provide free, stable and feature rich Linux drivers for
wireless 802.11b/g/i cards based on the following Ralink chipsets: rt2400, rt2500, rt2570,
rt61 and rt73.


Em downloads fiz o download do "Last beta release: v1.1.0-b2", mas como tenho muita sorte, ao tentar compilar deu erro na compilação...

Agora só falta a última chama de esperança, o "CVS hourly tarball: rt61-CVS", o que correu muito bem, e mais simples impossível.

Fazer o download:

http://rt2x00.serialmonkey.com/rt61-cvs-daily.tar.gz

Extrair:
$ tar -xzf rt61-cvs-daily.tar.gz

No meu caso foi:
$ cd rt61-cvs-2008050721/Module

Dá para ver que o projeto não esta abandonado.

Compilar e instalar, com a conta do root:
# make && make install

Caso de erro na compilação deve ser que falta instalar o source da versão do kernel que esta sendo usado, ter atenção a isto, é preciso ter a source do kernel instalada.

Feito isto falta registrar o novo module:
# echo "rt61" >> /etc/modules

Também pode tentar um "modprobe rt61", mas convém fazer um: Reboot!

O nm-applet reconheceu o wireless, consegui conectar facilmente, logo de primeira a internet funcionou, e vim fazer este post com tudo fresquinho na cabeça, são agora 4:50 da manhã e seja o que Deus quiser amanhã no trabalho, ou melhor hoje :P

Usei a configuração manual, que na automática pediu a senha 2 vezes e ai cancelei e fui tentar no manual e funcionou muito bem com WEP (ASCII).

Também fui testar alguns sites mais pesado, e reparei que ficou muito mais rápido que no outro notebook com windows... muito rápido mesmo, demorou, custou, mas valeu a pena.

Próximo é passo configurar com WPA em vez de WEP...

Tuesday, April 8, 2008

LVM vs Mount

Se por acaso ao tentar montar uma partição no Linux e der com o seguinte erro:

mount: unknown filesystem type 'LVM2_member'

O problema é que as partições do disco foram registradas na LVM.

Minha distribuição é o OpenSuse 10.3, mas em princípio esta solução servirá para qualquer Linux.

Podemos ver a estrutura LVM com o comando:

# /sbin/pvs

PV VG Fmt Attr PSize PFree
/dev/sdb1 system lvm2 a- 5,86G 5,86G


Para mais detalhes:

# /sbin/pvscan

PV /dev/sdb1 VG system lvm2 [5,86 GB / 5,86 GB free]
Total: 1 [5,86 GB] / in use: 1 [5,86 GB] / in no VG: 0 [0 ]


Precisamos do VG Name, mais detalhes ainda:

# /sbin/pvdisplay /dev/sdb1

--- Physical volume ---
PV Name /dev/sdb1
VG Name system
PV Size 5,86 GB / not usable 3,73 MB
Allocatable yes
PE Size (KByte) 4096
Total PE 1499
Free PE 1499
Allocated PE 0
PV UUID lPwtfx-5ocj-eXah-gqcX-1bCd-kcod-YN96is


Com o VG Name que no meu caso é "system".

Podemos agora remover o Volume Group:

# vgremove system

Volume group "system" successfully removed


Se voltar a fazer o pvs, pvscan ou pvdisplay, verificamos que o disco já não tem o VG Name (Volume Group Name).

Falta remover definitivamente a partição da LVM, com o seguinte comando:

# pvremove /dev/sdb1

Labels on physical volume "/dev/sdb1" successfully wiped


Se tentar montar a partição agora não vai ser possível, vai dar sempre esta mensagem, mesmo definindo o type:

# mount /dev/sdb1 /mnt/hd1

mount: you must specify the filesystem type


Então é preciso fazer um reboot, para que os dispositivos dos discos sejam recarregados:

# reboot

Depois do reboot verifique com o pvs, pvscan ou pvdisplay, para ter a certeza que a partição já não esta registrada.

Agora só falta montar a partição normalmente:

# mount /dev/sdb1 /mnt/hd1

Para mais informações veja a documentação:
http://tldp.org/HOWTO/LVM-HOWTO/

E para saber para que serve a LVM e mais informções:
http://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)

Saturday, February 23, 2008

Apache 2.2 - Modules

No Apache 2.2 resolveram mudar os nomes dos modulos, o que tem dado alguma dor de cabeça...

Lista da mudanças nos nomes dos modulos.

Se tiver o seguinte erro:

[CODE]

Starting httpd: httpd: Syntax error on line 170 of /etc/httpd/conf/httpd.conf: Cannot load /etc/httpd/modules/mod_access.so into server: /etc/httpd/modules/mod_access.so: cannot open shared object file: No such file or directory

[/CODE]

Segue a lista dos modulos corrigido:

[CODE]
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_anon_module modules/mod_authn_anon.so
LoadModule authn_dbm_module modules/mod_authn_dbm.so
LoadModule auth_digest_module modules/mod_auth_digest.so
LoadModule ldap_module modules/mod_ldap.so
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
LoadModule include_module modules/mod_include.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule mime_magic_module modules/mod_mime_magic.so
LoadModule cern_meta_module modules/mod_cern_meta.so
LoadModule expires_module modules/mod_expires.so
LoadModule deflate_module modules/mod_deflate.so
LoadModule headers_module modules/mod_headers.so
LoadModule usertrack_module modules/mod_usertrack.so
LoadModule unique_id_module modules/mod_unique_id.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule mime_module modules/mod_mime.so
LoadModule dav_module modules/mod_dav.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule asis_module modules/mod_asis.so
LoadModule info_module modules/mod_info.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule vhost_alias_module modules/mod_vhost_alias.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule dir_module modules/mod_dir.so
LoadModule imagemap_module modules/mod_imagemap.so
LoadModule actions_module modules/mod_actions.so
LoadModule speling_module modules/mod_speling.so
LoadModule userdir_module modules/mod_userdir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule cache_module modules/mod_cache.so
LoadModule suexec_module modules/mod_suexec.so
LoadModule disk_cache_module modules/mod_disk_cache.so
LoadModule file_cache_module modules/mod_file_cache.so
LoadModule mem_cache_module modules/mod_mem_cache.so
LoadModule cgi_module modules/mod_cgi.so
[/CODE]

Fiz isto no CentOS 5.1, mas deve ajudar na configuração em outras distribuições.

Sunday, January 13, 2008

NetBeans 6 vs OpenSuse 10.3

Se tiver problemas com OpenSuse 10.3 para rodar o NetBeans 6, o bug-buddy acusando um bug e parando a execução logo na inicialização. Então vou explicar como instalar o JDK 6 e o NetBeans 6 no OpenSuse 10.3 e resolver este problema.

Instalação JDK 6:
- Em java.sun.com abrir o link para o Java SE, depois fazer o download do JDK 6 Update 4 versão para Linux o que tem a extenção .rpm.bin:
jdk-6u4-linux-x64-rpm.bin
- Dar permissões de execução para o arquivo:
chmod +x jdk-6u4-linux-x64-rpm.bin
- Executar:
./jdk-6u4-linux-x64-rpm.bin
- Vai ser criado no mesmo diretório varios arquivos *.rpm, para instalar execute:
sudo /sbin/yast2 -i jdk-6u4-linux-amd64.rpm
- O JDK 6 será instalado em:
/usr/java/jdk1.6.0_04
- E também terá estes atalhos para o jdk:
/usr/java/latest
/usr/java/default

Instalação NetBeans 6:
- Em www.netbeans.org faça o download do NetBeans 6 versão Linux, eu usei a versão "All".
- Dar permissões de execução para o arquivo:
chmod +x netbeans-6.0-linux.sh
- Eu instalei em /opt, caso queira instalar ai também faça assim:
sudo mkdir /opt/netbeans-6.0
sudo chmod a+rwx /opt/netbeans-6.0
sudo mkdir /opt/glassfish-v2
sudo chmod a+rwx /opt/glassfish-v2
- Agora execute o arquivo de instalação do NetBeans 6, e escolha a pasta de instalação, se for no /opt/netbeans-6.0 escolha esta pasta e o GlassFish também /opt/glassfish-v2, e eu coloquei em JDK /usr/java/latest.
- Será criado atalhos no desktop e nos programas.
- Execute...

Caso de Error, do bug-buddy, como aconteceu no meu caso, ele pode ser removido, não vai fazer falta, para o remover execute:
sudo zypper rm bug-buddy

Agora é só executar outra vez e deverá ter o problema resolvido, e o NetBeans 6 a funcionar perfeitamente.