Agilizando la Infraestructura III: oVirt 3.4 con glusterFS

En esta entrada voy a explicar como he instalado un entorno de virtualización basado en oVirt 3.4 y utilizando como almacenamiento compartido volúmenes de glusterFS. oVirt requiere de un nodo de control y varios nodos de computación. La arquitectura viene a ser bastante similar a la que podríamos tener con VMware vSphere. He instalado el motor de gestión en un servidor físico con 2 CPU y 1 GB de RAM. Si bien los requisitos son mucho mayores, para la demo que he preparado va bastante bien aunque le puede llegar a faltar algo de fluidez.

Instalación de oVirt

La instalación, como en todos los productos en los que Red Hat está por detras, se realiza desde un RPM. Se instala primero un rpm que nos configurará los repositorios oficiales de ovirt y a continuación se instala el paquete ovirt-engine:

[root@ovirt ~]# yum install http://plain.resources.ovirt.org/pub/yum-repo/ovirt-release34.rpm
[root@ovirt ~]# yum -y install ovirt-engine

 Una vez instalado se lanza la configuración donde deberemos responder algunas preguntas:

[root@ovirt ~]# engine-setup
[ INFO ] Stage: Initializing
[ INFO ] Stage: Environment setup
Configuration files: [‘/etc/ovirt-engine-setup.conf.d/10-packaging.conf’]
Log file: /var/log/ovirt-engine/setup/ovirt-engine-setup-20140704130518-cgito9.log
Version: otopi-1.2.1 (otopi-1.2.1-1.el6)
[ INFO ] Stage: Environment packages setup
[ INFO ] Yum Downloading: repomdSYOvZitmp.xml (0%)
[ INFO ] Stage: Programs detection
[ INFO ] Stage: Environment setup
[ INFO ] Stage: Environment customization

–== PRODUCT OPTIONS ==–


–== PACKAGES ==–

[ INFO ] Checking for product updates…
[ INFO ] No product updates found

–== NETWORK CONFIGURATION ==–

Host fully qualified DNS name of this server [ovirt.enterprise.com]:
Setup can automatically configure the firewall on this system.
Note: automatic configuration of the firewall may overwrite current settings.
Do you want Setup to configure the firewall? (Yes, No) [Yes]: yes
The following firewall managers were detected on this system: iptables Firewall manager to configure (iptables): iptables
[ INFO ] iptables will be configured as firewall manager.

–== DATABASE CONFIGURATION ==–

Where is the Engine database located? (Local, Remote) [Local]:
Setup can configure the local postgresql server automatically for the engine to run. This may conflict with existing applications.
Would you like Setup to automatically configure postgresql and create Engine database, or prefer to perform that manually? (Automatic, Manual) [Automatic]:

–== OVIRT ENGINE CONFIGURATION ==–

Application mode (Both, Virt, Gluster) [Both]:
Default storage type: (NFS, FC, ISCSI, POSIXFS, GLUSTERFS) [NFS]: GLUSTERFS
Engine admin password:
Confirm engine admin password:
–== PKI CONFIGURATION ==–

Organization name for certificate [enterprise.com]:

–== APACHE CONFIGURATION ==–

Setup can configure apache to use SSL using a certificate issued from the internal CA.
Do you wish Setup to configure that, or prefer to perform that manually? (Automatic, Manual) [Automatic]:
Setup can configure the default page of the web server to present the application home page. This may conflict with existing applications.
Do you wish to set the application as the default page of the web server? (Yes, No) [Yes]:

–== SYSTEM CONFIGURATION ==–

Configure WebSocket Proxy on this machine? (Yes, No) [Yes]:
Configure an NFS share on this server to be used as an ISO Domain? (Yes, No) [Yes]:
Local ISO domain path [/var/lib/exports/iso]:
Local ISO domain ACL [0.0.0.0/0.0.0.0(rw)]:
Local ISO domain name [ISO_DOMAIN]:

–== MISC CONFIGURATION ==–


–== END OF CONFIGURATION ==–

[ INFO ] Stage: Setup validation
–== CONFIGURATION PREVIEW ==–

Engine database name : engine
Engine database secured connection : False
Engine database host : localhost
Engine database user name : engine
Engine database host name validation : False
Engine database port : 5432
NFS setup : True
PKI organization : enterprise.com
Application mode : both
Firewall manager : iptables
Update Firewall : True
Configure WebSocket Proxy : True
Host FQDN : ovirt.enterprise.com
NFS export ACL : 0.0.0.0/0.0.0.0(rw)
NFS mount point : /var/lib/exports/iso
Datacenter storage type : glusterfs
Configure local Engine database : True
Set application as default page : True
Configure Apache SSL : True

Please confirm installation settings (OK, Cancel) [OK]:
[ INFO ] Stage: Transaction setup
[ INFO ] Stopping engine service
[ INFO ] Stopping websocket-proxy service
[ INFO ] Stage: Misc configuration
[ INFO ] Stage: Package installation
[ INFO ] Stage: Misc configuration
[ INFO ] Initializing PostgreSQL
[ INFO ] Creating PostgreSQL ‘engine’ database
[ INFO ] Configuring PostgreSQL
[ INFO ] Creating Engine database schema
[ INFO ] Creating CA
[ INFO ] Configuring WebSocket Proxy
[ INFO ] Generating post install configuration file ‘/etc/ovirt-engine-setup.conf.d/20-setup-ovirt-post.conf’
[ INFO ] Stage: Transaction commit
[ INFO ] Stage: Closing up

–== SUMMARY ==–SSH fingerprint: 83:1F:BB:B9:DC:7B:94:D3:41:38:67:AC:33:E9:58:AE Internal CA 7E:BE:5C:B7:34:DD:E3:EB:2D:44:18:1B:E4:B8:3B:BE:33:BB:99:14 Web access is enabled at:
http://ovirt.enterprise.com:80/ovirt-engine https://ovirt.enterprise.com:443/ovirt-engine
Please use the user “admin” and password specified in order to login

–== END OF SUMMARY ==–

[ INFO ] Starting engine service
[ INFO ] Restarting httpd
[ INFO ] Restarting nfs services
[ INFO ] Stage: Clean up
Log file is located at /var/log/ovirt-engine/setup/ovirt-engine-setup-20140704130518-cgito9.log
[ INFO ] Generating answer file ‘/var/lib/ovirt-engine/setup/answers/20140704131454-setup.conf’
[ INFO ] Stage: Pre-termination
[ INFO ] Stage: Termination


[ INFO ] Execution of setup completed successfully

Con las pocas preguntas que hemos respondido ya nos instala todo lo necesario y nos habilita el acceso a la consola web. También nos ha configurado un repositorio de imágenes ISO que mas adelante mostraré como usar y terminar de configurar.

Interfaz web

Si accedemos a la URL que nos ha devuelto el proceso de configuración veremos que nos ha habilitado varios portales, entre ellos el de administración:

Accedemos al portal y lo primero que haremos será añadir dos hosts al cluster. Para crear los hosts existen dos opciones:

  • utilizar una imagen desde la web de oVirt con la que se instala el sistema operativo y todo lo necesario
  • utilizar un sistema operativo ya preinstalado al que se le instalará el software necesario al agregarlo al cluster.

En mi caso ya disponia de dos servidores instalados con lo que los he añadido al cluster. Previamente he configurado los repositorios de oVirt al igual que hice para instalar el motor. A continuación desde la interfaz web añadomos el host e introduciremos los datos del usuario root para que pueda instalar el software:

En la parte inferior podemos ver los eventos y tareas que se están ejecutando. En el se puede ver que se está ejecutando YUM en los servidores para instalar el software de oVirt.

Almacenamiento

Una vez instalado los nodos sobre los que correrán las máquinas virtuales es necesario la configuración de un almacenamiento compartido. He elegido GlusterFS por las bondades de HA y performance que tiene. GlusterFS lo configuro sobre dos servidores adicionales, aunque bien podría instalarse en los mismos servidores donde van a correr las máquinas virtuales.

La instalacioń es secilla:

[root@storage01 ~]# yum install -y glusterfs glusterfs-fuse glusterfs-server

Una vez instalado se configuran los pares y ya se puede crear un volumen e iniciarlo:

[root@storage01 ~]# gluster peer probe storage02
peer probe: success.[root@storage01 ~]# gluster peer status
Number of Peers: 1

