RemoteOff

Esse script executa o desligamento remoto (shutdown) de servidores Windows ou Linux através da execução remota de comandos via SSH. O desligamento pode ser feito em um servidor ou em todos os servidores cadastrados no arquivo de configuração.

READ-ME

RemoteOff
=========
Shutdown remoto de servidores.


SERVIDORES LINUX
================

Preparando servidores
---------------------
* Permitir que usuários não root façam shutdown

  - Adicionar o grupo shutdown:
    $ sudo groupadd shutdown

  - Adicionar usuário ao grupo shutdown:
    $ sudo usermod -a -G shutdown 

  - Configurar o 'sudo' para dar permissão aos usuários do grupo 'shutdown':
    $ sudo visudo

  - Adicionar ao final do arquivo aberto pelo 'visudo', as linhas abaixo:
    %shutdown ALL=(root) NOPASSWD: /sbin/reboot
    %shutdown ALL=(root) NOPASSWD: /sbin/poweroff
    %shutdown ALL=(root) NOPASSWD: /sbin/shutdown

  - No RedHat, comentar a linha que contém "Defaults requiretty" no mesmo arquivo.

* OBS: Para que o  faça shutdown, ele deve usar 'sudo', mas não será pedida nenhuma senha:
  $ sudo shutdown -h now


SERVIDORES WINDOWS
==================

Preparando servidores
---------------------
* Instalar servidor SSH: OpenSSH ou freeSSHd
  - freeSSHd: http://www.freesshd.com/?ctt=download         (mais simples de configurar)
  - OpenSSH:  http://sshwindows.sourceforge.net/download/   (OpenSSH portado com Cygwin mínimo)


ARQUIVO DE CONFIGURAÇÃO
=======================

* Criar ou editar o arquivo "remoteoff.conf", uma linha por servidor, com as seguintes informações:
  # IP.........: Endereço IP do servidor remoto
  # PORT.......: Número da porta do ssh no serv. remoto 
  # USER.......: Login do usuário ssh no serv. remoto
  # PASSWD.....: Senha do usuário ssh no serv. remoto
  # DELAY......: Tempo de espera em segundos antes de exec. o comando.
  # CMD........: Comando a ser executado no serv. remoto.

* Exemplo de arq. de configuração (10.0.0.1 -> Linux; 10.0.0.2 -> Windows):
  # IP           PORT  USER     PASSWD    DELAY CMD
  # ------------ ----- -------- --------- ----- -------------------
    10.0.0.1     22    user     user      0     sudo poweroff
    10.0.0.2     22    suporte  suporte   0     shutdown -s -t 0

* IMPORTANTE: chmod 700 remoteoff.conf
  ^^^^^^^^^^


EXECUTANDO SCRIPT
=================
* Para executar shutdown em todos os servidores:
  $ ./remoteoff -s all

* Para executar shutdown em um servidor somente:
  $ ./remoteoff -s 10.0.0.1

CÓDIGO

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# Programa: remoteoff
# Função: Realiza shutdown em todos os servidores.
VERSION = "1.0"
#
# Arquivo de configuração: arquivo texto contendo as seguintes 
#    informações para cada servidor, um servidor por linha.
# IP.........: Endereço IP do servidor remoto
# PORT.......: Número da porta do ssh no serv. remoto
# USER.......: Login do usuário ssh no serv. remoto
# PASSWD.....: Senha do usuário ssh no serv. remoto
# DELAY......: Tempo de espera em segundos antes de exec. o comando.
# CMD........: Comando a ser executado no serv. remoto.
#
# OBS1: SUDO deve ser configurado para executar "shutdown" ou "poweroff"
#       sem pedir senha.
#
# OBS2: Pode ser adicionado um comentário no final de cada linha
#       usando caracter "#".
#
# IMPORTANTE: chmod 700 remoteoff.conf
#
# Exemplo de arq. de configuração
## IP        PORT USER     PASSWD   DELAY CMD
## --------- ---- -------- -------- ----- -------------------
#  10.0.0.1  22   user     user     0     sudo poweroff
#  10.0.0.2  22   suporte  suporte  0     shutdown -s -t 0

import os, sys, time
import getopt
import paramiko                       # apt-get install python-paramiko

#Variáveis globais
CONF_FILE = "remoteoff.conf"          # Nome do arquivo conf
TEST = False
SERVER = None

# Para debug...
# paramiko.util.log_to_file('remoteoff.log')

def main():
   global TEST, SERVER

   #Obtem argumentos
   getArgs()
   
   #Início
   #printLogMsg("Inicio de execucao.")

   #Remove arquivos antigos
   shutdownServers(TEST, SERVER, CONF_FILE)
   
   #Fim
   #printLogMsg("Fim de execucao.")
#end main


