segunda-feira, 26 de julho de 2010

[Oracle ODI] FTP e SFTP


Olá pessoal,

Continuo com meus estudos e implementações em ODI e hoje escrevo sobre uma limitação que encontrei na ferramenta, e também como eu a solucionei/contornei.

Vamos para o que interessa.

Tentei utilizar o componente de FTP padrão do ODI para transferir arquivos para alguns sistemas, e para um caso especifico não consegui fazer funcionar de jeito nenhum. A única diferença que percebi entre os sistemas que funcionavam para o que não funcionava era a seguinte:

Ao logar em um FTP, onde o componente padrão de FTP do ODI funcionou, em uma estação linux, era apresentado a seguinte linha no cabeçalho.

Exemplo: Remote system type is UNIX.

Em um dos sistemas, que eu tive problemas em conectar com o componente do ODI, a seguinte mensagem é retornada:

Exemplo: Remote system type is xxxxxxxxxxxxxxx.
Observe o xxxxxxxxxxxxxxx, acredito que este possa ser o motivo do componente de FTP do ODI não conseguir conectar.
Bom, já que não foi possível utilizar o componente padrão do ODI, resolvi escrever uma procedure em Jython para fazer FTP. Na primeira versão utilizei o módulo snpsftp, e o código que implementei na procedure ficou mais ou menos assim:
1 import snpsftp 2 ftp = snpsftp.SnpsFTP('ftp.myserver.com', 'mylogin', 'mypasswd') 3 ftp.setmode('ASCII') 4 ftp.put('/home/oracle/teste.txt','/u02/arquivos/teste.txt') 5 ftp.close()

Estava tudo funcionando bem, mas logo surgiu a necessidade de fazer SFTP ao invés de FTP. E o módulo snpsftp, claro, não implementa SFTP. :(
A solução foi desenvolver o meu próprio módulo.
Desenvolvendo um novo módulo

O primeiro passo foi criar um módulo (biblioteca) utilizando a linguagem Jython, e neste passo contei com a ajuda de um colega “fera” na linguagem Python. Segue abaixo o código do módulo que desenvolvemos.
1 import com.jcraft.jsch.Channel; 2 import com.jcraft.jsch.ChannelSftp; 3 import com.jcraft.jsch.JSch; 4 import com.jcraft.jsch.JSchException; 5 import com.jcraft.jsch.Session; 6 import com.jcraft.jsch.SftpException; 7 8 import java.util.Hashtable 9 import java.io.File 10 import java.io.FileInputStream 11 12 import os 13 14 __all__ = ["SFTP"] 15 16 class SFTP: 17 18 def __init__(self, paramHost, paramUser, paramPass): 19 self.strHost = paramHost 20 self.strUser = paramUser 21 self.strPass = paramPass 22 23 def putFile(self, paramDestino, paramFile): 24 self.__execute('putFile', paramFile, paramDestino) 25 26 def getFile(self, paramDestino, paramFile): 27 self.__execute('getFile', paramFile, paramDestino) 28 29 def deleteFile(self, paramFile): 30 self.__execute('deleteFile', paramFile, None) 31 32 def __execute(self, paramCommand, paramFile, paramDestino): 33 34 ObjJSch = com.jcraft.jsch.JSch() 35 ObjSession = com.jcraft.jsch.Session 36 37 try: 38 ObjHashTable = java.util.Hashtable() 39 ObjHashTable.put("StrictHostKeyChecking", "no") 40 41 ObjSession = ObjJSch.getSession(self.strUser, self.strHost, 22) 42 ObjSession.setConfig(ObjHashTable) 43 ObjSession.setPassword(self.strPass) 44 45 ObjSession.connect() 46 47 ObjChannel = ObjSession.openChannel("sftp") 48 ObjChannel.connect() 49 50 ObjSftp = com.jcraft.jsch.Channel 51 ObjSftp = ObjChannel 52 53 intMode = com.jcraft.jsch.ChannelSftp.OVERWRITE 54 55 try: 56 if paramCommand == 'putFile': 57 58 try: 59 ObjSftp.cd(paramDestino) 60 ObjFile = java.io.File(paramFile) 61 strNameFile = ObjFile.getName() 62 strNewFileName = "TMP_%s" % strNameFile 63 ObjSftp.put( java.io.FileInputStream(ObjFile), strNewFileName ) 64 ObjSftp.rename(strNewFileName, strNameFile) 65 except Exception, e: 66 raise e 67 68 elif paramCommand == 'getFile': 69 70 ObjSftp.get(paramFile, paramDestino) 71 72 elif paramCommand == 'deleteFile': 73 74 ObjSftp.rm(paramFile) 75 76 else: 77 78 raise Exception("METODO NAO IMPLEMENTADO") 79 80 except com.jcraft.jsch.JSchException, e: 81 raise e 82 83 except com.jcraft.jsch.SftpException, e: 84 raise e 85 86 print "OK"
Após criar o módulo, no nosso caso chamamos de “sftp.py”, este precisa ser salvo na pasta <ODI_HOME>/lib/scripting/Lib/ e é necessário reiniciar o agente para funcionar.
Para fins de teste é possível executar o console da linguagem jython através do executável <ODI_HOME>/bin/jython.sh.
Feito isto, agora podemos criar as procedures dentro do ODI, abaixo segue o código utilizado nas 3 operações que eu precisei implementar.

Operação PUT:
1 import sftp 2 3 ftp = sftp.SFTP(‘host’,’user’,’password’) 4 5 ftp.putFile('diretório destino','diretório origem/nome do arquivo')

Operação GET:
1 import sftp 2 3 ftp = sftp.SFTP(‘host’,’user’,’password’) 4 5 ftp.getFile('diretório destino','diretório origem/nome do arquivo')

Operação DELETE:
1 import sftp 2 3 ftp = sftp.SFTP(‘host’,’user’,’password’) 4 5 ftp.deleteFile(‘diretório/nome do arquivo')

No final, juntei tudo isso e desenvolvi um pacote genérico no ODI, o que me permite utilizar FTP ou SFTP, em qualquer integração sem que eu precise reescrever estes códigos.

Abraço, e até o próximo post.

Referências
Jython Reference

Um comentário:

  1. Olá Zucheto, como vai?
    Estou em um projeto onde preciso ler um diretorio remoto(FTP) e logo após o cenario terminar o processo preciso que ele delete o arquivo pois ao rodar o cenário novamente não podemos ler o mesmo arquivo, sei que isso deveria ser executado por quem disponibiliza ja que o ODi tem essa limitação, porém aqui no projeto essa tarefa terá que ser executada pelo ODI , tentei implementar suas dicas no site porém esta dando vários erros , não sei se estou passando algum caminho errado ou algum detalhe que esta passando, segue o diretorio onde o arquivo chega :
    10.120.142.9\Sistema_Van\BOLETO_WEB\Sacados
    e tbm segue a minha proc em Jython para que vc dê uma olhada:

    import sftp
    ftp = sftp.SFTP('ftp.10.120.142.9', 'Usuario_1', 'ftpUserVan@CscApoio')
    ftp.setmode('ASCII')
    ftp.deleteFile('Sacados/CLI_RET_ACCESSTAGE_TESTE_111229151214.TXT')
    ftp.close()

    gostaria de saber como vc poderia me ajudar nisso, desde já te agradeço , abraço

    Alan Yves

    ResponderExcluir