jueves, 21 de octubre de 2010

Programación de scripts (parte 2)

En esta ocasión, vamos a ver cómo trabajar con instrucciones de control de flujo.

En cualquier lenguaje de programación, las instrucciones de control de flujo se encargan de evaluar el resultado de una instrucción y ejecutar el código correspondiente según dicho resultado.

Vamos a ver un ejemplo:

$ while true
> do
> echo "Bucle infinito"
> done

Al ejecutar este ejemplo voy a ver a continuación que se repite en forma infinita la cadena “Bucle infinito” hasta que ingrese la secuencia Ctrl-C. Noten que después de escribir “while true” el prompt cambia al caracter ‘>’, esto es porque hasta la instrucción “done” la instrucción esta incompleta.

Además del while contamos con otras instrucciones, las mas comunes son if, for y case.

Vamos a retomar el script del ejercicio anterior, si yo escribía mi nombre como parámetro me devuelve una cadena en la que incluye mi nombre, pero si no escribo el parámetro, simplemente no lo incluye en la cadena que devuelve, vamos a incluirle la condición de que escriba la cadena siempre y cuando el usuario haya escrito el parámetro:

#!/bin/ksh
#
# hola2
# Segunda corrección al script hola
# Revisa si por lo menos hay un parámetro
if test $# -gt 0
then
   echo Hola $1!
fi

Utilizamos la instrucción if para determinar si ejecutamos el comando echo, esto se va a decidir conforme a lo evaluado por la instrucción test. La instrucción test evalúa si la expresión dada es verdadera o no, si es verdadera, concluye con éxito, si no, lo hace con error. Una vez concluida dicha evaluación, if revisa si concluyo en forma correcta, en caso afirmativo, ejecuta todo lo que se encuentra entre la instrucción then y fi.


La instrucción if puede incluir un apartado else para ejecutar en caso de no se cumpla con la condición verdadera. Veamos el siguiente ejemplo:

#!/bin/ksh
#
# hola3
# Tercera corrección al script hola
# Revisa si por lo menos hay un parámetro
if test $# -gt 0
then
   echo "Hola $1!"
# de lo contrario
else
   echo "Escribe un parámetro"
fi

Aquí estoy utilizando else para indicarle que en el caso de que el usuario no escriba ningún parámetro escriba otra cadena solicitándolo.


Hasta ahora hemos visto como utilizar la instrucción test de una forma “canónica”, sin embargo, por lo regular se utiliza en la forma [ ], es decir, las condiciones a evaluar se encierran entre paréntesis rectangulares y ksh hace la sustitución, de esta forma nuestro código quedará más legible.


Vamos a corregir nuevamente nuestro ejemplo, por medio del if, elif y else vamos a evaluar si de mañana, tarde o noche y de acuerdo a eso haremos un saludo “mas apropiado”.

