HostsEntry

Here is a component that manages entries in /etc/hosts. I use this to satisfy prerequisites for various other components.
One benefit to using a component for this code is that you can look at a host through N1SPS, and see if this component has been installed, or you can look at the component and see where it is installed in the environment. You can also see the values that were used for the variables. All this without touching the system.



<?xml version="1.0" encoding="UTF-8"?>

<!-- generated by N1 SPS -->
<component
platform='system#Solaris - any version'
xmlns='http://www.sun.com/schema/SPS'
name='HostsEntryCT' version='5.2'
description='Backing component for HostEntry component type'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
softwareVendor='Sun Microsystems'
path='/com/sun/tools/types'
xsi:schemaLocation='http://www.sun.com/schema/SPS component.xsd'
installPath=":[installPath]"
>

<varList>
<var name="host" default="" prompt="Hostname of host to add"/>
<var name="ip" default="" prompt="IP address of host to add"/>
<var name="alias" default="" prompt="one or more space separated aliases for the host (ex: hostname.domainname)"/>
<var access='PRIVATE' modifier='FINAL' name="installName" default='HostsEntry-:[host]-:[ip]'/>
<var access='PRIVATE' modifier='FINAL' name='installPath' default=':[target(/):sys.raDataDir]:[/]com.sun.tools:[/]hosts_entries' prompt='Path where component will be installed'></var>
<var access='PRIVATE' name='hostsFile' default='/etc/inet/hosts' prompt='Location of local hosts file' modifier="FINAL"></var>
<var access='PRIVATE' default='/usr/bin/getent' name='getent' modifier='FINAL'></var>
</varList>
<installList>
<installSteps returns='true' name='default'>
<paramList>
<param name="forceNewEntry" displayMode="BOOLEAN" prompt="Set to true to overwrite existing entry for hostname or IP address"/>
</paramList>
<varList>
<var name="returnStatus" default=""/>
</varList>
<if>
<condition>
<or>
<equals value1=":[host]" value2=""/>
<equals value1=":[ip]" value2=""/>
</or>
</condition>
<then>
<raise message="Value of host and IP must be non-NULL"/>
</then>
</if>

<execNative userToRunAs='root'>
<assignStatus varName="returnStatus"/>
<inputText><![CDATA[

host=":[host]"
ip=":[ip]"
hostAliases=":[alias]"
forceNewEntry=":[forceNewEntry]"
DATESTAMP="`date +%m%d%y%H%M%S`"
tmp=`getent hosts $host`
hostFound=$?
ray1=( $tmp )
tmp=`getent hosts $ip`
ipFound=$?
ray2=( $tmp )
echo "hostFound = $hostFound"
echo "ipFound = $ipFound"
echo "host1 = ${ray1[1]}, ip1 = ${ray1[0]}"
echo "host2 = ${ray2[1]}, ip2 = ${ray2[0]}"

if [[ ($hostFound == 0 && $ipFound == 0) && ((${ray1[0]} == ${ray2[0]}) && (${ray1[1]} == ${ray2[1]})) ]] ; then
# Don't need to do anything. Entry is correct.
echo "Entry already exists and matches."
exit 0
fi
if [[ "$hostFound" == "0" || "$ipFound" == "0" ]] ; then
# Need to check the forceNewEntry flag
if [[ "$forceNewEntry" == "true" ]] ; then
# Need to add the entry
if [[ $hostFound == 0 && $ipFound == 0 ]] ; then
cat /etc/inet/hosts | sed -e "/${ray1[0]}[ \\t]\*${ray1[1]}[ \\t#]/d" > /tmp/hosts.$$.interim2
cat /tmp/hosts.$$.interim2 | sed -e "/${ray2[0]}[ \\t]\*${ray2[1]}[ \\t#]/d" > /tmp/hosts.$$.interim

elif [[ $hostFound == 0 ]] ; then
cat /etc/inet/hosts | sed -e "/${ray1[0]}[ \\t]\*${ray1[1]}[ \\t#]/d" > /tmp/hosts.$$.interim

else [[ $ipFound == 0 ]]

cat /etc/inet/hosts | sed -e "/${ray2[0]}[ \\t]\*${ray2[1]}[ \\t#]/d" > /tmp/hosts.$$.interim
fi

cp /etc/inet/hosts /etc/inet/hosts.$DATESTAMP
echo "Forced change of :[hostsFile] entry for :[host]"
echo "$ip $host $hostAliases # Added by N1SPS $DATESTAMP" >> /tmp/hosts.$$.interim
cp /tmp/hosts.$$.interim :[hostsFile]
rm /tmp/hosts.$$.\*
exit 0
else
# Fail
echo "Entry for either host or IP exists. Use forceNewEntry flag to overwrite."
exit 1
fi
fi
# Need to add the entry
cp :[hostsFile] :[hostsFile].$DATESTAMP
cp :[hostsFile] /tmp/hosts.$$.interim
echo "$ip $host $hostAliases # Added by N1SPS $DATESTAMP" >> /tmp/hosts.$$.interim
cp /tmp/hosts.$$.interim :[hostsFile]
rm /tmp/hosts.$$.interim
exit 0


]]></inputText>
<exec cmd='/bin/bash'>
<arg value='-x'></arg>
</exec>
</execNative>
<return value=":[returnStatus]"/>
</installSteps>
<installSteps name="markOnly">
<paramList>
<param name="forceInstall" default="false" prompt="Force install if no matching entry" displayMode="BOOLEAN"/>
</paramList>