Hostname: storage02
Uuid: 3e4056d0-2ab0-4e83-b273-ceb565b7458c
State: Peer in Cluster (Connected)
[root@storage01 #]# gluster volume create DATA replica 2 transport tcp storage01:/opt/gluster/data storage02:/opt/gluster/data
volume create: DATA: success: please start the volume to access data
[root@storage01 ~]# gluster volume start DATA


volume start: DATA: success  

He creado un volúmen con dos réplicas, de forma que si perdemos una de las dos no habría pérdida de datos. Para poder utilizarlo en oVirt se deben realizar algunas modificaciones:

[root@storage01 ~]# gluster volume set DATA allow-insecure on[root@storage01 ~]# gluster volume set DATA server.allow-insecure on
[root@storage01 ~]# gluster volume set DATA storage.owner-uid=36
[root@storage01 ~]# chown 36:36 /opt/gluster/data
[root@storage01 ~]# gluster volume info

Volume Name: DATA
Type: Replicate
Volume ID: 6361b068-7601-4903-88c4-5cdc50f28236
Status: Started
Number of Bricks: 1 x 2 = 2
Transport-type: tcp
Bricks:
Brick1: storage01:/opt/gluster/data
Brick2: storage02:/opt/gluster/data
Options Reconfigured:
server.allow-insecure: on


storage.owner-uid: 36

También se debe modificar el fichero /etc/glusterfs/glusterd.vol añadiendo la opción rcp-auth-allow-insecure:

[root@storage01 ~]# vi /etc/glusterfs/glusterd.volvolume management
type mgmt/glusterd
option working-directory /var/lib/glusterd
option transport-type socket,rdma
option transport.socket.keepalive-time 10
option transport.socket.keepalive-interval 2
option transport.socket.read-fail-log off
# option base-port 49152
option rpc-auth-allow-insecure on


end-volume

Una vez realizado estos cambios se debe reiniciar el demonio en los nodos:

[root@storage01 ~]# service glusterd restart
Starting glusterd: [ OK ]

Por último, en los Hosts de oVirt es necesario instalar el paquete vdsm-gluster para que puedan montar los volúmenes:

[root@compute01 ~]# sudo yum install vdsm-gluster

Con todo ya configurado se puede crear el dominio de almacenamiento y mapear el volúmen que hemos creado anteriormente:

Ya está todo preparado para poder empezar a crear máquinas virtuales. En la siguiente entrada explicaré como crear el repositorio de imágenes y como integrar oVirt con Foreman.

Agilizando la Infraestructura II: Despliegue de sistemas con Foreman

Ya vimos en la entrada anterior cómo instalar y configurar Foreman para poder realizar despliegues de una manera desatendida. Veamos a continuación como se despliega un sistema.

En la pantalla principal de Foreman accederemos al menú Hosts y seleccionaremos New host.  


Nos aparecerá un wizard muy sencillo donde especificaremos algunos datos, como la MAC de la interfaz de red configurada para arrancar el servidor. También le indicaremos el “host group” y el entorno que le queremos asignar.  Esto nos permitirá aplicar al servidor unas clases de Puppet u otras.
Como se puede ver, también se puede indicar qué tipo de despliegue se quiere hacer, en este caso Bare Metal, para instalar un servidor físico, pero podríamos integrar Foreman con Openstack o con oVirt por ejemplo, y nos serviría para desplegar instancias virtuales.

 En la pestaña de Network especificaremos la MAC de la interfaz de red así como la dirección IP que queremos asignarle al servidor. En cualquier caso nos sugerirá una IP del rango DHCP que hayamos configurado, pero siempre podremos cambiarla:

En la pestaña Operating System indicamos el sistema operativo a instalar, el repositorio que debe utilizar, la tabla de partición que le queramos aplicar y finalmente la password del usuario root.

 Podemos darle ya al botón Submit para que quede configurado el servidor. En el próximo reinicio el servidor arrancará por red (si no arranca verificar la configuración de la BIOS) e iniciará la instalación del sistema operativo:

 

 A medida que vayamos instalando servidores se irán añadiendo a la lista de servidores y se le irán aplicando las clases que hayamos configurado al Host Group asignado:

En próximas entradas veremos cómo integrarlo con oVirt.

Agilizando la infraestructura I: Provisioning

Estoy evaluando soluciones para poder modernizar la infraestructura que manejamos actualmente. La tendencia es ir a un modelo IaaS, pero tampoco se puede pasar de un modelo tradicional (de principio de siglo) a un IaaS completo en unos meses.

Lo primero que planteo es el tema del aprovisionamiento de servidores, ya sean físicos o virtuales. Hasta ahora veníamos utilizando herramientas de Oracle, puesto que la mayoría de los servidores que administrábamos eran Solaris. Pero últimamente empezamos a tener cada vez mas servidores linux y el uso de estas herramientas de Oracle es muy tedioso.

Entre las herramientas que he encontrado, la que mas me ha gustado y con la que he empezado a hacer pruebas es Foreman. Foreman se trata de una herramienta Open Source que utiliza puppet para gestionar el ciclo de vida de los servidores y ademas esta soportada por Red Hat, con lo que se garantiza que el proyecto tiene la suficiente calidad como para integrarlo en un entorno empresarial.

Instalación de Foreman
La instalación, como siempre que se utilizan repositorios, no puede ser mas sencilla. Se añaden los repositorios del proyecto (y el EPEL en caso de no tenerlo ya) y en este caso se instala el programa que se encargará de la configuración:

[root@foreman ~]# yum -y install http://yum.theforeman.org/releases/1.5/el6/x86_64/foreman-release.rpm
[root@foreman ~]# yum -y install http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
[root@foreman ~]# yum -y install foreman-installer

Como nota, en la web de Foreman recomiendan instalarlo en un servidor que disponga de la versión Open Source de puppet, puesto que al parecer es incompatible con la versión Enterprise.

El instalador se puede lanzar de varias formas, a mi me gusta el modo interactivo. Una de las cosas que hay que tocar el el tipo de Base de Datos. Por defecto es Postgres, pero si mas adelante se quiere integrar Foreman con Packstack será necesario pasar a una base de datos MySQL, con lo que yo lo cambio antes de empezar.

    [root@foreman ~]# foreman-installer -i
    Welcome to the Foreman installer!
    ———————————

    This wizard will gather all required information. You can change any parameter
    to your needs.

    Ready to start? (y/n)
    y
    Main Config Menu
    1. [✓] Configure foreman_plugin_templates
    2. [✓] Configure foreman_proxy
    3. [✓] Configure foreman_plugin_puppetdb
    4. [✓] Configure foreman_compute_openstack
    5. [✓] Configure foreman_plugin_discovery
    6. [✓] Configure foreman_plugin_default_hostgroup
    7. [✗] Configure foreman_plugin_chef
    8. [✓] Configure foreman_plugin_bootdisk
    9. [✗] Configure foreman_compute_rackspace
    10. [✗] Configure foreman_plugin_hooks
    11. [✓] Configure foreman #para cambiar el tipo de BBDD
    12. [✗] Configure foreman_compute_vmware
    13. [✓] Configure foreman_compute_ovirt
    14. [✓] Configure foreman_plugin_setup
    15. [✗] Configure foreman_compute_gce
    16. [✗] Configure foreman_compute_ec2
    17. [✓] Configure puppet
    18. [✓] Configure foreman_compute_libvirt
    19. Display current config
    20. Save and run
    21. Cancel run without Saving
    Choose an option from the menu… 20

El instalador empieza a ejecutar varios módulos de puppet e instala y configura todo lo necesario. En unos minutos tenemos nuestro servidor de foreman preparado:

    Installing — /etc/httpd/conf/httpd.confhed2014-03-20 11:17:58 [38%] [……………………….. Installing — /etc/sysconfig/foremanig/fore2014-06-18 11:00:08.000 [99%] [………………………………………………………………Installing Done [100%] […………………………………………………………………]
    Success!
    * Foreman is running at https://foreman.globalia.com
    Default credentials are ‘admin:changeme’
    * Foreman Proxy is running at https://foreman.globalia.com:8443
    * Puppetmaster is running at port 8140
    The full log is at /var/log/foreman-installer/foreman-installer.log

Configuración del provisioning

Para configurar el provisoning existe un wizard donde se especifican el origen del software y la configuración básica de red. Se accede a través del menú Infrastructure/Provisioning setup:

En el primer paso indicamos sobre que segmento de red se va a hacer el autoprovisioning:

A continuación varios datos sobre la red:

​En el paso 3 nos indicará que ejecutemos de nuevo el instalador de Foreman adaptado a nuestra configuración. Nos dará dos opciones, si queremos utilizar DHCP o no:

​En el cuarto paso se selecciona el origen de los medios de instalación. Se pueden utilizar los repositorios públicos, pero es recomendable utilizar un repositorio local para acelerar el proceso de instalación:

​En el último paso ya podemos lanzar la creación de nuevos servidores, pero antes es necesario configurar algunas cosas mas.

Creación del repositorio:
Lo mas sencillo para crear un repositorio local es utilizar los DVD de instalación, en este caso de CentOS 6.5. Se copian los rpm a la carpeta que contendrá nuestro repositorio:

[root@foreman ~]# cd /opt/jgp/
[root@foreman jgp]# mkdir -p repo/centos/6.5/x86_64/repodata
[root@foreman jgp]# cp -a /media/DVD/dvd1/Packages/*.rpm repo/centos/6.5/x86_64/
[root@foreman jgp]# cp -a /media/DVD/dvd2/Packages/*.rpm repo/centos/6.5/x86_64/

Se copian las imágenes de inicio y el xml también al repositorio:

[root@foreman jgp]# cd repo/centos/6.5/x86_64/
[root@foreman x86_64]# cp -r /media/DVD/dvd1/images .
[root@foreman x86_64]# cp /media/DVD/dvd1/repodata/*comps*.xml repodata/comps.xml

A continuación se instala el paquete createrepo y se genera de nuevo el xml:

[root@foreman centos6.5]# yum install createrepo
[root@foreman centos6.5]# createrepo -g repodata/comps.xml .
Spawning worker 0 with 6367 pkgs
Workers Finished
Gathering worker results

Saving Primary metadata
Saving file lists metadata
Saving other metadata
Generating sqlite DBs
Sqlite DBs complete

Lo ultimo que debemos hacer es habilitar el acceso, en este caso habilito el acceso anónimo por ftp. Instalaré el servidor vsftpd y configuraré el directorio donde he ubicado el repositorio como público:

[root@foreman centos6.5]# yum install vsftpd
[root@foreman pub]# service vsftpd start
Starting vsftpd for vsftpd: [ OK ]
[root@foreman ~]# vi /etc/vsftpd/vsftpd.conf
anon_root=/opt/jgp/repo #public directory
[root@foreman bin]# service vsftpd start
Starting vsftpd for vsftpd: [ OK ]
[root@foreman bin]# chkconfig vsftpd on

Plantilla del Sistema Operativo

Se deberá crear una plantilla para el despliegue de los sistemas. Será necesario especificar una tabla de partición. En principio se puede  utilizar la que viene por defecto, pero también podemos crear una y adaptarla a nuestras necesidades. Yo voy a instalar los servidores físicos que disponen de mas de un disco de la siguiente forma:

  1. Mirror de la partición 1 de cada disco de un tamaño de 25 gigas para /.
  2. Mirror de la partición 2 de cada disco de un tamaño de 2 gigas para swap.
  3. Stripe con LVM de lo que queda de disco y se utilizará para datos.

En Foreman accederemos a partition tables y crearemos la nuestra según estos criterios:

El contenido del layout será el siguiente:

zerombr

clearpart –all –initlabel –drives=sda,sdb

part raid.008001 –asprimary –ondrive=sda –size=25000
part raid.008002 –asprimary –ondrive=sda –size=2048
part pv.008003 –asprimary –ondrive=sda –grow –size=25000

part raid.008011 –asprimary –ondrive=sdb –size=25000
part raid.008012 –asprimary –ondrive=sdb –size=2048
part pv.008013 –asprimary –ondrive=sdb –grow –size=25000

raid / –fstype=ext4 –level=1 –device=md0 raid.008001 raid.008011
raid swap –level=1 –device=md1 raid.008002 raid.008012
volgroup vg_data –pesize=4096 pv.008003 pv.008013
logvol /opt/jgp –fstype=xfs –name=jgp –vgname=vg_data –grow –size=100

Una vez configurado el particionado que utilizarán nuestros sistemas pasamos a configurar el origen del software para nuestra instalación, que apuntará al repositorio que hemos creado anteriormente. En installation media crearemos una plantilla nueva:

​Ya por último crearemos la plantilla del sistema operativo que queremos desplegar. Para ello iremos a operating systems y allí crearemos uno nuevo, o modificaremos el que viene por defecto. En la primera pestaña únicamente hay que darle un nombre y seleccionar la arquitectura sobre la que se puede aplicar esta plantilla:

En la siguiente pestaña se selecciona la tabla de partición que hemos creado anteriormente.

En installation media seleccionamos el mirror que también hemos creado antes:

En los templates en principio no hace falta modificar nada, aunque se podrían haber modificado para especificar configuraciones concretas, como el software que se debe instalar en cada servidor o configurar el proxy para las actualizaciones a través de YUM.

La última pestaña es la de parámetros. En mi caso añado la zona horaria que deberán tener mis servidores, aunque también se podría especificar en el provisioning template.

Una vez hemos terminado con esta plantilla ya estamos en disposición de empezar a desplegar sistemas automáticamente con solo unos clicks. En los próximos posts añadiré algunos ejemplos.

Jugando con Docker

Últimamente se esta oyendo mucho hablar de Docker. Se trata de una tecnología similar a la que ya existía en Solaris con las zonas, y en Linux con LXC (de hecho utiliza LXC por debajo). Parece que viene patrocinado por algunas de las grandes en internet como eBay, Spotify e incluso Google parece que venia utilizando algo parecido desde hace tiempo.
Docker
La gran ventaja, como en el caso de las zonas, es que te permite “virtualizar” sin depender de un hipervisor y con un overhead mínimo en comparación a la virtualización tradicional.

Instalación

Como todo en Linux es muy fácil de instalar y ya viene preparado en la mayoría de distribuciones. En el caso de CentOS hay que habilitar el repositorio EPEL editando el fichero de configuración del repositorio y poniendo la variable enabled a 1:

[root@centos1 ~]# vi /etc/yum.repos.d/epel.repo

[epel]
name=Extra Packages for Enterprise Linux 6 – $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
A continuación ya podemos instalar docker con yum. Como veremos, una de las dependencias es LXC:
[root@centos1 ~]# yum install docker-io
Dependencies Resolved

================================================================================
 Package            Arch            Version                 Repository     Size
================================================================================
Installing:
 docker-io          x86_64          1.0.0-3.el6             epel          4.5 M
Installing for dependencies:
 lxc                x86_64          0.9.0-2.el6             epel           78 k
 lxc-libs           x86_64          0.9.0-2.el6             epel          116 k

Transaction Summary
================================================================================
Install       3 Package(s)

Total download size: 4.7 M
Installed size: 24 M
Is this ok [y/N]: y

Así de sencillo es instalarlo. Y como vemos, la versión es la primera estable que se ha publicado recientemente:
[root@centos1 ~]# docker -v
Docker version 1.0.0, build 63fe64c/1.0.0
Para empezar a utilizarlo se debe iniciar el servicio y configurarlo para que arranque en el runlevel predeterminado:
[root@centos1 ~]# service docker start
Starting cgconfig service:                                 [  OK  ]
Starting docker:                                                [  OK  ]
[root@centos1 ~]# chkconfig docker on

Imágenes y contenedores

Con el servicio ya en marcha podemos descargar las imágenes que docker mantiene, así como imágenes que la comunidad ha creado y ha subido. Por ejemplo descargaremos las últimas para centos y para ubuntu:

[root@centos1 ~]# docker pull centos:latest
Pulling repository centos
0c752394b855: Download complete
511136ea3c5a: Download complete
34e94e67e63a: Download complete

[root@centos1 ~]# docker pull ubuntu:latest
Pulling repository ubuntu
e54ca5efa2e9: Download complete
511136ea3c5a: Download complete
d7ac5e4f1812: Download complete
2f4b4d6a4a06: Download complete
83ff768040a0: Download complete
6c37f792ddac: Download complete
Para ver las imágenes que tenemos descargadas y disponibles para utilizar bastará con ejecutar el subcomando “images”:
[root@centos1 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              latest              e54ca5efa2e9        41 hours ago        276.1 MB
centos              latest              0c752394b855        10 days ago         124.1 MB
Pasando el parámetro -a podemos ver el historial de versiones de cada imagen:
[root@centos1 ~]# docker images -a
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              latest              e54ca5efa2e9        41 hours ago        276.1 MB
                            6c37f792ddac        41 hours ago        276.1 MB
                            83ff768040a0        41 hours ago        192.7 MB
                            2f4b4d6a4a06        41 hours ago        192.7 MB
                            d7ac5e4f1812        41 hours ago        192.5 MB
centos              latest              0c752394b855        10 days ago         124.1 MB
                            34e94e67e63a        2 weeks ago         0 B
                            511136ea3c5a        12 months ago       0 B
Podremos arrancar instancias o contenedores con las imágenes que queramos de la siguiente manera:
[root@centos1 ~]# docker run -i -t centos /bin/bash
bash-4.1# more /etc/centos-release
CentOS release 6.5 (Final)
bash-4.1# hostname
3ce460cbb9d8

[root@centos1 ~]# docker run -i -t ubuntu /bin/bash
root@60d6e0455be0:/# more /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION=”Ubuntu 14.04 LTS”
root@60d6e0455be0:/# hostname
60d6e0455be
Al pasar el parámetro -i al comando run se ejecutará el contenedor de forma interactiva, de forma que, en cuanto termine el comando que pasamos como parámetro la ejecución del contenedor terminará.
Mientras estemos ejecutando la shell, veremos que el contenedor está ejecutándose:
[root@centos1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
49087a343e7f        centos:latest       /bin/bash           12 seconds ago      Up 11 seconds                           dreamy_curie   
Si quisiesemos ver un historial de las instancias ejecutadas pasaríamos el parámetro -a:
 [root@centos1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
15dc7c59189c        centos:latest       /bin/bash           27 seconds ago      Up 26 seconds                                   compassionate_fermi  
49087a343e7f        centos:latest       /bin/bash           12 minutes ago      Exited (0) 17 seconds ago                       dreamy_curie         
9e69f5b64254        ubuntu:latest       uname -r            15 minutes ago      Exited (0) 15 minutes ago                       high_engelbart       
f5aa352a5ce9        centos:latest       uname -r            15 minutes ago      Exited (0) 15 minutes ago                       jovial_meitner       
60d6e0455be0        ubuntu:latest       /bin/bash           17 minutes ago      Exited (0) 16 minutes ago                       cocky_leakey         
961b10b9bbbf        ubuntu:latest       hostname            17 minutes ago      Exited (0) 17 minutes ago                       insane_mayer         
3ce460cbb9d8        centos:latest       /bin/bash           19 minutes ago      Exited (0) 17 minutes ago                       loving_yonath  
Si por contra, quisiesemos ejecutar un contenedor en background o demonizado, como sucede en Solaris con las zonas, al comando run le pasaríamos el parámetro -d. En el siguiente ejemplo arrancaríamos una instancia de la imagen ubuntu y dos instancias de la imagen de centos y finalmente veríamos que se están ejecutando las tres:
[root@centos1 ~]# docker run -d -t ubuntu  /bin/bash
abc254ab2e8eb392ce80938c8f2b8fa8cb1603ab6935b2121b7cb0cddbdd64c3
[root@centos1 ~]# docker run -d -t centos  /bin/bash
59adfe1998cc678cf2c9db964f1b57e60a301ffa2139c7a4635ebe315db2b718
[root@centos1 ~]# docker run -d -t centos  /bin/bash
6714217732adadec19f47399fe5f7252823787869a96e8fed72457cd5106589c
[root@centos1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
6714217732ad        centos:latest       /bin/bash           3 seconds ago       Up 2 seconds                            romantic_shockley 
59adfe1998cc        centos:latest       /bin/bash           7 seconds ago       Up 6 seconds                            thirsty_bartik    
abc254ab2e8e        ubuntu:latest       /bin/bash           14 seconds ago      Up 13 seconds                           naughty_yonath 
Al arrancar cada contenedor nos devuelve un número muy largo. Este número es el container_id que mas adelante vemos en la primera columna del comando ps. La última columna es un nombre que se asigna automáticamente y servirá para identificar las instancias de una forma mas amigable. Para parar las zonas que están corriendo podríamos pasar como identificador tanto el container_id como el nombre:

[root@centos1 ~]# docker stop romantic_shockley
romantic_shockley
[root@centos1 ~]# docker stop thirsty_bartik
thirsty_bartik
[root@centos1 ~]# docker stop naughty_yonath
naughty_yonath
[root@centos1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 

Como vemos, el kernel que se está ejecutando es el del host:

[root@centos1 ~]# uname -r
2.6.32-431.el6.x86_64
[root@centos1 ~]# docker run -i -t centos uname -r
2.6.32-431.el6.x86_64
[root@centos1 ~]# docker run -i -t ubuntu uname -r
2.6.32-431.el6.x86_64

Otra forma de arrancar un contenedor es con el comando start y pasando como parámetro el id del contenedor o el nombre que docker le asigno en su momento (lo podemos encontrar con docker ps -a)
 [root@centos1 ~]# docker start romantic_shockley
romantic_shockley
[root@centos1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
6714217732ad        centos:latest       /bin/bash           15 minutes ago      Up 3 seconds                            romantic_shockley
Para acceder a la consola del contenedor ejecutaríamos el comando attach:
 [root@centos1 ~]# docker attach romantic_shockley

Obtener información

Existe una serie de comandos que nos servirán para obtener información, tanto de docker, como de las imagenes o contenedores que tenemos creados. El comando info nos devolverá información general de la instalación actual de docker:
[root@centos1 ~]# docker info
Containers: 6
Images: 8
Storage Driver: devicemapper
 Pool Name: docker-8:1-132310-pool
 Data file: /var/lib/docker/devicemapper/devicemapper/data
 Metadata file: /var/lib/docker/devicemapper/devicemapper/metadata
 Data Space Used: 784.9 Mb
 Data Space Total: 102400.0 Mb
 Metadata Space Used: 1.4 Mb
 Metadata Space Total: 2048.0 Mb
Execution Driver: native-0.2
Kernel Version: 2.6.32-431.el6.x86_64
Con el comando history veremos el historial de versiones de la imagen que le hayamos especificado:
[root@centos1 ~]# docker history centos
IMAGE               CREATED             CREATED BY                                      SIZE
0c752394b855        10 days ago         /bin/sh -c #(nop) ADD file:ce8fdb737386beb5fd   124.1 MB
34e94e67e63a        2 weeks ago         /bin/sh -c #(nop) MAINTAINER The CentOS Proje   0 B
511136ea3c5a        12 months ago                                                       0 B
También tendremos el comando inspect, que nos devolverá un objeto JSON con información detallada de la imagen. Tambien sirve para obetner información de un contenedor.

[root@centos1 ~]# docker inspect centos
[{
    “Architecture”: “amd64”,
    “Author”: “The CentOS Project \u003ccloud-ops@centos.org\u003e – ami_creator”,
    “Comment”: “”,
    “Config”: {
        “AttachStderr”: false,
        “AttachStdin”: false,
        “AttachStdout”: false,
        “Cmd”: null,
        “CpuShares”: 0,
        “Cpuset”: “”,
        “Domainname”: “”,
        “Entrypoint”: null,
        “Env”: [
            “HOME=/”,
            “PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin”
        ],
        “ExposedPorts”: null,
        “Hostname”: “b2d0f1281acd”,
        “Image”: “34e94e67e63a0f079d9336b3c2a52e814d138e5b3f1f614a0cfe273814ed7c0a”,
        “Memory”: 0,
        “MemorySwap”: 0,
        “NetworkDisabled”: false,
        “OnBuild”: [],
        “OpenStdin”: false,
        “PortSpecs”: null,
        “StdinOnce”: false,
        “Tty”: false,
        “User”: “”,
        “Volumes”: null,
        “WorkingDir”: “”
    },
    “Container”: “b2d0f1281acd040292b36f6623feca10a89df1637c8d86e54079d473da4d05e3”,
    “ContainerConfig”: {
        “AttachStderr”: false,
        “AttachStdin”: false,
        “AttachStdout”: false,
        “Cmd”: [
            “/bin/sh”,
            “-c”,
            “#(nop) ADD file:ce8fdb737386beb5fd9aff7c9bbe9e6c9e60db290809dd6407c61b377e444b59 in /”
        ],
        “CpuShares”: 0,
        “Cpuset”: “”,
        “Domainname”: “”,
        “Entrypoint”: null,
        “Env”: [
            “HOME=/”,
            “PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin”
        ],
        “ExposedPorts”: null,
        “Hostname”: “b2d0f1281acd”,
        “Image”: “34e94e67e63a0f079d9336b3c2a52e814d138e5b3f1f614a0cfe273814ed7c0a”,
        “Memory”: 0,
        “MemorySwap”: 0,
        “NetworkDisabled”: false,
        “OnBuild”: [],
        “OpenStdin”: false,
        “PortSpecs”: null,
        “StdinOnce”: false,
        “Tty”: false,
        “User”: “”,
        “Volumes”: null,
        “WorkingDir”: “”
    },
    “Created”: “2014-06-09T21:38:41.281490617Z”,
    “DockerVersion”: “0.10.0”,
    “Id”: “0c752394b855e8f15d2dc1fba6f10f4386ff6c0ab6fc6a253285bcfbfdd214f5”,
    “Os”: “linux”,
    “Parent”: “34e94e67e63a0f079d9336b3c2a52e814d138e5b3f1f614a0cfe273814ed7c0a”,
    “Size”: 124078508
}

Para obtener informacion específica de un contenedor especificaremos al comando inspect la clave que queremos que nos devuelva, como por ejemplo el hostname o la dirección IP:
[root@centos1 ~]# docker run -d -t centos  /bin/bash
d7e7938ab7e98ff8e2413179d5222201de6a0c66716b99aafb35a0805fbf279e
[root@centos1 ~]# docker  ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d7e7938ab7e9        centos:latest       /bin/bash           11 seconds ago      Up 11 seconds                           nostalgic_newton   

[root@centos1 ~]# docker inspect -f ‘{{ .Config.Hostname }}’ nostalgic_newton
d7e7938ab7e9
[root@centos1 ~]# docker inspect -f ‘{{ .NetworkSettings.IPAddress }}’ nostalgic_newton
172.17.0.22

Borrado de contenedores

Para norrar contenedores utilizaremos el comando rm. Le podremos pasar un único identificador de contenedor o varios en el mismo comando:
[root@centos1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                       PORTS               NAMES
abc254ab2e8e        ubuntu:latest       /bin/bash           22 minutes ago      Exited (0) 18 minutes ago                        naughty_yonath      
90ae553f4384        centos:latest       /bin/bash           23 minutes ago      Exited (-1) 22 minutes ago                       ecstatic_mcclintock

[root@centos1 ~]# docker rm ecstatic_mcclintock naughty_yonath
ecstatic_mcclintock
naughty_yonath

Creación de módulos para puppet

Una vez puesto en marcha un servidor de Puppet es importante tener bien organizado la estructura de directorios para que no se convierta en un caos. Hay tres directorios importantes, el manifests, el modules y el files. Mi estructura actual es la siguiente:

[root@puppet puppet]# tree /etc/puppet/
/etc/puppet/
├── auth.conf
├── files
│   ├── limits.conf
│   ├── motd
│   ├── nicstat-linux
│   ├── nicstat-solarisx86
│   ├── ntp.conf
│   └── sysctl.conf
├── fileserver.conf
├── manifests
│   ├── nodes.pp
│   ├── site.pp
├── modules
│   ├── ftp
│   │   └── manifests
│   │   └── init.pp
│   ├── nicstat
│   │   └── manifests
│   │   └── init.pp
│   ├── ntp
│   │   └── manifests
│   │   └── init.pp
│   ├── sysconf
│   │   └── manifests
│   │   └── init.pp
│   └── users
│   └── manifests
│   └── init.pp
└── puppet.conf
En el manifests se ubican los principales scripts. Yo lo organizo en un site.pp que incluye el fichero nodes.pp que es donde defino las configuraciones específicas para cada nodo. En el directorio modules habrá un subdirectorio por cada módulo y dentro de este otro subdirectorio manifests y un fichero init.pp donde esta la propia definición del módulo. El último directorio importante es el files que utilizo para almacenar los ficheros de configuración estandarizados o binarios que quiero desplegar en los nodos.
Voy a analizar algunos de los ficheros comentados:
site.pp:
La idea de este fichero es que esté lo mas limpio posible para que de un vistazo sea intuitivo ver que scripts se están aplicando. En mi caso únicamente importo el nodes.pp.
[root@puppet manifests]# more site.pp
import ‘nodes.pp’
En el nodes.pp defino los nodos, filtrando por el nombre (se podría filtrar por algún otro parámetro). En cada definición de nodo incluyo los módulos que les quiero aplicar.
[root@puppet manifests]# more nodes.pp
node puppet {
    include ntp
    include nicstat
    include users
}
node /linux[1-3].enterprise.com/ {
    include ntp
    include nicstat
    include sysconf
    include users
    notice(“I am running on node ${fqdn}”)
}
node ‘solaris[1-2].enterprise.com‘ {
    include ftp
    include nicstat
    include users
    notice(“I am running on node ${fqdn}”)
}
Modulos
Para crear un módulo hay que crear una subcarpeta con el nombre del módulo. Dentro de este nuevo subdirectorio puede haber una estructura similar a la general en /etc/puppet. Como requisito fundamental es la existencia del fichero init.pp. En dicho fichero deberá existir una definición de clase (class) que será la que se importa en el nodes.pp.
He creado varios módulos para configurar determinadas funcionalidades, por ejemplo:
FTP
me aseguro que este parado por temas de seguridad.
[root@puppet manifests]# more /etc/puppet/modules/ftp/manifests/init.pp
class ftp {
    service { ‘ftp’:
        ensure => stopped,
    }
}
NTP
Existe en Puppet Forge algún módulo mas completo para el ntp, sin embargo para lo que yo busco este me es suficiente. Me aseguro de que el paquete esté instalado, el servicio arrancado y que el fichero de configuración es el mismo en todos los servidores.
[root@puppet manifests]# more /etc/puppet/modules/ntp/manifests/init.pp
class ntp {
    package { ‘ntp’:
        ensure => installed,
    }
    service { ‘ntpd’:
        ensure => running,
        require => Package[‘ntp’],
    }
    file { ‘/etc/ntp.conf’:
        notify => Service[“ntpd”],
        source => “puppet:///files/ntp.conf”,
        require => Package[‘ntp’],
    }
}
NICSTAT
Se trata de un binario para obtener estadísticas avanzadas de red. Me interesa desplegarlo en todos los nodos y ademas hay que tener en cuenta que el binario es diferente para Solaris y Linux:
[root@puppet manifests]# more /etc/puppet/modules/nicstat/manifests/init.pp
class nicstat{
    if $::osfamily == ‘Solaris’ {
        file { ‘/opt/utils/’:
            ensure => directory,
        }
        file { ‘/opt/utils/nicstat’:
            source => “puppet:///files/nicstat-solarisx86”,
        }
    } elsif $::osfamily == ‘RedHat’ {
        file { ‘/opt/utils/’:
            ensure => directory,
        }
        file { ‘/opt/utils/nicstat’:
        source => “puppet:///files/nicstat-linux”,
        }
    }
}
USERS
Con este módulo pretendo estandarizar la creación de usuarios. Podríamos crear todos los usuarios de los administradores por ejemplo o asegurarnos de que no exista determinado usuario.
[root@puppet puppet]# more /etc/puppet/modules/users/manifests/init.pp
class users{
    user { ‘jsotoca’:
        ensure => present,
        comment => ‘Julian Garcia-Sotoca’,
        home => $operatingsystem ?{
            Solaris => ‘/export/home/jsotoca’,
            default => ‘/home/jsotoca’,
        },
        managehome => true,
    }

    user { ‘baduser’:
        ensure => absent,
    }

Instalación de Puppet en Solaris 10

Para instalar el agente de puppet en Solaris 10 lo mas facil es recurrir a OpenCSW. De esta forma podemos descargar el paquete y sus correspondientes dependencias (a partir de Solaris 11.2 ya viene incluido en los repositorios oficiales). 

Lo mas útil es crear un paquete que contenga el propio paquete de puppet y sus dependencias, de forma que podamos redistribuir dicho paquete en todos los servidores donde lo queramos instalar y no será necesario que todos los servidores tengan conexión a Internet. Para ello ejecutaremos:

root@solaris01 # /opt/csw/bin/pkgutil –stream –target=i386:5.10 –output /tmp/puppet.pkg –yes –download puppet
=> Fetching new catalog and descriptions (http://mirror.opencsw.org/opencsw/testing/i386/5.10) if available …
==> 3707 packages loaded from /var/opt/csw/pkgutil/catalog.mirror.opencsw.org_opencsw_testing_i386_5.10
Solving needed dependencies …
Solving dependency order …
Package list:
       CSWalternatives-1.2,REV=2013.10.15 (opencsw/testing)
       CSWaugeas-0.10.0,REV=2012.01.04 (opencsw/testing)
       CSWcas-initsmf-1.49,REV=2013.03.13 (opencsw/testing)
       CSWcas-usergroup-1.44,REV=2011.05.02 (opencsw/testing)
       CSWcommon-1.5,REV=2010.12.11 (opencsw/testing)
       CSWfacter-1.7.1,REV=2013.05.22 (opencsw/testing)
       CSWlibgcc-s1-4.8.2,REV=2013.11.08 (opencsw/testing)
       CSWlibgdbm4-1.9,REV=2011.10.24 (opencsw/testing)
       CSWlibgnugetopt0-1.3,REV=2011.07.06 (opencsw/testing)
       CSWlibiconv2-1.14,REV=2011.08.07 (opencsw/testing)
       CSWliblzma5-5.0.5,REV=2013.07.05 (opencsw/testing)
       CSWlibncurses5-5.9,REV=2011.11.21 (opencsw/testing)
       CSWlibreadline6-6.2,REV=2011.07.02 (opencsw/testing)
       CSWlibruby18-1-1.8.7p357,REV=2014.03.06 (opencsw/testing)
       CSWlibssl1-0-0-1.0.1g,REV=2014.04.08 (opencsw/testing)
       CSWlibxml2-2-2.9.1,REV=2013.08.16 (opencsw/testing)
       CSWlibz1-1.2.8,REV=2013.09.23 (opencsw/testing)
       CSWpuppet-2.7.23,REV=2013.08.15 (opencsw/testing)
       CSWruby18-1.8.7p357,REV=2014.03.06 (opencsw/testing)
       CSWrubyaugeas-0.4.1,REV=2012.03.25 (opencsw/testing)
       CSWterminfo-5.9,REV=2011.11.21 (opencsw/testing)
Total size: 9.3 MB
A local copy of CSWcommon-1.5,REV=2010.12.11 exists and is of matching size.
=> Fetching CSWlibz1-1.2.8,REV=2013.09.23 (2/21) …
A local copy of CSWlibiconv2-1.14,REV=2011.08.07 exists and is of matching size.
=> Fetching CSWliblzma5-5.0.5,REV=2013.07.05 (4/21) …
=> Fetching CSWlibxml2-2-2.9.1,REV=2013.08.16 (5/21) …
=> Fetching CSWlibgcc-s1-4.8.2,REV=2013.11.08 (6/21) …
A local copy of CSWlibgnugetopt0-1.3,REV=2011.07.06 exists and is of matching size.
A local copy of CSWterminfo-5.9,REV=2011.11.21 exists and is of matching size.
=> Fetching CSWlibruby18-1-1.8.7p357,REV=2014.03.06 (9/21) …
=> Fetching CSWlibssl1-0-0-1.0.1g,REV=2014.04.08 (10/21) …
=> Fetching CSWlibgdbm4-1.9,REV=2011.10.24 (11/21) …
=> Fetching CSWalternatives-1.2,REV=2013.10.15 (12/21) …
A local copy of CSWcas-usergroup-1.44,REV=2011.05.02 exists and is of matching size.
A local copy of CSWcas-initsmf-1.49,REV=2013.03.13 exists and is of matching size.
A local copy of CSWlibncurses5-5.9,REV=2011.11.21 exists and is of matching size.
A local copy of CSWlibreadline6-6.2,REV=2011.07.02 exists and is of matching size.
A local copy of CSWaugeas-0.10.0,REV=2012.01.04 exists and is of matching size.
=> Fetching CSWruby18-1.8.7p357,REV=2014.03.06 (18/21) …
A local copy of CSWrubyaugeas-0.4.1,REV=2012.03.25 exists and is of matching size.
=> Fetching CSWfacter-1.7.1,REV=2013.05.22 (20/21) …
=> Fetching CSWpuppet-2.7.23,REV=2013.08.15 (21/21) …
Transforming CSWcommon …
Transforming CSWlibz1 …
Transforming CSWlibiconv2 …
Transforming CSWliblzma5 …
Transforming CSWlibxml2-2 …
Transforming CSWlibgcc-s1 …
Transforming CSWlibgnugetopt0 …
Transforming CSWterminfo …
Transforming CSWlibruby18-1 …
Transforming CSWlibssl1-0-0 …
Transforming CSWlibgdbm4 …
Transforming CSWalternatives …
Transforming CSWcas-usergroup …
Transforming CSWcas-initsmf …
Transforming CSWlibncurses5 …
Transforming CSWlibreadline6 …
Transforming CSWaugeas …
Transforming CSWruby18 …
Transforming CSWrubyaugeas …
Transforming CSWfacter …
Transforming CSWpuppet …
Transforming packages into stream (/tmp/puppet.pkg) …

Install commands in dependency safe order:

pkgadd -G -d /tmp/puppet.pkg CSWcommon
pkgadd -G -d /tmp/puppet.pkg CSWlibz1
pkgadd -G -d /tmp/puppet.pkg CSWlibiconv2
pkgadd -G -d /tmp/puppet.pkg CSWliblzma5
pkgadd -G -d /tmp/puppet.pkg CSWlibxml2-2
pkgadd -G -d /tmp/puppet.pkg CSWlibgcc-s1
pkgadd -G -d /tmp/puppet.pkg CSWlibgnugetopt0
pkgadd -G -d /tmp/puppet.pkg CSWterminfo
pkgadd -G -d /tmp/puppet.pkg CSWlibruby18-1
pkgadd -G -d /tmp/puppet.pkg CSWlibssl1-0-0
pkgadd -G -d /tmp/puppet.pkg CSWlibgdbm4
pkgadd -G -d /tmp/puppet.pkg CSWalternatives
pkgadd -G -d /tmp/puppet.pkg CSWcas-usergroup
pkgadd -G -d /tmp/puppet.pkg CSWcas-initsmf
pkgadd -G -d /tmp/puppet.pkg CSWlibncurses5
pkgadd -G -d /tmp/puppet.pkg CSWlibreadline6
pkgadd -G -d /tmp/puppet.pkg CSWaugeas
pkgadd -G -d /tmp/puppet.pkg CSWruby18
pkgadd -G -d /tmp/puppet.pkg CSWrubyaugeas
pkgadd -G -d /tmp/puppet.pkg CSWfacter
pkgadd -G -d /tmp/puppet.pkg CSWpuppet
Como vemos, al final del proceso nos muestra el paso a paso de como instalarlo correctamente. Dichos comandos se pueden poner en un script de forma que la instalación consista en copiar el software y ejecutar el instalador:
root@solaris01 # ls -l | grep puppet
-rwxr-xr-x   1 root     root         883 Apr 29 16:58 install_puppet.sh
-rw-r–r–   1 root     root     32153600 Apr 29 16:56 puppet.pkg
root@solaris01 # ./install_puppet.sh

Una vez instalado podemos verificar el archivo de configuración y verificamos que en el hosts aparezca el servidor de puppet:
root@solaris01 # grep puppet /etc/hosts
X.X.X.X puppet

root@solaris01 # vi /opt/csw/etc/puppet/puppet.conf
# puppet.conf
#
# points puppet at OpenCSW default paths

[main]
   confdir = /etc/opt/csw/puppet
   config = $confdir/puppet.conf
   vardir = /var/opt/csw/puppet
   ssldir = $vardir/ssl

[agent]
   # The file in which puppetd stores a list of the classes
   # associated with the retrieved configuratiion.  Can be loaded in
   # the separate “puppet“ executable using the “–loadclasses“
   # option.
   # The default value is ‘$confdir/classes.txt’.
   classfile = $vardir/classes.txt

   # Where puppetd caches the local configuration.  An
   # extension indicating the cache format is added automatically.
   # The default value is ‘$confdir/localconfig’.
   localconfig = $vardir/localconfig
   report = true
~

En este momento ya podemos realizar un test y firmar el certificado en la parte del servidor. A continuación habilitaríamos el servicio:
root@solaris01 #  /opt/csw/bin/puppet agent –test
root@solaris01 #  svcadm enable cswpuppetd

Para parar el agente hay que deshabilitar el servicio:
 
root@solaris01 #  svcadm disable cswpuppetd
He creado algunos manifiestos específicos para solaris o que realizan una determinada acción en función del sistema operativo:

Despliegue de un fichero

root@solaris01 #cat modules/nicstat/manifests/init.pp
class nicstat{
    if $::osfamily == ‘Solaris’ {
        file { ‘/opt/utils/’:
            ensure => directory,
        }
        file { ‘/opt/utils/nicstat’:
            source => “puppet:///files/nicstat-solarisx86”,
        }
       
       
    } elsif $::osfamily == ‘RedHat’ {
        file { ‘/opt/utils/’:
            ensure => directory,
        }
        file { ‘/opt/utils/nicstat’:
            source => “puppet:///files/nicstat-linux”,
        }   
    }
}

Customizar el MOTD:

node ‘solaris’’ {
   include ftp
   include nicstat
   file { “/etc/motd”:
           content => “Welcome
\tServer IP address: ${ipaddress}.
\tHostname: ${fqdn}
\tOperating System: ${operatingsystem}\tRelease: ${operatingsystemrelease}
\tOS family: ${osfamily}
\tKernel: ${kernel} ${kernelversion}
\tPuppet ${puppetversion}
\tCPU: ${physicalprocessorcount}\t\t\tCores: ${processorcount}
\tMemory: ${memorysize}\tSwap: ${swapsize}
\tTimeZone: ${timezone}
\tphyisical/virtual: ${virtual}\tType: ${type}
\tManufacturer: ${manufacturer}\tModel: ${productname}
\tSerial Number: ${serialnumber}
\n”
       }
       notice(“I am running on node ${fqdn}”)
}

Monitorización Switches fibra Brocade

Me ha tocado montar la monitorización de los switches de fibra que tenemos, dos Brocade 48000. Como en los dispositivos de red, lo mas sencillo para monitorizarlos es utilizando SNMP. De la documentación de referencia he conseguido extraer información de los puertos.

Los que he utilizado para crear una tabla dinámica con información de cada puerto son los siguientes:

  • Ancho de banda:

Words received: 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.12.X
Words transmited: 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.11.X

Hay que tener en cuenta que se trata de un contador de “words” con lo que si se quiere tener un dato mas común (Mbps por ejemplo) deberíamos hacer la conversión y tener en cuenta el tiempo entre muestras.

Si nuestra herramienta utilizase python por ejemplo bastaría con hacer la siguiente conversión:

txMBps = (abs(tx)*4)/60/1048576

Donde:

tx contiene la diferencia entre dos muestras consecutivas. Al ser una variable de tipo contador de 32 bits es posible que haya que hacer algún tipo de control al reiniciarse el contador.
Multiplico por 4 para convertir de “words” a bytes (ver página 618 de la documentación)
Divido por 60 porque la monitorización toma muestras de la variable cada minuto
Divido por 1024*1024 para convertir de bytes a MBytes.

  • Estadísticas puertos:

EIF: devuelve el número de errores de codificación o disparidad dentro de las tramas recibidas

swFCPortRxEncInFrs 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.21.X

CRC: errores de CRC detectados en las tramas recibidas

swFCPortRxCrcs 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.22.X

Trcs: Tramas truncadas que el puerto ha recibido

swFCPortRxTruncs 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.23.X

TL: Número de tramas recibidas que son demasiado largas

swFCPortRxTooLongs 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.24.X

BEOF: Cuenta el número de tramas que tienen malos delimitadores EOF

swFCPortRxBadEofs 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.25.X

EOF: devuelve el número de errores de codificación o disparidad fuera de las tramas recibidas

swFCPortRxEncOutFrs 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.26

BO: cuenta el número de tramas desordenadas recibidas

swFCPortRxBadOs 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.27

Cualquier incremento en estos contadores puede suponer un problema en la fibra o en los puertos.

  • Estado de los puertos:

swFCPortPhyState 1.3.6.1.4.1.1588.2.1.1.1.6.2.1.3

Este OID devuelve un número que se corresponde con los siguientes estados:

  1. noCard: No hay una tarjeta presentada en este slot del switch
  2. noTransceiver: No hay un GBIC o SFP en el puerto
  3. laserFault: El módulo esta avisando de un fallo en el láser, por lo tanto el GBIC esta defectuoso
  4. noLight: El modulo no está recibiendo luz
  5. noSync: El módulo esta recibiendo luz pero sin sincronismo
  6. inSync: El modulo está recibiendo luz y esta en sincronismo
  7. portFault: El puerto está marcado como en fallo
  8. diagFault: El puerto ha fallado en los diagnósticos
  9. lockRef: Puerto está bloqueado

Con estos OIDs se puede tener una visión bastante exacta del estado de nuestro switch, sus errores y su uso.
Así es como ha quedado en la herramienta de monitorización que utilizo, en caso de producirse algún cambio de estado respecto al día anterior de un vistazo lo detecto:

Estado de los puertos en varios slots de brocade 48k

Estado de los puertos en un slot de brocade 48k

 Tengo otra tabla con las estadísticas que he comentado antes para cada puerto:

 Estadisticas puertos brocade

 Existe un bug en la versión de firmware que tiene el brocade que hace que los slots con Gbics a 8Gbps muestren errores de sincronismo.

Instalación de squid como proxy para YUM

En entornos con multitud de servidores GNU/Linux la gestión de las actualizaciones debe ser un proceso a tener en cuenta. Si queremos actualizar una gran cantidad de servidores, la conexión a Internet puede no ser suficiente o incluso podemos afectar a servicios productivos saturando el ancho de banda. Para solventar este punto está la opción de utilizar repositorios locales. En algunos casos, como las distribuciones derivadas de Debian, se puede poner un proxy cache de los paquetes(aptProxy), el cual se descargará únicamente los paquetes que no se haya descargado con anterioridad.

A diferencia de los sistemas Debian y sus derivados, con Red Hat, no tenemos la opción de tener un proxy cache de paquetes . Siempre podemos tener una copia del repositorio de la distribución que usemos pero es una opción que requiere de un servidor con gran cantidad de espacio en disco y con paquetes que muy probablemente no vayamos a necesitar.
Para tener una solución parecida a la del aptProxy, se puede utilizar Squid como proxy al cual lo configuraremos en el fichero yum.conf de nuestros servidores. 
La instalación es muy sencilla desde yum:
[root@yumrepo ~]# yum install squid 
A continuación lo configuraremos editando el fichero /etc/squid/squid.conf. Básicamente lo que haremos será crear una ACL (localnet) para controlar quien puede utilizar el proxy y donde especificaremos los segmentos donde tenemos servidores instalados. También crearemos una ACL (GoodSites) para controlar a donde se puede conectar el proxy para descargar paquetes.Esta ACL leerá de un fichero los dominios permitidos:
[root@yumrepo ~]# vi /etc/squid/squid.conf
#
# Recommended minimum configuration:
#
acl manager proto cache_object
acl localhost src 127.0.0.1/32 ::1
acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1

# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 192.168.1.0/24 # RFC1918 possible internal network
acl localnet src 192.168.2.0/24 # RFC1918 possible internal network
acl localnet src 192.168.3.0/24 # RFC1918 possible internal network
acl localnet src 192.168.4.0/24 # RFC1918 possible internal network
acl localnet src 192.168.5.0/24 # RFC1918 possible internal network
acl localnet src 10.0.0.0/8 # RFC1918 possible internal network

acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT

#
# Recommended minimum Access Permission configuration:
#
# Only allow cachemgr access from localhost
http_access allow manager localhost
http_access deny manager

# Deny requests to certain unsafe ports
http_access deny !Safe_ports

# Deny CONNECT to other than secure SSL ports
#http_access deny CONNECT !SSL_ports

# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on “localhost” is a local user
#http_access deny to_localhost

#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#
acl GoodSites dstdomain “/etc/squid/allowed-sites.squid”
# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
http_access allow localnet GoodSites
http_access allow localhost GoodSites

# And finally deny all other access to this proxy
http_access deny all

# Squid normally listens to port 3128
http_port 3128

# set visible_hostname
visible_hostname yumrepo.enterprise.com

# We recommend you to use at least the following line.
hierarchy_stoplist cgi-bin ?

# Uncomment and adjust the following to add a disk cache directory.
cache_dir ufs /var/spool/squid 25000 16 256

# Leave coredumps in the first cache dir
coredump_dir /var/spool/squid
# Add any of your own refresh_pattern entries above these.
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320

El fichero de la ACL GoodSites será el siguiente:
[root@yumrepo ~]# vi /etc/squid/allowed-sites.squid
.centos.com
.oracle.com
.vmware.com

De esta forma, solo podrá bajar paquetes RPM de esos dominios.

A continuación configuraremos el servicio para que arranque tras un reinicio del servidor:

[root@yumrepo ~]# chkconfig squid –list
squid 0:off 1:off 2: off 3: off 4: off 5: off 6:off
[root@yumrepo ~]# chkconfig squid on
[root@yumrepo ~]# chkconfig squid –list
squid 0:off 1:off 2:on 3:on 4:on 5:on 6:off

Un tema importante es la cache. El directorio donde estará ubicada se especifica en el archivo de configuración, así como el tamaño máximo que puede tener y el periodo de validez de la misma. En nuestro caso, al tratarse de un servicio que se usará para descargar software, se presupone que el volumen necesario será alto, por tanto optamos por asignar un disco y especificar el directorio de la cache como punto de montaje. Crearemos un volumen lógico para poder ser ampliado en un futuro con facilidad y editaremos el /etc/fstab para que se monte tras un reinicio:

[root@yumrepo ~]# fdisk /dev/sdb
[root@yumrepo ~]# partprobe -s

[root@yumrepo ~]# pvcreate /dev/sdb1
[root@yumrepo ~]# vgcreate repo-vg /dev/sdb1
[root@yumrepo ~]# vgdisplay
— Volume group —
VG Name repo-vg
System ID
Format lvm2
Metadata Areas 1
Metadata Sequence No 3
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 1
Max PV 0
Cur PV 1
Act PV 1
VG Size 30,00 GiB
PE Size 4,00 MiB
Total PE 7679
Alloc PE / Size 7679 / 30,00 GiB
Free PE / Size 0 / 0
VG UUID qapuNn-QQv4-psKa-lSTh-JsJZ-hS3j-Js6bjf
[root@yumrepo ~]# lvcreate -l 100%FREE repo-vg
[root@yumrepo ~]# lvrename /dev/repo-vg/lvol0 /dev/repo-vg/repo-lv01
[root@yumrepo ~]# lvdisplay
— Logical volume —
LV Path /dev/repo-vg/repo-lv01
LV Name repo-lv01
VG Name repo-vg
LV UUID nG55k1-k62o-UGZf-B6Pi-WTb6-vlI5-FRqzWL
LV Write Access read/write
LV Creation host, time ol6Template, 2014-04-14 14:43:56 +0200
LV Status available
# open 1
LV Size 30,00 GiB
Current LE 7679
Segments 1
Allocation inherit
Read ahead sectors auto
– currently set to 256
Block device 252:2
[root@yumrepo ~]# mkfs.ext4 /dev/repo-vg/repo-lv01
[root@yumrepo ~]# mount /dev/repo-vg/repo-lv01 /var/spool/squid
[root@yumrepo ~]# vi /etc/fstab
/dev/repo-vg/repo-lv01 /var/spool/squid ext4 defaults 1 1Arranque del servicio

Una vez montado el directorio de la cache se crean los directorios que utilizará squid:
[root@yumrepo ~]# squid -z
[root@yumrepo ~]# ls -l /var/spool/squid
total 68
drwxr-x—. 258 squid squid 4096 abr 14 15:05 00
drwxr-x—. 258 squid squid 4096 abr 14 15:05 01
drwxr-x—. 258 squid squid 4096 abr 14 15:05 02
drwxr-x—. 258 squid squid 4096 abr 14 15:05 03
drwxr-x—. 258 squid squid 4096 abr 14 15:05 04
drwxr-x—. 258 squid squid 4096 abr 14 15:05 05
drwxr-x—. 258 squid squid 4096 abr 14 15:05 06
drwxr-x—. 258 squid squid 4096 abr 14 15:05 07
drwxr-x—. 258 squid squid 4096 abr 14 15:05 08
drwxr-x—. 258 squid squid 4096 abr 14 15:05 09
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0A
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0B
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0C
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0D
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0E
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0F
-rw-r—–. 1 squid squid 2880 abr 28 18:20 swap.state
El último paso será arrancar el servicio y verificar que está escuchando en el puerto por defecto.

[root@yumrepo ~]# service squid start
Starting squid: . [ OK ]
[root@yumrepo ~]# netstat -ant | grep 3128
tcp 0 0 :::3128 :::* LISTEN

En los clientes bastará con añadir la siguiente línea en el fichero /etc/yum.conf:
proxy=http://X.X.X.X:3128 

Si lanzamos dos actualizaciones en clientes diferentes veremos que la segunda va mucho mas rápido que la primera y que los directorios de la cache empiezan a tener uso.

Instalación de sistemas linux (Derivados de Red Hat) con kickstart

Cuando se instala un sistema Red Hat (o derivados) el instalador deja en el directorio /root un fichero de configuración con la configuración que se ha utilizado a la hora de realizar la instalación. Dicho fichero se puede utilizar si se necesitan instalar varios servidores idénticos. 
El fichero de configuración deberá ser accesible desde el nuevo servidor, en teoría se puede compartir por nfs, ftp o http. La forma que me ha ido mejor a mi ha sido por http. He instalado un simple apache en un servidor y he puesto el fichero accesible. 
Para lanzar la instalación debemos arrancar con el DVD de la distribución y cuando aparezca el menú del GRUB pulsar la tecla ESC. En ese momento nos aparece un promt donde especificaremos donde se encuentra el fichero de configuración y la configuración de red para ese sistema:
linux ks=http://X.X.X.X/ks.cfg ksdevice=eth0 ip=X.X.X.Y netmask=255.255.255.0 gateway=X.X.X.Z
 

El proceso de instalación arrancará y automáticamente instalará el sistema hasta que nos pida reiniciar el servidor ya con el sistema operativo instalado.
El fichero de configuración está dividido en bloques. Una primera parte donde se especifican las opciones globales de configuración. A continuación se indican que paquetes se van a instalar en un bloque identificado con la etiqueta “%packages”. Adicionalmente se pueden indicar comandos que se ejecutarán antes de arrancar la instalación y otros que se ejecutarán una vez la instalación haya terminado, identificados con las etiquetas “%pre” y “%post” respectivamente.

La parte que me ha parecido mas cómoda es la de la configuración de los discos. En mi caso quería montar un Raid-1 por software con los dos discos que tiene el servidor. Para ello se especifica de la siguiente manera:

zerombr 

clearpart –all –drives=sda,sdb 
part raid.008001 –asprimary –ondrive=sda –size=500 
part raid.008002 –asprimary –ondrive=sda –size=98304 
part raid.008003 –asprimary –ondrive=sda –size=100000 
part raid.008005 –asprimary –ondrive=sda –grow –size=755060 
part raid.008011 –asprimary –ondrive=sdb –size=500 
part raid.008012 –asprimary –ondrive=sdb –size=98304 
part raid.008013 –asprimary –ondrive=sdb –size=100000 
part raid.008015 –asprimary –ondrive=sdb –grow –size=755060 
raid /boot –fstype=ext4 –level=1 –device=md0 raid.008001 raid.008011 
raid / –fstype=ext4 –level=1 –device=md1 raid.008003 raid.008013 
raid /var –fstype=ext4 –level=1 –device=md2 raid.008005 raid.008015 
raid swap –level=1 –device=md3 raid.008002 raid.008012
Estoy utilizando cada disco, creando cuatro particiones y luego creando los meta-dispositivos raid-1 con una partición de cada disco.

Dejo en github una copia del fichero que me ha servido durante mis instalaciones

Reconfiguración de interfaces en entornos virutales con máquinas virtuales Linux

En entornos virtuales es habitual clonar servidores. En Linux el sistema udev, al detectar un nuevo hardware con una MAC diferente, le asigna un número de interfaz secuencial. Da igual si se le ha borrado alguna interfaz previa, la nueva que se configure seguirá la numeración. Con este comportamiento, es posible que haya cosas que no funcionen, por ejemplo si tenemos un script que haga referencia al nombre de interfaz eth0. Si queremos recuperar la numeración deberemos modificar el fichero de reglas de udev y luego además revisar los scripts de configuración de las interfaces ya que probablemente las MACs no coincidan.
He creado un nuevo script, que se puede poner en el .bashrc del usuario root por ejemplo. Dicho script detectará si existe la interfaz eth0, en caso de no existir realizará la reconfiguración de udev, limpiará configuraciones de red previas y finalmente creará los nuevos ficheros de configuración. Para crear estos ficheros tendrá en cuenta si queremos utilizar un direccionamiento estático o dinámico (DHCP). 
Utilizando este script, siempre que clonemos la máquina y accedamos con el usuario root nos preguntará la configuración de red que queremos.
Ejemplo de uso (desde una consola ya que baja las interfaces):
Verificamos que el nombre de la interfaz eth0 no existe:

Configuración de red tras el clonado

Lanzamos el script, donde veremos que baja las inerfaces de red y pide si queremos borrar configuraciones previas:

Llamada al script netconfig.sh

Pide que tipo de configuración queremos en todas las interfaces:

Reconfiguración de las interfaces

Una vez terminada la ejecución del script vemos que la interfaz eth0 ya aparece y mantiene la MAC de la interfaz que veiamos en la primer imágen:

Configuración de red final

El script:

#!/bin/bash
function static {
hostname=`hostname`
read -r -p “Hostname: [${hostname}] ” hostname
if [ -z “$hostname” ]; then hostname=`hostname`; fi
read -r -p “IP address: ” ip
read -r -p “Netmask: ” mask
grep dhcp /etc/sysconfig/network-scripts/ifcfg-eth* 2>/dev/null >/dev/null
if [ $? -eq 0 ] ; then
echo “there is a network configured with dhcp which should configure your gateway”
else
read -r -p “Gateway: ” gate
if [ $? -eq 0 ] ; then
sed -i -e ‘s#^\(GATEWAY=\).*$#\1′”${gate}”‘#’ /etc/sysconfig/network
else
echo “GATEWAY=\”${gate}\”” >>/etc/sysconfig/network
fi
fi
#echo “HOSTNAME: ${hostname}\tIP: ${ip}\tNETMASK: ${mask}”
mac=`ifconfig ${iface} | grep eth | awk ‘{ print $5}’`
if [ -f /etc/sysconfig/network-scripts/ifcfg-${iface} ]; then
rm -r /etc/sysconfig/network-scripts/ifcfg-${iface}
fi
echo “DEVICE=\”${iface}\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “BOOTPROTO=\”static\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “NM_CONTROLLED=\”yes\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “ONBOOT=\”yes\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “TYPE=\”Ethernet\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “IPADDR=\”${ip}\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “NETMASK=\”${mask}\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “HWADDR=\”${mac}\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “DNS1=\”X.X.X.X\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “DNS2=\”Y.Y.Y.Y\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “DOMAIN=\”enterprise.com\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
sed -i -e ‘s#^\(HOSTNAME=\).*$#\1′”${hostname}”‘#’ /etc/sysconfig/network
grep GATEWAY /etc/sysconfig/network 2>/dev/null >/dev/null
}

function dhcp {
echo “Configuring DHCP for ${iface}”
hostname=`hostname`
read -r -p “Hostname: [${hostname}] ” hostname
if [ -z “$hostname” ]; then hostname=`hostname`; fi
mac=`ifconfig ${iface} | grep eth | awk ‘{ print $5}’`
if [ -f /etc/sysconfig/network-scripts/ifcfg-${iface} ]; then
rm -r /etc/sysconfig/network-scripts/ifcfg-${iface}
fi
echo “DEVICE=\”${iface}\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “BOOTPROTO=\”dhcp\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “HWADDR=\”${mac}\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “NM_CONTROLLED=\”yes\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “ONBOOT=\”yes\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
echo “TYPE=\”Ethernet\”” >> /etc/sysconfig/network-scripts/ifcfg-${iface}
sed -i -e ‘s#^\(HOSTNAME=\).*$#\1′”${hostname}”‘#’ /etc/sysconfig/network
}


ifconfig eth0 2>/dev/null >/dev/null
if [ $? -ne 0 ] ; then
echo “eth0 not found. Interface configuration…”
echo “Recreating interfaces”
# Rename eth1 with eth0    
echo “Stopping network”
service network stop

#Clearing devices and renaming
echo “UDEV Config…”
rm -f /etc/udev/rules.d/70-persistent-net.rules
#ls -l  /etc/udev/rules.d/70-persistent-net.rules
udevadm trigger
sleep 2
#ls -l  /etc/udev/rules.d/70-persistent-net.rules
ifdevs=`udevadm info –export-db | grep “INTERFACE=eth” | cut -d “=” -f2`
#echo “Interfaces ${ifdevs}”
count=0
for ifdev in ${ifdevs}; do
sed -i -e “s/${ifdev}/eth${count}/g” /etc/udev/rules.d/70-persistent-net.rules
# echo “sed -i -e ‘s/${ifdev}/eth${count}/g’ /etc/udev/rules.d/70-persistent-net.rules”
count=$((count+1))
# echo “count: ${count}”
done
udevadm trigger –attr-match=subsystem=net
#echo “udev Net rules”
#grep eth /etc/udev/rules.d/70-persistent-net.rules
    echo “—————————————————“
    
#Clearing configuration    
echo “Remove previous configuration”
for cfgfile in `ls /etc/sysconfig/network-scripts/ifcfg-eth*`; do
read -r -p “Remove previous configuration file ${cfgfile}? [y/N] ” response
case $response in
[yY])
rm -f ${cfgfile}
;;
*)
echo “Not removing ${cfgfile}”
;;
esac
done
    
#Setup ehternet devices
sleep 2
ifaces=`ifconfig -a | grep eth | awk ‘{ print $1}’`
#echo ${ifaces}
for iface in ${ifaces}; do
read -r -p “Do you want to configure a static IP for ${iface}? [y/N] ” response
case $response in
[yY])
static
;;
*)
read -r -p “Do you want to configure DHCP for ${iface}? [y/N] ” respdhcp
case $respdhcp in
[yY])
dhcp
;;
*)
echo “Not configuring ${iface}.”
#rm -r /etc/sysconfig/network-scripts/ifcfg-${iface}
;;
esac
;;
esac
done
#Start networking
echo “Starting networking”
service network start
fi