#!/bin/ksh
#
# hola4
# Cuarta corrección al script hola
# Revisa si no hay parámetros
if [ $# == 0 ]
then
        # entonces termina la ejecución
        echo "Escribe un parámetro"
        exit 1
fi
# Obtiene la hora actual entre 0 y 23
HORA=`date +%H`
# Si es entre las 3 de la madrugada y las 12 del día
if [ $HORA -gt 3 -a $HORA -lt 12 ]
then
        echo "Buenos días $1!"
# Si es entre las 12 de día y las 7 de la noche
elif [ $HORA -ge 12 -a $HORA -lt 19 ]
then
        echo "Buenas tardes $1!"
else
        echo "Buenas noches $1!"
fi

Analicemos esto:



En el primer if revisamos si el número de parámetros es igual a cero, es decir, que no se escribió ninguno, de ser cierto, escribimos un mensaje y concluimos la ejecución del script con la instrucción exit, la mejor práctica nos indica que si un script o cualquier programa en Unix concluye en forma incorrecta debe concluir con lo que se denomina “run level” diferente a cero, en este ejemplo le indicamos que concluya con 1.


Después de esto, definimos la variable HORA con la salida del comando date el cual, esta delimitado por acentos graves (`), en ksh, todo lo que se encuentra encerrado entre acentos graves se ejecuta y su salida se inserta en forma de cadena, es decir, suponiendo que son las 6 de la tarde y 3 minutos, el comando date +%H su salida es 18 el shell sustituye `date +%H` por 18 y a la variable HORA le asigna ese valor.


El script continua con un if, en el cual, se evalúa si el valor de HORA es mayor a 3 (-gt) y (-a) si es menor a 12 (-lt) en caso afirmativo da los buenos días, si no, si es mayor o igual a 12 (-ge) y (-a) menor a 19 (-lt) entonces da las buenas tardes, en caso contrario da las buenas noches, porque si no es mañana ni tarde, entonces debe ser noche.

martes, 19 de octubre de 2010

Programación de scripts (parte 1)

En un ambiente “NIX” se le llama intérprete de comandos al programa con el que regularmente llamamos a otros programas para que inicien. Este intérprete llamado “shell” es el equivalente a command.com de DOS y puede ser el Bourne Shell (sh), C-Shell (csh), Korn Shell y en sistemas modernos Borne Again Shell (bash).

Estos shell interpretan las órdenes que ingresamos por medio del teclado y nos permiten automatizar algunas tareas en la que se repiten las mismas órdenes en archivos que agrupan a éstas, estos archivos se les conoce como “scripts”.

En su forma más sencilla, un script simplemente agrupa una o mas instrucciones:

echo Hola, mundo

Para este ejemplo, vamos a crear un archivo llamado hola con el contenido anterior y lo ejecutamos de la siguiente forma:



$ sh hola
Hola, mundo


Cada shell tiene diferencias con respecto a los demás, principalmente entre sh y csh, el ksh y bash son derivados de sh, por lo que casi cualquier script escrito para este shell se puede ejecutar con los otros 2.


El sh es de todos estos el mas “viejo”, existe desde 1977 y su sintaxis es muy simple, en sistemas abiertos como Linux, en realidad el sh es una liga a otro shell, regularmente el bash.


El csh utiliza una sintaxis “inspirada” en el lenguaje C, al menos es lo que llevan años diciendo sus autores, su uso ya no es muy recomendado en la actualidad y las diferentes distros lo mantienen para mantener la compatibilidad, principalmente, de scripts ya muy viejos. Hay sistemas en los que el csh es sustituido por el más moderno tcsh.


El ksh está basado en sh, mantiene la misma sintaxis y tiene mejorías principalmente en lo que respecta a mantener un histórico de comando y la posibilidad de edición de las instrucciones.


El bash está desarrollado para mantener la compatibilidad con sh y su licencia es GNU, por lo que puede ser portado a cualquier "NIX”.


Regularmente la industria reconoce a ksh como el estándar y bash regularmente no tiene problemas para ejecutar scripts desarrollados para ksh por lo que es el que voy a utilizar para estos ejemplos.

#!/bin/ksh
#
# hola1
# Primera correccion al script hola
echo Hola $1!

En los scripts, los renglones que inician con el signo de número de consideran comentarios. Si el comentario inicia con #! el resto se considera el programa con el que se va a ejecutar el script, esta es una manera de “formalizar” al script indicando cual es el shell para el que fue desarrollado, además de que vamos a poder “forzar” su ejecución en el caso de que el usuario utilice otro shell, por estándar, el path completo del ksh es /bin/ksh. La cadena $1 representa a un parámetro que vamos a “pasar” en tiempo de ejecución. Vamos a “hacerlo” ejecutable y lo corremos de la siguiente forma:



$ chmod 755 hola1
$ ./hola1 Alejandro
Hola Alejandro!



Con el comando chmod activamos el “bit de ejecución” para todos, igual hubiera funcionado chmod +x hola1. Después de esto, lo ejecutamos con ./hola1, esto lo hice así debido a que, regularmente, el directorio actual no está incluido en el path de ejecución (variable PATH). Para los siguientes ejemplo voy a agregar el directorio al path de ejecución para evitar confusiones. Observen que después del nombre del script le dí un espacio y continuación escribí mi nombre, esta cadena es llamada parámetro.


Observen que ejecuta el echo dentro del script sustituyendo a $1 con la cadena “Alejandro”, en ksh, el signo $ al inicio de un identificador representa el valor de una variable de entorno, es decir, que al aparecer la cadena $var va a reemplazarla por el valor de la variable var. Esta variable debe estar definida previamente de la forma: var=valor, por ejemplo:



$ var1=Alejandro
$ var2=Jaramillo
$ echo $var1 $var2
Alejandro Jaramillo


Observen algo muy importante, para definir una variable no se utiliza el signo $.


Existen variables ya predefinidas, algunas son:



# Número de parámetros
1..9 Parámetro 1 al 9
? Valor devuelto por último comando ejecutado
PWD Directorio actual
PATH Path de búsqueda para ejecutables


En siguientes entradas continuaremos con este tema.

jueves, 14 de octubre de 2010

Uso de SSH (parte 2)

El SSH nos permite intercambiar archivos mediante los comandos sftp y scp, para poder usar esta funcionalidad es indispensable tener activo el sftp en el archivo de configuración del sshd normalmente llamado /etc/ssh/sshd_config. A continuación el renglón que lo activa:

Subsystem       sftp    /usr/lib/ssh/sftp-server

La forma de transferir es muy semejante al ftp y al rcp, a continuación muestro un ejemplo de cómo usar el sftp:

hajarami@ubuntu:~$ sftp solaris10
Connecting to solaris10...
sftp> put httpd-2.2.16.tar.gz
Uploading httpd-2.2.16.tar.gz to /export/home/hajarami/httpd-2.2.16.tar.gz
httpd-2.2.16.tar.gz                             100% 6220KB 345.5KB/s   00:18
sftp> quit

Como observarán es muy similar su uso al ftp normal se suben archivos con put y se bajan con get.

El scp es prácticamente igual al rcp:

hajarami@ubuntu:~$ scp php-5.3.3.tar.gz solaris10:/export/home/hajarami
php-5.3.3.tar.gz                                 100%   13MB 647.4KB/s   00:21

La sintaxis se resumen como “scp [servidor1:][path1/]archivo1 [servidor2:]path2[/archivo2]”. En el ejemplo estamos transfiriendo el archivo php-5.3.3.tar.gz local al servidor solaris10 en el path /export/home/hajarami.

Observarán que es muy sencillo su uso y la ventaja de esto es que no existe el riesgo de que alguien pudiera “interceptar” nuestro archivo.

miércoles, 13 de octubre de 2010

Uso de SSH (parte 1)

Tradicionalmente utilizamos telnet para iniciar una sesión en nuestro servidor, sin embargo, este protocolo no cuenta con ningún tipo de seguridad, por lo que basta conectar un analizador de protocolo a la red para averiguar lo que se escribe desde una IP determinada, es por eso que se recomienda utilizar en su lugar el SSH, el cual, esta cifrado y permite iniciar sesiones e intercambiar archivos.

Una de las ventajas de SSH es que permite el uso de llaves públicas para iniciar la sesión sin necesidad de ingresar contraseña siendo, de esta forma, un buen sustituto para el rsh.

Vamos a crear primero una llave RSA para nuestro usuario con el comando ssh-keygen:

hajarami@ubuntu:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to. save the key (/home/hajarami/.ssh/id_rsa):
Created directory '/home/hajarami/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/hajarami/.ssh/id_rsa.
Your public key has been saved in /home/hajarami/.ssh/id_rsa.pub.
The key fingerprint is:
27:99:0b:f0:bd:98:b9:54:c9:b8:c6:47:08:15:96:ba hajarami@ubuntu
The key's randomart image is:
+--[ RSA 2048]----+
|      +o         |
|     o.          |
|    o.           |
|    .+ = +       |
|     .= S .      |
|    E. O =       |
|      O +        |
|     o o         |
|      .          |
+-----------------+

Esta llave esta compuesta por dos partes la pública y la privada, la privada es el archivo $HOME/.ssh/id_rsa y debe permanecer siempre ahí con solo permisos para el propietario.

Revisamos el contenido de la llave pública:

hajarami@ubuntu:~$ cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAv53P81IpkhJPzzzZ7xygmWq1ynTeJ3ut/XetJPX4fENmo/c1nQlG+tsNzsuAV6OBFa2KI0YT9avxkDOFA+1SaO8dqslo0wF46/CCKyFmUn2NMHlA69NyBKiL2cLxvTXq6fBj3+f9jVijv4df/9NoBpup7uIETJt0MlYVsSbidR1FMdzNO91mcCZkrgQ9rxH4N9geI9KMUEXSfuouhmY0Z8GQUZSIB1f5djub1NfT10F6riPW7njF7HMRHlAIb8EKaGBcgK0LCEFP1OVc9uSLOWIzbz2slvze5Dly31d6O4Rb+T0LeTPL+7FavEaCeUM7lW+WVIs+sGemsEL+h2VQ8Q== hajarami@ubuntu

Esta llave se la vamos a proporcionar al propietario de la cuenta a la que necesitamos entrar para que nos “autorice” el acceso.

En el otro servidor, en el home directory del usuario con el que vamos a iniciar sesión vamos a agregar la llave pública en el archivo $HOME/.ssh/authorized_keys:

[solaris10:~]$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAv53P81IpkhJPzzzZ7xygmWq1ynTeJ3ut/XetJPX4fENmo/c1nQlG+tsNzsuAV6OBFa2KI0YT9avxkDOFA+1SaO8dqslo0wF46/CCKyFmUn2NMHlA69NyBKiL2cLxvTXq6fBj3+f9jVijv4df/9NoBpup7uIETJt0MlYVsSbidR1FMdzNO91mcCZkrgQ9rxH4N9geI9KMUEXSfuouhmY0Z8GQUZSIB1f5djub1NfT10F6riPW7njF7HMRHlAIb8EKaGBcgK0LCEFP1OVc9uSLOWIzbz2slvze5Dly31d6O4Rb+T0LeTPL+7FavEaCeUM7lW+WVIs+sGemsEL+h2VQ8Q== hajarami@ubuntu" >> $HOME/.ssh/authorized_keys

Y listo, ya tenemos autorización para iniciar sesión, desde nuestro servidor origen:

hajarami@ubuntu:~$ ssh hajarami@solaris10
The authenticity of host 'solaris10 (192.168.188.138)' can't be established.
RSA key fingerprint is 88:4d:ff:4c:67:17:46:20:14:9c:3b:7f:1c:5b:f9:c5.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'solaris10,192.168.188.138' (RSA) to the list of known hosts.
Last login: Wed Oct 13 20:13:24 2010 from 192.168.188.1
Sun Microsystems Inc.   SunOS 5.10      Generic January 2005
You have mail.
[solaris10:~]$

La primera vez que entramos a un servidor, nos hace la advertencia de que no lo tiene en la lista de servidores conocidos, por lo que nos pide una confirmación, esto es importante ya que, en el caso de que hubiera un reemplazo del servidor la llave del servidor no correspondería y nos devolvería un error, lo normal es que simplemente inicie sesión sin mayor aviso. En la invocación del comando ssh le indicamos el login del usuario del otro servidor, el caracter arroba y el nombre del servidor o su dirección; si el login del usuario remoto es igual al local, no es necesario escribirlo, basta con el nombre del servidor.

Además de iniciar iniciar sesión es posible ejecutar en forma remota un comando de una forma similar a la del comando rsh:

hajarami@ubuntu:~$ ssh hajarami@solaris10 uname -a
SunOS solaris10 5.10 Generic_142901-12 i86pc i386 i86pc

Regularmente es muy sencillo, no es necesario crear una llave para el usuario remoto, en caso de problemas, se puede ejecutar el ssh con el parámetro –v para que muestre mensajes de “cómo va”.

Mañana les muestro cómo utilizar el ssh para enviar y recibir archivos.

Oracle anuncia el retiro de SunSolve

Si son usuarios de SunSolve como yo, seguramente ya recibieron o están por recibir la notificación de que se retira el sitio de Soporte Sun conocido como SunSolve.

Esto cómo lo debemos interpretar, yo no me considero fanático del software libre, de hecho, cuando me inicié en Solaris era un sistema cerrado, eso sí, con esquemas de licenciamiento mas “accesibles” que otros sistemas tales como HP-UX y AIX por mencionar algunos. Poco a poco, Sun fue “abriendo” a Solaris en un muy evidente intento de competir contra Linux (RedHat, SuSE) hasta que iniciaron el proyecto OpenSolaris con la licencia CDDL, fue entonces que esta plataforma se presentaba como una alternativa a Linux.

Desde que Oracle anunció la adquisición de Sun, al menos todos los administradores que conozco y yo mismo nos negamos a referirnos a “Oracle” como fabricante del sistema, probablemente en nuestras mentes ya aparecía como una visión lo que Oracle a revelado a lo largo de este año, su intención de convertir a Solaris en un producto similar a su Oracle Database, completamente cerrado, con esquemas de licenciamiento francamente voraces que ya no se conforman con el tipo de plataforma, el número de servidores y hasta el número de procesadores, sino que se van hasta el nivel de “cores” de procesador. Por lo que en mi opinión Solaris ya no puede ser una opción viable para pymes.

En fin mis amigos, tendremos que continuar y esta es una de las razones por las que escribo en este blog, debemos permanecer unidos como expertos en Unix para intercambiar nuestros conocimientos, por lo que espero poder seguir aportando aunque sea un “granito de arroz”.

martes, 12 de octubre de 2010

Uso del módulo SSL en Apache HTTP Server

Actualmente es considerado normal el realizar operaciones a través de internet en las que se intercambian datos de todo tipo, sin embargo, el protocolo http por si mismo no ofrece ningún tipo de blindaje ya que es posible obtener la información simplemente monitoreando las comunicaciones, por lo que es indispensable proteger los sitios en los que se ingresan datos mediante el uso del protocolo https, el cual, utiliza TLS/SSL para encriptar la comunicación, además de que se recurre a un certificado emitido por un CA para evitar el robo de identidad.

Para esta práctica requerimos un servidor Apache 2 con el módulo SSL activo, previamente vimos cómo instalarlo.

Lo primero que vamos a hacer es crear un certificado para pruebas empleando el OpenSSL, en un directorio vacío creamos los subdirectorios demoCA, demoCA/newcerts y demoCA/private:

mkdir demoCA
mkdir demoCA/newcerts
mkdir demoCA/private

También creamos el archivo vacío demoCA/index.txt y el archivo demoCA/serial con la cadena “01”:

touch demoCA/index.txt
echo 01 > demoCA/serial

Ahora creamos un certificado x509 autofirmado:

openssl genrsa -out demoCA/private/cakey.pem 1024
Generating RSA private key, 1024 bit long modulus
.........................++++++
...................++++++
e is 65537 (0x10001)
openssl req -new -key demoCA/private/cakey.pem -out demoCA/cacert.pem -x509
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:MX
State or Province Name (full name) [Some-State]:Queretaro
Locality Name (eg, city) []:Queretaro
Organization Name (eg, company) [Internet Widgits Pty Ltd]:unixymas
Organizational Unit Name (eg, section) []:unixymas
Common Name (eg, YOUR name) []:unixymas
Email Address []:webmaster@unixymas.com.mx

Ahora estamos listos para firmar una solicitud, vamos a crear una:

openssl genrsa -out key.pem 1024
Generating RSA private key, 1024 bit long modulus
.........++++++
..........................................++++++
e is 65537 (0x10001)
openssl req -new -key key.pem -out req.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:MX
State or Province Name (full name) [Some-State]:Queretaro
Locality Name (eg, city) []:Queretaro
Organization Name (eg, company) [Internet Widgits Pty Ltd]:unixymas
Organizational Unit Name (eg, section) []:unixymas
Common Name (eg, YOUR name) []:ubuntu.unixymas.com.mx
Email Address []:webmaster@unixymas.com.mx

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Observen que en “common name” escribí el nombre del sitio. Tal cual, esta solicitud podemos enviarla a un CA para adquirir un certificado, pero en este ejemplo vamos a firmarlo nosotros mismos:

openssl ca -in req.pem -key key.pem -out cert.pem
Using configuration from /usr/lib/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Oct 13 02:39:21 2010 GMT
            Not After : Oct 13 02:39:21 2011 GMT
        Subject:
            countryName               = MX
            stateOrProvinceName       = Queretaro
            organizationName          = unixymas
            organizationalUnitName    = unixymas
            commonName                = ubuntu.unixymas.com.mx
            emailAddress              = webmaster@unixymas.com.mx
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                8F:E6:90:EE:92:EA:C4:B7:FA:5D:EF:AC:ED:26:5D:6E:C9:BD:81:FE
            X509v3 Authority Key Identifier:
                keyid:DD:63:E9:44:86:7B:7B:E3:85:43:31:C2:6C:4D:A7:B0:7B:5C:4D:C9

Certificate is to be certified until Oct 13 02:39:21 2011 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Listo, ahora vamos a instalar este certificado en nuestro servidor, nos pasamos al directorio conf dentro del Apache, en mi caso, /usr/local/apache2/conf, y editamos el archivo httpd.conf, localizamos la línea #Include conf/extra/httpd-ssl.conf y le retiramos el signo de número, lo salvamos y copiamos el archivo certificado a server.crt y la llave a server.key:

cp cert.pem /usr/local/apache2/conf/server.crt
cp key.pem /usr/local/apache2/conf/server.key

Es muy importante que el archivo server.key tenga solo los atributos 600:

chmod 600 /usr/local/apache2/conf/server.key

Y listo, podemos probar desde un browser con la url: https://sitio

image

Es lógico que al principio presente errores por la falta de un certificado firmado por un CA reconocido, simplemente agregamos la excepción y listo.

image

jueves, 7 de octubre de 2010

Introducción al uso de contenedores en Solaris 10 (zonas)

Solaris 10 permite la virtualización por medio de contenedores también llamados zonas. Cada uno de estos contenedores actúa como un servidor Solaris (ó Linux) autónomo, para lo cual, el sistema comparte recursos e inclusive puede reservarlos para el uso exclusivo de determinados contenedores, en este ejercicio vamos a ver una forma básica de cómo crear un equipo virtual y cómo trabajar con él.

Pará qué nos sirve una máquina virtual, se preguntaran algunos, un escenario podría ser que necesitemos correr varias instancias de una aplicación pequeña (un servidor web, por ejemplo) y no vale la pena tener varias máquinas pequeñas para esto. Otro que se me ocurre en para implementar un esquema DRP, en el cual, en caso de un desastre, se movería solo el contenedor a otro equipo.

Para una instalación muy básica necesitamos no menos de 700Mb de espacio en disco y una dirección IP libre y válida para la NIC que vamos a utilizar. Si solo tenemos una conexión a red esa NIC funciona perfectamente, el contenedor va a dar de alta una dirección virtual en ese caso.

En mi caso voy a utilizar el filesystem /export/home y la IP que voy a utilizar es la 192.168.188.34 para la NIC e1000g0.

La instalación se realiza en dos etapas, la primera es crear la configuración de la zona y la segunda es su instalación, iniciamos entonces la creación de la configuración de la siguiente forma:

# zonecfg -z zona1
zona1: No such zone configured
Use 'create' to begin configuring a new zone.
zonecfg:zona1> create
zonecfg:zona1> set zonepath=/export/home/zonas/zona1
zonecfg:zona1> add net
zonecfg:zona1:net> set address=192.168.188.34
zonecfg:zona1:net> set physical=e1000g0
zonecfg:zona1:net> set defrouter=192.168.188.2
zonecfg:zona1:net> end
zonecfg:zona1> commit
zonecfg:zona1> exit

Al comando zonecfg se le indica el nombre de la zona con el parámetro –z, el nombre que elegí fue zona1, entramos al modo interactivo y lo primero que nos indica es que la zona es “nueva” y debemos darle el comando create. Después de esto con set zonepath=/export/home/zonas/zona1 le indico directorio en el que va a estar físicamente los datos de la zona, podría decirse que este directorio va a tener la función de disco duro virtual. A continuación le indicamos que dé de alta una interfaz de red virtual con add net; con set address=192.168.188.34 le indicamos la dirección IP que va a utilizar; con set physical=e1000g0 la NIC real que va a utilizar, si ya existen una dirección IP configurada, va a dar de alta la de la zona como virtual; con set defrouter=192.168,188.2 le indico la IP del gateway; salimos de la configuración de red con end y con commit le decimos que guarde la configuración, finalmente salimos con exit.

Ahora instalamos la zona:

# zoneadm -z zona1 install
Preparing to install zone <zona1>.
Creating list of files to copy from the global zone.
Copying <8783> files to the zone.
Initializing zone product registry.
Determining zone package initialization order.
Preparing to initialize <1244> packages on the zone.
Initialized <1244> packages on zone.
Zone <zona1> is initialized.
The file </export/home/zonas/zona1/root/var/sadm/system/logs/install_log> contains a log of the zone installation.

Este comando tarda en procesar algunos minutos. Ya concluido, estamos listos para “bootear” a nuestro contenedor, primero vamos a “loguearnos” en la consola del contenedor:

# zlogin -C zona1
[Connected to zone 'zona1' console]

Desde otra sesión iniciamos el “booteo” del contenedor:

# zoneadm -z zona1 boot

Vamos a observar como inicia el proceso de inicio de sistema en la consola:

[NOTICE: Zone booting up]

SunOS Release 5.10 Version Generic_142901-12 64-bit
Copyright 1983-2010 Sun Microsystems, Inc.  All rights reserved.
Use is subject to license terms.
Hostname: zona1
Loading smf(5) service descriptions:  31/153

Select a Language

  0. English
  1. es
  2. fr

Please make a choice (0 - 2), or press h or ? for help:

Como es la primera vez que “bootea” requiere lo configuremos como si se tratara de un servidor recién instalado, entre otras cosas, nos va a pedir un nombre, la configuración regional, el dns y concluido esto, va a reiniciar en forma nomal:

System identification is completed.

rebooting system due to change(s) in /etc/default/init

[NOTICE: Zone rebooting]

SunOS Release 5.10 Version Generic_142901-12 64-bit
Copyright 1983-2010 Sun Microsystems, Inc.  All rights reserved.
Use is subject to license terms.
Hostname: zona1
Reading ZFS config: done.

zona1 console login:

Puedo salir de la consola escribiendo ~.

Listo, ya tenemos un contenedor corriendo, podemos entrar a él con zlogin o directamente por medio de su IP con ssh o con telnet (inclusive con XDMCP).

Este es el contenedor más básico que podemos crear, es posible indicarle filesystems, asociarlos con pools zfs, utilizar recursos dedicados al contenedor, etc. Inclusive en el caso de Solaris 10 en SPARC, se pueden utilizar contenedores Solaris 8 y 9, en Solaris 10 en x86 se pueden crear contenedores Linux (SUSE, RedHat y CentOS).

martes, 5 de octubre de 2010

Activar el uso de sesiones gráficas remotas en Solaris 10 (XDMCP)

Esta es la forma de permitir el uso de sesiones gráficas remotas a un servidor Solaris 10 que fue instalado dándole “si” a la opción de cerrar servicios remotos.

En un servidor así, solo se permite el inicio de sesiones gráficas desde la consola, pero si es necesario el poder iniciar sesión desde otras estaciones de trabajo, lo que debemos hacer es activar al administrador de sesiones para que permita la conexión remota.

Esta sesión remota se logra mediante el protocolo XDMCP, el cual, utiliza el puerto 177 UDP, este servicio lo proporciona el cde-login, por lo que vamos a realizar una modificación en este servicio utilizando el comando svccfg:

svccfg -s cde-login

Al ejecutar este comando vamos a entrar a “una consola” que nos permitirá modificar los atributos del servicio, ejecutamos lo siguiente:

svc:/application/graphical-login/cde-login> setprop dtlogin/args = astring: ""
svc:/application/graphical-login/cde-login> end

Después, le indicamos al servicio que vuelva a “leer” sus atributos y que reinicie:

svcadm refresh cde-login
svcadm restart cde-login

Por último, vamos a activar el servidor de fuentes, el cual, es necesario para algunos servidores X.

svcadm enable xfs

image

lunes, 4 de octubre de 2010

Crear un volumen con LVM en Linux

El LVM se ha convertido en el administrador de volúmenes más popular en las distros Linux debido a que nos facilita mucho tareas como extender el tamaño de los volúmenes, concatenar discos y todo esto con una licencia GNU, por lo que el ahorro en licencias de software privativo (por ejemplo: Veritas Storage Foundation) es muy significativo, lamentablemente no cuenta con una forma de definir arreglos RAID, por lo que en un ambiente de alta disponibilidad, se recomienda el uso de arreglos físicos.

Para este ejemplo voy a cambiar de distro y voy a ocupar Fedora 13, voy a empezar con agregar un disco nuevo, el cual, fue reconocido por el sistema con el dispositivo /dev/sdb (noten que en Linux, el uso de dispositivo “raw” no aplica, solo por bloques).

El LVM se compone de tres capas, el volumen físico (PV), el cuál, es una partición o un disco completo cedido al LVM; el grupo de volúmes (VG), es una agrupación de uno o más PV’s, y finalmente, el volumen lógico (LV), es una parte de un VG que contiene un filesystem o forma parte del swap.

Voy a crear un PV utilizando el total del disco nuevo:

pvcreate /dev/sdb
  Physical volume "/dev/sdb" successfully created

Ahora el VG:

vgcreate vg_appl /dev/sdb
  Volume group "vg_appl" successfully created

Y continuamos con el LV:

[root@fedora ~]# lvcreate -n apache -L 10G vg_appl
  Logical volume "apache" created

Ya que tenemos listo nuestro LV, (para el cuál, creó el dispositivo /dev/vg_appl/apache) vamos a crearle un filesystem, voy a crearlo tipo ext4 que es el que utiliza por default esta distro:

mkfs.ext4 /dev/vg_appl/apache
mke2fs 1.41.10 (10-Feb-2009)
Etiqueta del sistema de ficheros=
Tipo de SO: Linux
Tamaño del bloque=4096 (bitácora=2)
Tamaño del fragmento=4096 (bitácora=2)
Stride=0 blocks, Stripe width=0 blocks
655360 nodos-i, 2621440 bloques
131072 bloques (5.00%) reservados para el superusuario
Primer bloque de datos=0
Número máximo de bloques del sistema de ficheros=2684354560
80 bloque de grupos
32768 bloques por grupo, 32768 fragmentos por grupo
8192 nodos-i por grupo
Respaldo del superbloque guardado en los bloques:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Escribiendo las tablas de nodos-i: hecho
Creating journal (32768 blocks): hecho
Escribiendo superbloques y la información contable del sistema de ficheros: hecho

Este sistema de ficheros se revisará automáticamente cada 38 montajes o
180 días, lo que suceda primero.  Utilice tune2fs -c o -i para cambiarlo.

En mi caso, no necesito que le dé un fsck cada 38 montajes, por lo que voy a seguir la recomendación y voy a cambiarlo:

tune2fs -c -1 -i 0 /dev/vg_appl/apache
tune2fs 1.41.10 (10-Feb-2009)
Se pone la cuenta de montajes máxima a -1
Se pone el intervalo entre revisiones en 0 segundos

Lo monto:

mkdir /apache
mount -t ext4 /dev/vg_appl/apache /apache

Reviso que este correcto:

df -h
S.ficheros            Size  Used Avail Use% Montado en
/dev/mapper/vg_fedora-lv_root
                      2.9G  747M  2.2G  26% /
tmpfs                 502M  208K  502M   1% /dev/shm
/dev/sda1             291M   60M  217M  22% /boot
/dev/mapper/vg_fedora-lv_home
                      2.9G  1.1G  1.8G  37% /home
/dev/mapper/vg_fedora-lv_opt
                      2.0G  930M  954M  50% /opt
/dev/mapper/vg_fedora-lv_usr
                      3.9G  2.8G  922M  76% /usr
/dev/mapper/vg_fedora-lv_var
                      2.0G  320M  1.6G  17% /var
/dev/mapper/vg_appl-apache
                      9.9G  151M  9.2G   2% /apache

Observen que el dispositivo asociado a mi filesystem es un mapa, el cual, vamos a utilizarlo para definir en el archivo /etc/fstab a este filesystem para que lo monte en forma automática. Agregamos la siguiente línea:

/dev/mapper/vg_appl-apache      /apache ext4    defaults        1 2

Y listo, tenemos un nuevo filesystem sobre LVM.

Una ventaja de utilizar un filesystem ext3 o ext4 para este volumen es que es posible extender su tamaño si se requiere alguna vez, también se puede reducir, pero esto no es recomendado ya que puede haber perdida de datos, suponiendo que queremos crecer el filesystem a 15Gb.

lvextend -L +5G -r /dev/vg_appl/apache
fsck from util-linux-ng 2.17.2
e2fsck 1.41.10 (10-Feb-2009)
/dev/mapper/vg_appl-apache está montado.

¡¡ATENCIÓN!!  Ejecutar e2fsck en un sistema de ficheros montado
puede causar GRAVES daños al sistema de ficheros.

¿De verdad quiere continuar? (s/n)? si

/dev/mapper/vg_appl-apache: recuperando el fichero de transacciones
/dev/mapper/vg_appl-apache: limpio, 11/655360 ficheros, 79663/2621440 bloques
  Extending logical volume apache to 15.00 GiB
  Logical volume apache successfully resized
resize2fs 1.41.10 (10-Feb-2009)
Filesystem at /dev/dm-2 is mounted on /apache; on-line resizing required
old desc_blocks = 1, new_desc_blocks = 1
Performing an on-line resize of /dev/dm-2 to 3932160 (4k) blocks.
El sistema de ficheros en /dev/dm-2 tiene ahora 3932160 bloques.

domingo, 3 de octubre de 2010

Migración de sistema basado en UFS a ZFS en Solaris 10

En la entrada anterior vimos a grandes rasgos, cómo crear un ZFS y mencioné algunas de sus ventajas con respecto al tradicional UFS. En esta ocasión vamos a ver cómo migrar nuestro sistema montado sobre UFS a ZFS.

Para esto requiero un disco libre, en el cual, voy a crear el pool que va a contener el sistema, en mi caso, estoy utilizando Solaris 10 en x86, por lo que debo inicializar el disco con fdisk:

fdisk c1t1d0p0
No fdisk table exists. The default partition for the disk is:

  a 100% "SOLARIS System" partition

Type "y" to accept the default partition,  otherwise type "n" to edit the
partition table.
y

Creo una partición:

format
Searching for disks...done

AVAILABLE DISK SELECTIONS:
       0. c1t0d0 <DEFAULT cyl 2607 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@0,0
       1. c1t1d0 <DEFAULT cyl 2607 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@1,0
Specify disk (enter its number): 1
selecting c1t1d0
[disk formatted]

FORMAT MENU:
        disk       - select a disk
        type       - select (define) a disk type
        partition  - select (define) a partition table
        current    - describe the current disk
        format     - format and analyze the disk
        fdisk      - run the fdisk program
        repair     - repair a defective sector
        label      - write label to the disk
        analyze    - surface analysis
        defect     - defect list management
        backup     - search for backup labels
        verify     - read and display labels
        save       - save new disk/partition definitions
        inquiry    - show vendor, product and revision
        volname    - set 8-character volume name
        !<cmd>     - execute <cmd>, then return
        quit
format> p

PARTITION MENU:
        0      - change `0' partition
        1      - change `1' partition
        2      - change `2' partition
        3      - change `3' partition
        4      - change `4' partition
        5      - change `5' partition
        6      - change `6' partition
        7      - change `7' partition
        select - select a predefined table
        modify - modify a predefined partition table
        name   - name the current table
        print  - display the current table
        label  - write partition map and label to the disk
        !<cmd> - execute <cmd>, then return
        quit
partition> p
Current partition table (original):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       0               0         (0/0/0)           0
  1 unassigned    wm       0               0         (0/0/0)           0
  2     backup    wu       0 - 2606       19.97GB    (2607/0/0) 41881455
  3 unassigned    wm       0               0         (0/0/0)           0
  4 unassigned    wm       0               0         (0/0/0)           0
  5 unassigned    wm       0               0         (0/0/0)           0
  6 unassigned    wm       0               0         (0/0/0)           0
  7 unassigned    wm       0               0         (0/0/0)           0
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition> 0
Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       0               0         (0/0/0)           0

Enter partition id tag[unassigned]:
Enter partition permission flags[wm]:
Enter new starting cyl[0]: 1
Enter partition size[0b, 0c, 1e, 0.00mb, 0.00gb]: 2606e
partition> p
Current partition table (unnamed):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       1 - 2606       19.96GB    (2606/0/0) 41865390
  1 unassigned    wm       0               0         (0/0/0)           0
  2     backup    wu       0 - 2606       19.97GB    (2607/0/0) 41881455
  3 unassigned    wm       0               0         (0/0/0)           0
  4 unassigned    wm       0               0         (0/0/0)           0
  5 unassigned    wm       0               0         (0/0/0)           0
  6 unassigned    wm       0               0         (0/0/0)           0
  7 unassigned    wm       0               0         (0/0/0)           0
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition> label
Ready to label disk, continue? y

partition> q

FORMAT MENU:
        disk       - select a disk
        type       - select (define) a disk type
        partition  - select (define) a partition table
        current    - describe the current disk
        format     - format and analyze the disk
        fdisk      - run the fdisk program
        repair     - repair a defective sector
        label      - write label to the disk
        analyze    - surface analysis
        defect     - defect list management
        backup     - search for backup labels
        verify     - read and display labels
        save       - save new disk/partition definitions
        inquiry    - show vendor, product and revision
        volname    - set 8-character volume name
        !<cmd>     - execute <cmd>, then return
        quit
format> q

Como va a contener el sistema operativo debo hacerlo booteable:

fdisk -b /usr/lib/fs/ufs/mboot /dev/rdsk/c1t1d0p0
             Total disk size is 2610 cylinders
             Cylinder size is 16065 (512 byte) blocks

                                               Cylinders
      Partition   Status    Type          Start   End   Length    %
      =========   ======    ============  =====   ===   ======   ===
          1       Active    Solaris2          1  2609    2609    100

SELECT ONE OF THE FOLLOWING:
   1. Create a partition
   2. Specify the active partition
   3. Delete a partition
   4. Change between Solaris and Solaris2 Partition IDs
   5. Exit (update disk configuration and exit)
   6. Cancel (exit without updating disk configuration)
Enter Selection: 5

installgrub /boot/grub/stage1 /boot/grub/stage2 /dev/rdsk/c1t1d0s0
stage1 written to partition 0 sector 0 (abs 16065)
stage2 written to partition 0, 272 sectors starting at 50 (abs 16115)

Creamos el pool:

zpool create rpool c1t1d0s0

Ahora vamos a utilizar el Live Upgrade para iniciar esta migración, lo primero es crear un ambiente de booteo (Boot Environment) utilizando el comando lucreate:

lucreate -c BE_ufs_1009 -n BE_zfs_1009 -p rpool

Estos parámetros indican lo siguiente:

  • -c BE_ufs_1009: Es una identificación con la que vamos a nombrar el ambiente actual, es completamente a discreción. Para esta denominación en particular, estoy utilizando una muy común, BE es por boot environment, ufs por el sistema de archivo actual y 1009 por el release de Solaris.
  • -n BE_zfs_1009: Es la identificación del nuevo ambiente.
  • -p rpool: El pool que va a contener el nuevo ambiente.

Lo ejecutamos, van a aparecer algunos errores y advertencias que tienen que ver con el hecho de que es la primera vez que estamos definiendo ambiente de booteo.

Una vez concluido este proceso, revisamos los ambientes de booteo con lustatus:

lustatus
Boot Environment           Is       Active Active    Can    Copy
Name                       Complete Now    On Reboot Delete Status
-------------------------- -------- ------ --------- ------ ----------
BE_ufs_1009                yes      yes    yes       no     -
BE_zfs_1009                yes      no     no        yes    -

Observen que el ambiente zfs aparece como completo, es muy importante que tenga este estatus. Ahora vamos a activar el nuevo ambiente con luactivate:

luactivate BE_zfs_1009
Generating boot-sign, partition and slice information for PBE <BE_ufs_1009>
A Live Upgrade Sync operation will be performed on startup of boot environment <BE_zfs_1009>.

Generating boot-sign for ABE <BE_zfs_1009>
NOTE: File </etc/bootsign> not found in top level dataset for BE <BE_zfs_1009>
Generating partition and slice information for ABE <BE_zfs_1009>
Boot menu exists.
Generating multiboot menu entries for PBE.
Generating multiboot menu entries for ABE.
Disabling splashimage
Re-enabling splashimage
No more bootadm entries. Deletion of bootadm entries is complete.
GRUB menu default setting is unaffected
Done eliding bootadm entries.

**********************************************************************

The target boot environment has been activated. It will be used when you
reboot. NOTE: You MUST NOT USE the reboot, halt, or uadmin commands. You
MUST USE either the init or the shutdown command when you reboot. If you
do not use either init or shutdown, the system will not boot using the
target BE.

**********************************************************************

In case of a failure while booting to the target BE, the following process
needs to be followed to fallback to the currently working boot environment:

1. Boot from the Solaris failsafe or boot in Single User mode from Solaris
Install CD or Network.

2. Mount the Parent boot environment root slice to some directory (like
/mnt). You can use the following command to mount:

     mount -Fufs /dev/dsk/c1t0d0s0 /mnt

3. Run <luactivate> utility with out any arguments from the Parent boot
environment root slice, as shown below:

     /mnt/sbin/luactivate

4. luactivate, activates the previous working boot environment and
indicates the result.

5. Exit Single User mode and reboot the machine.

**********************************************************************

Modifying boot archive service
Propagating findroot GRUB for menu conversion.
File </etc/lu/installgrub.findroot> propagation successful
File </etc/lu/stage1.findroot> propagation successful
File </etc/lu/stage2.findroot> propagation successful
File </etc/lu/GRUB_capability> propagation successful
Deleting stale GRUB loader from all BEs.
File </etc/lu/installgrub.latest> deletion successful
File </etc/lu/stage1.latest> deletion successful
File </etc/lu/stage2.latest> deletion successful
Activation of boot environment <BE_zfs_1009> successful.

Aparecen otros errores y advertencias e incluside nos da indicaciones de qué hacer en caso de falla, reiniciamos el sistema operativo:

shutdown -i6 -g0 –y

En el menú del GRUB elegimos la opción que corresponde a nuestro ambiente de booteo y de no ocurrir ningún error deberá iniciar el sistema operativo en forma correcta. Si observamos a los filesystem montados observamos lo siguiente:

df -h
Filesystem             size   used  avail capacity  Mounted on
rpool/ROOT/BE_zfs_1009
                        20G   4.1G    13G    24%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.3G   348K   2.3G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/usr/lib/libc/libc_hwcap1.so.1
                        17G   4.1G    13G    24%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
swap                   2.3G    40K   2.3G     1%    /tmp
swap                   2.3G    24K   2.3G     1%    /var/run
/dev/dsk/c1t0d0s5      2.9G   3.0M   2.9G     1%    /export/home
rpool                   20G    35K    13G     1%    /rpool
rpool/ROOT              20G    21K    13G     1%    /rpool/ROOT

Sólo aparece /export/home en UFS, lo migramos en forma manual:

umount /export/home
rmdir /export/home
zfs create -o mountpoint=/export/home rpool/home
cd /export/home
ufsdump 0cf - /dev/dsk/c1t0d0s5 | ufsrestore rf -

Eliminamos del vfstab la línea que corresponde al /export/home y listo, ya podemos eliminar el ambiente de booteo anterior:

ludelete -f BE_ufs_1009

Nuevamente reiniciamos sistema operativo y comprobamos que inicie sin problemas.

Con esto queda como concluida la migración a ZFS, aprovechando que me queda un disco duro libre, voy a “espejear” mi sistema, es muy sencillo, por medio del comando format, borro todas las particiones del disco que quedo libre (disco 0) y creo una con todo el espacio disponible, después, la agrego al pool de datos:

zpool attach -f rpool c1t1d0s0 c1t0d0s0

Y como punto final, reinstalamos el grub en c1t0d0s0:

installgrub /boot/grub/stage1 /boot/grub/stage2 /dev/rdsk/c1t0d0s0

Podemos monitorear el progreso de sincronización con zpool status:

zpool status
  pool: rpool
state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
scrub: resilver in progress for 0h4m, 48.94% done, 0h4m to go
config:

        NAME          STATE     READ WRITE CKSUM
        rpool         ONLINE       0     0     0
          mirror      ONLINE       0     0     0
            c1t1d0s0  ONLINE       0     0     0
            c1t0d0s0  ONLINE       0     0     0  2.23G resilvered

errors: No known data errors

jueves, 30 de septiembre de 2010

Introducción al uso de ZFS en Solaris

Desde que hizo su aparición Solaris 10, se presentó con un gran número de avances con respecto a sus versiones anteriores, por ejemplo: el DTrace, la virtualización por medio de contenedores, la sustitución del rc por svc, etc. En esta ocasión vamos a mostrar como trabajar con una de estas nuevas características: el ZFS.

El ZFS es un nuevo tipo de filesystem, combina una serie de tecnologías de almacenamiento en una forma automatizada y simple, solo basta crear un pool de datos y crear en este filesystems, los cuales son montados en forma automática sin necesidad de darlos de alta en la tabla de montaje (/etc/vfstab).

Para este ejercicio, voy a utilizar un equipo con Solaris 10 x86 instalado y un disco duro nuevo sin utilizar.

Recordemos que en la plataforma x86 es necesario inicializar todos los discos duros nuevos:

fdisk /dev/rdsk/c1t1d0p0
No fdisk table exists. The default partition for the disk is:

  a 100% "SOLARIS System" partition

Type "y" to accept the default partition,  otherwise type "n" to edit the
partition table.
y

Ahora vamos a crear una partición nueva que ocupe todo el espacio disponible:

format
Searching for disks...done

AVAILABLE DISK SELECTIONS:
       0. c1t0d0 <DEFAULT cyl 2607 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@0,0
       1. c1t1d0 <DEFAULT cyl 2607 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@1,0
Specify disk (enter its number): 1
selecting c1t1d0
[disk formatted]

FORMAT MENU:
        disk       - select a disk
        type       - select (define) a disk type
        partition  - select (define) a partition table
        current    - describe the current disk
        format     - format and analyze the disk
        fdisk      - run the fdisk program
        repair     - repair a defective sector
        label      - write label to the disk
        analyze    - surface analysis
        defect     - defect list management
        backup     - search for backup labels
        verify     - read and display labels
        save       - save new disk/partition definitions
        inquiry    - show vendor, product and revision
        volname    - set 8-character volume name
        !<cmd>     - execute <cmd>, then return
        quit
format> p

PARTITION MENU:
        0      - change `0' partition
        1      - change `1' partition
        2      - change `2' partition
        3      - change `3' partition
        4      - change `4' partition
        5      - change `5' partition
        6      - change `6' partition
        7      - change `7' partition
        select - select a predefined table
        modify - modify a predefined partition table
        name   - name the current table
        print  - display the current table
        label  - write partition map and label to the disk
        !<cmd> - execute <cmd>, then return
        quit
partition>
p
Current partition table (original):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       0               0         (0/0/0)           0
  1 unassigned    wm       0               0         (0/0/0)           0
  2     backup    wu       0 - 2606       19.97GB    (2607/0/0) 41881455
  3 unassigned    wm       0               0         (0/0/0)           0
  4 unassigned    wm       0               0         (0/0/0)           0
  5 unassigned    wm       0               0         (0/0/0)           0
  6 unassigned    wm       0               0         (0/0/0)           0
  7 unassigned    wm       0               0         (0/0/0)           0
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition> 0
Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       0               0         (0/0/0)           0

Enter partition id tag[unassigned]:
Enter partition permission flags[wm]:
Enter new starting cyl[0]: 1
Enter partition size[0b, 0c, 1e, 0.00mb, 0.00gb]: 2606e
partition>
p
Current partition table (unnamed):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       1 - 2606       19.96GB    (2606/0/0) 41865390
  1 unassigned    wm       0               0         (0/0/0)           0
  2     backup    wu       0 - 2606       19.97GB    (2607/0/0) 41881455
  3 unassigned    wm       0               0         (0/0/0)           0
  4 unassigned    wm       0               0         (0/0/0)           0
  5 unassigned    wm       0               0         (0/0/0)           0
  6 unassigned    wm       0               0         (0/0/0)           0
  7 unassigned    wm       0               0         (0/0/0)           0
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition> label
Ready to label disk, continue? y

partition>

Ahora que nuestro disco esta listo para trabajar, vamos a crear un pool de datos:

zpool create pool1 c1t1d0s0

Y ya estamos listos para crear filesystems, suponiendo que necesite uno que se monte en la ruta /tomcat, por ejemplo:

zfs create -o mountpoint=/tomcat pool1/tomcat

Con este comando estamos indicando que creé el nuevo filesystem “tomcat” utilizando el pool de datos llamado “pool1”, adicionalmente, le estamos indicando que utilice como punto de montaje la ruta /tomcat, si nosotros no indicamos un punto de montaje, en este caso lo hubiera montado por default en /pool1/tomcat. Ahora, vamos a utilizar el comando df para revisar como están nuestros filesystem:

df -h
Filesystem             size   used  avail capacity  Mounted on
/dev/dsk/c1t0d0s0      2.9G   464M   2.4G    16%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.5G   940K   2.5G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/dev/dsk/c1t0d0s4      5.8G   2.9G   2.8G    51%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       5.8G   2.9G   2.8G    51%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
/dev/dsk/c1t0d0s3      2.9G    73M   2.8G     3%    /var
swap                   2.5G    40K   2.5G     1%    /tmp
swap                   2.5G    24K   2.5G     1%    /var/run
/dev/dsk/c1t0d0s6      2.9G   484M   2.4G    17%    /opt
/dev/dsk/c1t0d0s5      2.9G   3.0M   2.9G     1%    /export/home
pool1                   20G    21K    20G     1%    /pool1
pool1/tomcat            20G    21K    20G     1%    /tomcat

Observen que aparecen 2 nuevos filesystem pool1 y pool1/tomcat, pool1 representa al filesystem “raíz” del pool, sobre el se crean el resto de los ZFS.

Vamos a ver qué ocurre si creo otro filesystem:

zfs create -o mountpoint=/postgresql pool1/postgresql
df -h
Filesystem             size   used  avail capacity  Mounted on
/dev/dsk/c1t0d0s0      2.9G   464M   2.4G    16%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.5G   940K   2.5G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/dev/dsk/c1t0d0s4      5.8G   2.9G   2.8G    51%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       5.8G   2.9G   2.8G    51%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
/dev/dsk/c1t0d0s3      2.9G    73M   2.8G     3%    /var
swap                   2.5G    40K   2.5G     1%    /tmp
swap                   2.5G    24K   2.5G     1%    /var/run
/dev/dsk/c1t0d0s6      2.9G   484M   2.4G    17%    /opt
/dev/dsk/c1t0d0s5      2.9G   3.0M   2.9G     1%    /export/home
pool1                   20G    21K    20G     1%    /pool1
pool1/tomcat            20G    21K    20G     1%    /tomcat
pool1/postgresql        20G    21K    20G     1%    /postgresql

Como podrán notar, todos los ZFS de este pool aparecen con el mismo número de espacio disponible (20Gb), esto es porque todos los ZFS de un mismo pool comparten el espacio disponible en el pool de datos, aunque cada uno de ellos mantiene su información independiente con respectos a los demás ZFS, es decir, los datos entre cada filesystem permanecen separados y conforme van aumentando del tamaño el pool les asigna más espacio.

Con esto se reduce la necesidad de reasignar espacios, lo cuál es un problema clásico en la administración de cualquier servidor: si mantengo la información en un solo filesystem se complica la administración del sistema operativo ya que una actualización implica modificar todo, si separo los filesystem, corro el riesgo de que alguno crezca mas allá de lo estimado y deba reorganizarlos.

Otro aspecto es que no tuve la necesidad de utilizar el mkfs para crear el filesystem, ni tampoco tuve que montarlo con el comando mount, todo esto se realizó de forma automática.

Si reiniciamos el servidor, podremos observar que los zfs se montan automáticamente y no tuvimos que darlos de “alta” en la tabla de montaje.

En siguientes entregas voy a explicar como migrar de un esquema de booteo UFS normal a uno ZFS y como hacer el mirroring.