<if>
<condition>
<or>
<equals value1=":[host]" value2=""/>
<equals value1=":[ip]" value2=""/>
</or>
</condition>
<then>
<raise message="Value of host and IP must be non-NULL"/>
</then>
</if>
<try>
<block>

<execNative userToRunAs='root'>

<inputText><![CDATA[

host=":[host]"
ip=":[ip]"
hostAliases=":[alias]"
forceInstall=":[forceInstall]"

if [[ "$forceInstall" == "true" || "$forceInstall" == "TRUE" ]] ; then
exit 0
fi
tmp=`getent hosts $host`
hostFound=$?
ray1=( $tmp )
tmp=`getent hosts $ip`
ipFound=$?
ray2=( $tmp )
echo "hostFound = $hostFound"
echo "ipFound = $ipFound"
echo "host1 = ${ray1[1]}, ip1 = ${ray1[0]}"
echo "host2 = ${ray2[1]}, ip2 = ${ray2[0]}"

if [[ ($hostFound == 0 && $ipFound == 0) && ((${ray1[0]} == ${ray2[0]}) && (${ray1[1]} == ${ray2[1]})) ]] ; then
# Don't need to do anything. Entry is correct.
echo "Entry already exists and matches."
exit 0
fi
]]>
</inputText>
<exec cmd='/bin/bash'>
<arg value='-x'></arg>
</exec>
<successCriteria status="0"/>
</execNative>
</block>
<catch>
<raise message="markOnly install failed because no matching hosts entry was found. Use the forceInstall parameter, or the default install control."/>
</catch>
</try>

</installSteps>
</installList>
<uninstallList>
<uninstallSteps returns='true' name='default'>

<varList>
<var name="returnStatus" default=""/>
</varList>

<execNative userToRunAs='root'>
<assignStatus varName="returnStatus"/>
<inputText><![CDATA[

host=":[host]"
ip=":[ip]"

DATESTAMP="`date +%m%d%y%H%M%S`"
cp :[hostsFile] :[hostsFile].$DATESTAMP
cat :[hostsFile].$DATESTAMP | sed -e "/:[ip][ \\t]\*:[host][ \\t#]/d" > :[hostsFile]
exit 0


]]></inputText>
<exec cmd='/bin/bash'>
<arg value='-x'></arg>
</exec>
</execNative>
<return value=":[returnStatus]"/>
</uninstallSteps>
<uninstallSteps name="markOnly"></uninstallSteps>
</uninstallList>
</component>

Let's take a look at what's going on here...
The varList defines the host (name), ip address, and one or more aliases to be added to the /etc/hosts file. It also defines some variables that are used within N1SPS to help with the component installation.

<varList>
<var name="host" default="" prompt="Hostname of host to add"/>
<var name="ip" default="" prompt="IP address of host to add"/>
<var name="alias" default="" prompt="one or more space separated aliases for the host (ex: hostname.domainname)"/>
<var access='PRIVATE' modifier='FINAL' name="installName" default='HostsEntry-:[host]-:[ip]'/>
<var access='PRIVATE' modifier='FINAL' name='installPath' default=':[target(/):sys.raDataDir]:[/]com.sun.tools:[/]hosts_entries' prompt='Path where component will be installed'></var>
<var access='PRIVATE' name='hostsFile' default='/etc/inet/hosts' prompt='Location of local hosts file' modifier="FINAL"></var>
<var access='PRIVATE' default='/usr/bin/getent' name='getent' modifier='FINAL'></var>
</varList>

The installList defines the various installation controls that you can run. I use a default install control, and you would generally find a "markOnly" install control. The markOnly install typically only removes the component from the host from an N1SPS context rather than performing any actions on the target system. This is sort of a failsafe incase your default uninstall action doesn't work. The default install control does a few things to ensure that we don't do something silly like blanket overwrite an existing entry. There is a "forceNewEntry" parameter that determines if you would like to overwrite an entry. It also checks to make sure that values were set for the host and ip variables (however, it doesn't currently check to see if they are valid). Once that is done, it enters an "execNative" block. The execNative is a way to call out to the OS with some native shell or command. In the execNative, I do a getent to see if the host or ip already exists in one of the configured name services. If so, I check the forceNewEntry value to determine if I should proceed. If so, a backup copy of /etc/hosts is made, and the entry is added. The "markOnly" install is useful if you already have an entry, but you want to sync your component landscape with reality, or you will be adding an entry later via another mechanism. It doesn't do anything other than check for non-null values, and install the component. The default uninstall makes a backup, and deletes the appropriate line using sed. The "markOnly" uninstall just removes the component from the system without modifying /etc/hosts.

Comments:

Post a Comment:
Comments are closed for this entry.
About

This is a space for me to post things I am thinking about. Most content will be related to datacenter operations and automation.

Search

Top Tags
Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today