def getArgs():
   """Obtem e faz consistência dos argumentos"""
   global TEST, SERVER

   #Captura parâmetros
   try:
      opts, args = getopt.getopt(sys.argv[1:], "hts:", \
         ["help", "test", "server="])
   except getopt.GetoptError, err:
      # Exibe ajuda e encerra:
      print str(err) # exibe algo como "option -a not recognized"
      usage()
      sys.exit(2)
   #endTry
   
   #Trata opções
   SERVER = None
   for o, a in opts:
      if o in ("-h", "--help"):
         usage()
         sys.exit()
      elif o in ("-t", "--test"):
         TEST = True
      elif o in ("-s", "--server"):
         SERVER = a
      else:
         assert False, "unhandled option"
   #endfor
   
   #Verifica argumentos
   errmsg = ""
   if (opts == []): #Se não houver parametro nenhum...
      errmsg = "missing options"
   else:
      if (SERVER == None):
         errmsg = "missing option: -s"
      #endIf
   #endIf
   if (errmsg != ""):
      print errmsg
      usage()
      sys.exit(2)
   #endIf
#endDef   


def usage():
   """Exibe help"""
   global VERSION
   print 
   print "RemonteOff v", VERSION
   print
   print "Uso: remoteoff [-h]|[[-t] -s {IP}|all]"
   print 
   print "Realiza shutdown em um ou todos servidores remotos, "
   print "conforme especificado no arquivo remoteoff.conf"
   print
   print "Opções:"
   print "-h, --help    Exibe o help de comandos."
   print "-s, --server  Endereço IP do servidor desejado ou 'all' para todos."
   print "-t, --test    Exibe os comandos que serão executados."
   print
   print "Exemplo:"
   print 'remoteoff -s all'
   print
#endDef

def shutdownServers(test, server, confFile):
   """Realiza shutdown do servidor especificado."""
   serverFound = False
   
   # Abre arquivo de configuração
   conf = os.path.dirname(sys.argv[0]) + "/" + confFile
   fconf = open(conf)
   
   # Cria objeto SSH
   ssh = paramiko.SSHClient()
   ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

   #Processa lista de servidores
   for line in fconf:
      # Linha do arquivo conf:
      # IP, PORT, USER, PASSWD, DELAY, CMD 
      ln = line.split()
      if (len(ln) > 0) and (ln[0] != "#"):
         ip    = ln[0]                   # host remoto
         dport = int(ln[1])              # porta ssh
         usr   = ln[2]                   # usuario ssh
         pwd   = ln[3]                   # senha do usuario ssh
         dly   = float(ln[4])            # retardo para execução
         cmd   = " ".join(ln[5:len(ln)]) # junta texto do comando
         cmd   = cmd[0:cmd.find("#")]    # remove comentários do final
         
         # Processa servidor da lista
         if (server == 'all') or (server == ip):
            serverFound = True
            print
            
            # Aguarda delay especificado
            if (dly > 0):
               printLogMsg("Aguardando %s seg..." % (dly))
               time.sleep(dly)
            #endIf
            
            # Executa comando
            if (test == True):
               printLogMsg("Teste: %s" % (ip))

            else:
               printLogMsg("Executando em %s: %s" % (ip, cmd))
               
               try:
                  ssh.connect(ip, port=dport, username=usr, password=pwd)
               except:
                  printLogMsg("Erro ao conectar em %s!!" % (ip))
                  continue
               #endTry
               
               try:
                  # Executa comando
                  stdin, stdout, stderr = ssh.exec_command(cmd)
               except:
                  printLogMsg("Erro ao executar comando %s" % (cmd))
                  pass
               #endTry

               # Mostra saída.
               for l in stdout.readlines():
                  print l.replace("\n", " ")
               #endFor
               
               ssh.close()
            #endIf
         #endIf
      #endIf
   #endFor

   if (serverFound == False):
      printLogMsg("Servidor %s nao configurado." % (server))
   #endIf
   fconf.close()
   print
   
#end shutdownServers   


#----- Funções Genericas -----------------------------------------------------

def printLogMsg(msg):
   """Imprime mensagem de log com data e hora correntes."""
   t = time.localtime(time.time())
   lmsg = "%02d/%02d/%d %02d:%02d - %s" % (t[2], t[1], t[0], t[3], t[4], msg)
   print lmsg
   sys.stdout.flush()
   return
#end printLogMsg


if __name__ == "__main__":
   main()

 


remoteoff.conf (exemplo)

# IP             PORT  USER      PASSWD      DELAY CMD
# -------------- ----- --------- ----------- ----- --------------------------------
 10.0.0.1        22    user      user        0     sudo poweroff
 10.0.0.2        22    suporte   suporte     0     shutdown -s -t 0

 

 

Os comentários estão desativados.