dijous, 18 de febrer del 2021

Automatització de tasques d'administració del SO amb Python: introducció

Les tasques repetitives en l'administració de sistemes són habituals, com ara controls de error del sistema de fitxers o còpies de seguretat; la automatització de les tasques d'administració de sistemes informàtics consisteix en usar programari per crear instruccions i processos que reemplacen o redueixen la tasca manual dels administradors amb els sistemes. Es pot aplicar automatització a qualsevol tasca de la infraestructura informàtica, des de el sistema operatiu, passant per la xarxa fins la implementació de dominis de xarxa local o sistemes al  núvol.

La automatització es sol realitzar usant llenguatges d'script com ara en el cas de Linux amb el llenguatge propi del shell, o en el cas de Windows, amb el llenguatge Powershell. El llenguatge del shell de Linux és potent, no obstant això, a mesura que les tasques es tornen més complexes, els scripts de l'intèrpret d'ordres poden ser més difícils de mantenir. En el cas de Powershell és un llenguatge modern amb centenars de instruccions i llibreries. Podem utilitzar Python en lloc del shell script per a l’automatització. Python proporciona la mateixa funcionalitat que els scripts de l'intèrpret d'ordres però d’una manera més estructurada i escalable; a més a més Python s'executa també en Windows.

Les operacions bàsiques que es solen fer des del shell són:

  • Lectura de fitxers de configuració
  • Matar /crear processos
  • Creació / supressió de fitxers i directoris
  • Iniciar /aturar aplicacions
  • Gestió de fitxers

Els scripts de shell sovint gestionen també recursos de xarxa,  és a dir accedeixen a recursos mitjançant curl i wget

Mòdul os ()

Proporciona accés a les funcions d'alt nivell del SO; per carregar-la:

jordi@jordi-sve1513c5e:~$ python3
Python 3.8.5 (default, Jul 28 2020, 12:59:40)  
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>>

Les funcions que proporciona el mòdul estan en la ajuda oficial. Veiem alguns exemples d'ús. 

1. Python permet executar immediatament una ordre qualsevol del shell mitjançant la funció os.system(). Exemple d'ús:

jordi@jordi-sve1513c5e:~$ python3
Python 3.8.5 (default, Jul 28 2020, 12:59:40)  
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system("ls -l -d")
drwxr-xr-x 37 jordi fisics 4096 de febr. 17 09:01 .

2. Llistar directoris:

>>> llista = os.listdir()
>>> for directori in llista:
...  print(directori)
... 

3. Veure la ruta d'un fitxer

>>> os.path.abspath('prova.txt')
'/home/jordi/prova.txt'
>>>

4. Separar cada directori de la ruta actual en cadenes de text separades:

>>> os.getcwd()
'/home/jordi/Documents/Feina'
>>> os.path.split(os.getcwd())
('/home/jordi/Documents', 'Feina')
>>>

5. Comprovar si existeix una carpeta:

>>> os.path.exists('/home/jordi/DAM')        
False

6. Accedir a les variables d'entorn:

>>> os.environ['HOME']
'/home/jordi'
>>> os.environ['USER']
'jordi'
>>>


NOTA: Com ja s'ha dit una de les avantatges de Python és que funciona tant en Windows con en Linux (i també en altres SO), així, l'exemple anterior en Windows només canviaria en el nom de les variables d'entorn, la imatge següent ho mostra en un Windows 8:



7. Obrir i llegir fitxers de text

Les funcions os.accessopen i read ens permeten comprovar si un fitxer existeix (per exemple un fitxer de configuració), obrir-lo i mostrar-lo per pantalla, per exemple.

>>> if os.access("prova", os.R_OK):
...  with open("prova") as f:       
...   l = f.read()
...   print(l)
...  
hola
adeu

Fixem-nos amb l´ús de la funció os.acces, obre el fitxer prova amb al paràmetre mode d'accés os.R_OK que serveix per comprovar si el fitxer és llegible. Per exemple si tenim aquest dos fitxers:

jordi@jordi-sve1513c5e:~$ sudo ls -l prova*
-r-------- 1 root  fisics   10 de febr. 18 11:08 prova
-rw-r--r-- 1 jordi fisics   13 de des.  12 11:40 prova.txt

Llavors el primer fitxer només serà llegit si executem Python com a root. Ampliem el codi de l'exemple, usant aquest cop un editor de text, incloent una lectura del nom del fitxer (funció input) i un missatge si no es pot accedir:

import os
print("fitxer a llegir?")
fitxer = input()
if os.access(fitxer, os.R_OK):
   with open(fitxer) as f:
        l = f.read()
        print(l)
   print("fitxer comprovat i llegit") 
else:
   print("fitxer sense accés de lectura")


I l'executem amb els dos fitxers, sense accés de root:

jordi@jordi-sve1513c5e:~/Documents/Feina/M6 2020/UF2$ python3 llegir_fitxer.py  
fitxer a llegir?
prova
fitxer sense accés de lectura
jordi@jordi-sve1513c5e:~/Documents/Feina/M6 2020/UF2$ python3 llegir_fitxer.py  
fitxer a llegir?
prova.txt
hola que tal

fitxer comprovat i llegit
jordi@jordi-sve1513c5e:~/Documents/Feina/M6 2020/UF2$


8. Escriure en un fitxer

Per escriure a un fitxer existent, heu d'afegir un paràmetre a la funció open ():

"a" - Afegeix - s'afegirà al final del fitxer

"w" - Escriu - sobreescriurà qualsevol contingut existent

Exemple: per afegir una ruta a la variable d'entorn $PATH podem fer:

jordi@jordi-sve1513c5e:~$ PATH="$HOME/Imatges:$PATH"    
jordi@jordi-sve1513c5e:~$ echo $PATH
/home/jordi/Imatges:/home/jordi/.local/bin:/home/jordi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/
sbin:/bin:/usr/games:/usr/local/games:/snap/bin
jordi@jordi-sve1513c5e:~$

El contingut de $PATH s'inicialitza quan l'usuari obre sessió al llegir-se el fiter ocult .profile; escrivim un script que afegeixi una ruta qualsevol a la variable $PATH dintre del fitxer de perfil de l'usuari.

import os
print("ruta a afegir al PATH?, ha de ser una subcarpeta del directori HOME de l'usuari actiu")
ruta = input()
path = "$HOME/" + ruta + ":" + os.environ['PATH']
fitxer = ".profile"
if os.access(fitxer, os.W_OK):
   with open(fitxer,"a") as f:
        f.write("PATH=" + path +'\n')
        f.close()
   print("PATH actualitzat!") 
else:
   print("fitxer sense accés de lectura")

Fixeu-vos en l'ús de l'operador "+" per unir cadenes de text, i també en el caràcter especial "\n" que representa un salt de línia. El provem:

jordi@jordi-sve1513c5e:~$ python3 ./Documents/Feina/M6\ 2020/UF2/modificar_profile.py            
ruta a afegir al PATH?, ha de ser una subcarpeta del directori HOME de l'usuari actiu
Documents/Feina/M6 2020 
PATH actualitzat!

Per comprovar que realment està modificat mirem el contingut del .profile:

# set PATH so it includes user's private bin if it exists 
if [ -d "$HOME/.local/bin" ] ; then
   PATH="$HOME/.local/bin:$PATH"
fi
PATH=$HOME/Documents/Feina/M6 2020:/home/jordi/Imatges:/home/jordi/.local/bin:/home/jordi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin


S'ha afegit correctament el nou camí a la variable PATH dins del fitxer de configuració del perfil.

Teniu tutorials de gestió bàsica de fitxers en la w3school

Automatització: introducció

Ara que tenim un mínim de nocions de Python aplicat a la gestió del sistema de fitxers, podem fer una primera incursió en la automatització de la administració del sistema operatiu. Un script senzill que pot ser de certa utilitat és l'script buscar_en_passwd_i_afegir.py, en la versió 1.0:

import os
fitxer = "/etc/passwd"
acabat = False                          # variable booleana
while not acabat:
 print ("usuari a buscar en el sistema?")
 user = input()
 if not user: break
 èxit = False                         # variable booleana
 if os.access(fitxer, os.R_OK):
    with open(fitxer) as f:
        tot = f.read()                # llegeix tot el fitxer de cop
        trobat =  (user in tot)         # cerca en tota el string, hi és?
        if trobat:
            print("usuari trobat")     # no cal afegir l'usuari, ja existeix
            èxit = True  
    f.close()
 if not èxit:                            # no existeix, afegir-lo
   print("no hi és, afegint-lo...")
   os.system("sudo useradd " + user)    # passem ordres al shell
   os.system("sudo passwd -e " + user)
   print ("Fet!")
   
L'script, el que fa és anar preguntant repetidament un nom d'usuari que buscarà en  /etc/passwd, si el troba ho indica, i si no el troba crea un usuari amb el nom donat, deixant la contrasenya nul·la de forma que quan el nou usuari entri per primer cop li demanarà que l'escrigui, això ho aconseguim usant os.system que recordem crida comandaments del shell directament. La repetició es trenca quan introduïm un nom sense contingut. Si el provem:

 jordi@jordi-sve1513c5e:~$ python3 ./Documents/Feina/M6\ 2020/UF2/buscar_en_passwd_i_afegir.py  
usuari a buscar en el sistema?
jordic 
usuari trobat
usuari a buscar en el sistema?
jordi
usuari trobat
usuari a buscar en el sistema?
PereElMagnífic 
no hi és, afegint-lo...
passwd: password expiry information changed.
Fet!
usuari a buscar en el sistema?

jordi@jordi-sve1513c5e:~$

Si no estem com a root, la instrucció sudo farà que l'escript s'aturi per tal de que el shell ens pregunti la contrasenya de root. 

EXERCICIS PROPOSATS

Exercici 1. Modifiqueu l'exemple de l'apartat 8 per tal de que afegeixi la instrucció umask 011 al final del fitxer .profile. Proveu-lo.

Exercici 2. Escriu un script buscar_en_profile.py Python que demani una paraula i la busqui en cada línia del fitxer .profile; per cada línia que trobi, escriu un missatge i mostra la línia. En acabar, si no ha trobat cap línia, mostra el missatge "no hi és". Exemple d'execució:

jordi@jordi-sve1513c5e:~$ python3 ./Documents/Feina/M6\ 2020/UF2/buscar_en_profile.py  
paraula a buscar en .profile?
umask
trobada a la línia: '# the default umask is set in /etc/profile; for setting the umask
'
trobada a la línia: '# for ssh logins, install and configure the libpam-umask package.
'
trobada a la línia: '#umask 022
'
trobada a la línia: 'umask 011'


Ajudes: per llegir línia a línia useu la funció readline() en comptes de la read (aquesta llegeix tot el fitxer de cop), per buscar una paraula en una línia de text useu la sentència in (veure exemple en el tutorial de Python en w3schools), serà útil que us acostumeu a usar variables i constants lògiques True / False. Us caldrà també una estructura repetitiva per recórrer totes les línies del fitxer, com a suggerència, podeu usar aquesta:

while (True):
        línia = fitxer.readline()
            ( . . .resta de línies del programa on fem coses amb la línia)
        if not línea:
            break

La instrucció break força a sortir de la repetició iniciada amb while, i com hem usat com a condició del while la constant True, equival a dir: comença sempre a llegir, si veus que no hi ha res per llegir (sentència if not línea ) llavors trenca (break) la repetició. 
  

Exercici 3. Com es podria modificar l'script buscar_en_passwd_i_afegir.py, per tal de que en comptes de preguntar cada usuari a afegir, llegeixi aquests usuaris d'un fitxer de text que li passem com a paràmetre?. L'script ha de comprovar que tal fitxer és accessible per lectura.  


Cap comentari:

Publica un comentari a l'entrada

Gestió d'usuaris i grups en Linux

Usuaris i grups Linux  Els comptes de Linux són com els comptes de Windows o MacOS; però els detalls no, així que cal explicar alguns detall...