25 Mayıs 2014 Pazar

Linux\Unix sistemlerde SSH servisi üzerinden otomatik olarak komut çalıştırarak sistem yönetimi otomatik olarak gerçekleştirilebilir. Örneğin Linux sistemlerde üzerinde periyodik olarak gerçekleştirilebilecek olan işlemler bu yolla yapılarak raporlanabilir. Özellikle aynı işin gerçekleştirilmesi gereken birden fazla Linux/Unix sunucunun bulunduğu ortamlar için bu durum oldukça büyük rahatlık sağlayabilmektedir.

Python ile SSH servisi üzerinden komut çalıştırmak amaçlı kullanılan kütüphanenin adı paramikodur. Detaylı bilgi için https://github.com/paramiko/paramiko/ adresine göz atılabilir.

Kısaca paramiko kütüphanesinin sisteme kurulabilmesi için apt-get paket yönetim sistemi kullanan sistemlerde aşağıdaki adımlar takip edilebilir. 

# apt-get install pip
# pip install ecsda
# wget https://github.com/paramiko/paramiko/archive/master.zip
# unzip master.zip
# python setup.py install

Betik bir yapılandırma dosyası aracılığı ile SSH servisi üzerinden otomatik olarak komut çalıştırmaya izin vermektedir Yapılandırma dosyasının formatı ise;

Ip_Adresi:Kullanıcı Adı:Parola: Çalıştırılmak İstenen Komut;Çalıştırılmak İstenen Komut2;...

Birden fazla komutun çalıştırılması isteniyorsa eğer ; ile belirtiminin gerçekleştirilmesi gerekmektedir.

#!/usr/bin/python

"""
In order to install paramiko, follow steps below... 
# apt-get install pip
# pip install ecsda
# wget https://github.com/paramiko/paramiko/archive/master.zip
# unzip master.zip
# python setup.py install
"""

try:
        import paramiko 
        import argparse
        import sys
        import os
        import threading
        import Queue
        import time
except ImportError,e:
        import sys
        sys.stdout.write("%s\n" %e)
        sys.exit(1)



class SshClient:
    TIMEOUT = 5

    def __init__(self, host, port, username, password, passphrase = None):
        self.username = username
        self.password = password
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        self.client.connect(host, port, username = username, password = password, timeout = self.TIMEOUT)


    def execute(self, command):
        stdin, stdout, stderr = self.client.exec_command(command)
 return {'out': stdout.readlines(), 'err': stderr.readlines(), 'retval': stdout.channel.recv_exit_status()}

 
    def close(self):
        if self.client is not None:
            self.client.close()
            self.client = None


class Main:
 def __init__(self):

  description = "Kullanim Parametreleri"
         usage = "Usage: use --help for futher information"
         parser = argparse.ArgumentParser(description = description, usage = usage)
         parser.add_argument('-c','--config', dest = 'config', help = 'Configuration File', required = True)
         parser.add_argument('-t','--thread', dest = 'thread', help = 'Thread Number', required = False)
         self.args = parser.parse_args()

         if not os.path.exists(self.args.config):
                 print >> sys.stderr, "%s Doesn't Exists"% (self.args.config)
                 sys.exit(1)

  self.queue_full = True


 def execute_command(self, queue):
 
  while self.queue_full:
                        try:
                                cred_line = queue.get(False)
    ip_addr = cred_line.split(":")[0]
    user = cred_line.split(":")[1]
    passwd = cred_line.split(":")[2]
    command = cred_line.split(":")[3].split(";")

    try:
     client = SshClient(host = ip_addr, port = 22, username = user, password = passwd)
    except Exception, err:
     print >> sys.stderr, "%s : %s"% (ip_addr, str(err))
     sys.exit(1)

    try:
     for cmd in command:
      ret = client.execute(cmd)
      if ret["retval"] == 0:
       print "SUCCCESS: %s - %s : %d\n"% (ip_addr, cmd[:-1], ret["retval"])
       for line in ret["out"]:
        print line[:-1]
      else:
       print "FAIL: %s - %s : %d\n"% (ip_addr, cmd[:-1], ret["retval"])
    finally:
     client.close()  
   
                        except Queue.Empty:
                                self.queue_full = False
   

 def run(self):

  q = Queue.Queue()
  for line in open(self.args.config,"r"):
   if line[0] == "#":
    continue
   else:
    q.put(line)

  if self.args.thread is None:
   self.args.thread = 1

  for i in range(int(self.args.thread)):
   t = threading.Thread(target = self.execute_command, args = (q,))
   t.start()


##
### Main
##

if __name__ == "__main__":
 
 main = Main()
 main.run()

https://github.com/galkan/tools/blob/master/others/programming/python/run_command_via_ssh.py adresinden betiğin en güncel haline erişim sağlanabilmektedir.

Betiğin çalıştırılması için -c parametresi ile yapılandırma dosyası belirtilmelidir. -t parametresi ile kaç adet thread açılacağı bilgisi belirtilebilir. Bu parametre seçimlik olup kullanılmadığı durumda thread sayısı 1 olarak belirlenmektedir. Yapılandırma dosyası içerisinde işleme sokulması istenmeyen sunucular için satırın başında # işaretinin belirtilmesi yeterli olacaktır.

Belirtilen yapılandırma dosyası ile sistemlerdeki root kullanıcı parola bilgisi Test123 olarak güncellenmiş, paket güncellemeleri gerçekleştirilmiş ve ardından netstat komutu yardımı ile açık portların listesi alınmıştır.

# cat config.db
192.168.100.145:root:Test:echo -e "Test123\nTest123" | passwd root;netstat -nlput
192.168.100.146:root:Test:echo -e "Test123\nTest123" | passwd root;netstat -nlput
192.168.100.147:root:Test:echo -e "Test123\nTest123" | passwd root;netstat -nlput

Betik belirtilen şekilde çalıştırıldığında aşağıdaki çıktı alınmaktadır.

# ./run_command_via_ssh.py -c config.db -t 3
SUCCCESS: 192.168.100.145 - echo -e "Test123\nTest123" | passwd root : 0

SUCCCESS: 192.168.100.146 - echo -e "Test123\nTest123" | passwd root : 0

SUCCCESS: 192.168.100.145 - netstat -nlput : 0

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1072/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1072/sshd
udp        0      0 0.0.0.0:68              0.0.0.0:*                           1035/dhclient3
SUCCCESS: 192.168.100.147 - echo -e "Test123\nTest123" | passwd root : 0

SUCCCESS: 192.168.100.146 - netstat -nlput : 0

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1107/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1107/sshd
udp        0      0 0.0.0.0:68              0.0.0.0:*                           1079/dhclient3
SUCCCESS: 192.168.100.147 - netstat -nlput : 0

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1068/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1068/sshd
udp        0      0 0.0.0.0:68              0.0.0.0:*                           1046/dhclient3

Kaynaklar:
https://github.com/paramiko/paramiko/
https://github.com/galkan/tools/blob/master/others/programming/python/run_command_via_ssh.py

0 yorum :

Yorum Gönderme