<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>second phase &#187; Work</title>
	<atom:link href="http://www.phase2.net/category/work/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.phase2.net</link>
	<description>confessions of a geek</description>
	<lastBuildDate>Fri, 06 Jan 2012 19:51:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>HP SA &#8211; Client Side Software Policy Installs</title>
		<link>http://www.phase2.net/2011/12/hp-sa-client-side-software-policy-installs/</link>
		<comments>http://www.phase2.net/2011/12/hp-sa-client-side-software-policy-installs/#comments</comments>
		<pubDate>Thu, 08 Dec 2011 07:44:56 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Opsware]]></category>
		<category><![CDATA[Scripts]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=1556</guid>
		<description><![CDATA[Seems about the only time I post here now is to put up another script.  I really should figure out a nice little script listing page, but I find myself &#8230; <a class="more" href="http://www.phase2.net/2011/12/hp-sa-client-side-software-policy-installs/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>Seems about the only time I post here now is to put up another script.  I really should figure out a nice little script listing page, but I find myself too busy playing Skyrim when I have any free time nowadays!</p>
<p>The following script is intended to be placed on your clients.  It allows you to search for a software policy to install, as well as for the host you wish to install it on.  If you don&#8217;t specify a host, it&#8217;ll just install locally.  It should work on HP SA 7.86 and up.</p>
<p>&nbsp;</p>
<p>Here&#8217;s the usage:</p>
<pre class="code">install_policy.py -u USER [ -p PASSWORD ] -s POLICY [ --host HOSTNAME ]</pre>
<p>&nbsp;</p>
<p>And the script:</p>
<pre class="code">I've taken down the script for a day or so while I rewrite it! The host I develop on uses a python 2.4 binary for the agent and the script isn't compatible with the much more common 1.5.2 binary that comes with SA</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2011/12/hp-sa-client-side-software-policy-installs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Here&#8217;s an SA quickie</title>
		<link>http://www.phase2.net/2011/08/heres-an-sa-quickie/</link>
		<comments>http://www.phase2.net/2011/08/heres-an-sa-quickie/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 20:10:47 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[opsware]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=1502</guid>
		<description><![CDATA[Not going to explain this one much &#8211; basically got asked by a coworker to write up a script real quick for him to update the Deployment Stage against every &#8230; <a class="more" href="http://www.phase2.net/2011/08/heres-an-sa-quickie/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>Not going to explain this one much &#8211; basically got asked by a coworker to write up a script real quick for him to update the Deployment Stage against every system in a device group.</p>
<pre class="brush:py">#!/opt/opsware/agent/bin/python

import sys
sys.path.append("/opt/opsware/pylibs")
sys.path.append("/opt/opsware/agent/pylibs")

from pytwist import *
from pytwist.com.opsware.device import DeviceGroupRef

ts = twistserver.TwistServer()
ds = ts.device.DeviceGroupService
ss = ts.server.ServerService

# Enter your username and password here
ts.authenticate("username","password")

# Enter the device group object ID for the group you want to iterate over
# You can get this object ID from the GUI
dgref = DeviceGroupRef(#######)
srefs = ds.getDevices(dgref)
for sref in srefs:
    svo = ss.getServerVO(sref)
    print "Updating %s" % svo.name
    # Set the stage.  This has to be a valid option - these are always in caps.
    svo.stage = "PRODUCTION"
    ss.update(sref, svo, 0, 0)</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2011/08/heres-an-sa-quickie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HP SA &#8211; Running a known script from pytwist</title>
		<link>http://www.phase2.net/2011/08/hp-sa-running-a-known-script-from-pytwist/</link>
		<comments>http://www.phase2.net/2011/08/hp-sa-running-a-known-script-from-pytwist/#comments</comments>
		<pubDate>Tue, 16 Aug 2011 20:06:04 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[opsware]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=1497</guid>
		<description><![CDATA[I was asked to put up a script that displays an easy way to find a script reference and then start that script. One thing to realize is that the &#8230; <a class="more" href="http://www.phase2.net/2011/08/hp-sa-running-a-known-script-from-pytwist/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>I was asked to put up a script that displays an easy way to find a script reference and then start that script. One thing to realize is that the hardest part about the pytwist API, besides some of the obscure functions, is actually finding your references so that you can get the objects to work on.</p>
<p>There are a few ways you can go around doing this. You can use filters and the search capability, you can manually create your ref, or you can find the refs via other objects, like device groups. The last one I mentioned is actually a very good way to loop through a set of systems to perform a task.</p>
<p>I&#8217;ll display the first method in this article and write up the other two later.</p>
<p>The first thing we need to do is get our script reference. Every object you work with in SA generally has a reference object and what I call the &#8216;virtual object&#8217; ( or whatever VO really stands for ). The VO contains all the important attributes where as the reference only contains the id of the object in SA and the name. There are some methods contained in the VO, but the pytwist API makes common use of a &#8216;Service&#8217; interface for specific types of objects, like the ServerService, the ServerScriptService, the SearchService, JobService, DeviceGroupService and so on that contain the methods that really make use of the VOs.</p>
<p>This first script enables us to run a known SA script on a known host thru SA from a command line. Note that the command line can be any host that has an agent &#8211; this doesn&#8217;t need to be run from the core.</p>
<p>I&#8217;ll show the script first, then explain it. This script is a version that can be run from an agent that has the Python 2 API Access for Server module installed.</p>
<pre class="brush:py">import sys
from optparse import OptionParser
from getpass import getpass
sys.path.append('/opt/opsware/smopylibs2')
sys.path.append('/opt/opsware/agent_tools/') 

import agenttools_common
from pytwist import *
from pytwist.com.opsware.server import ServerRef
from pytwist.com.opsware.script import ServerScriptRef
from pytwist.com.opsware.custattr import NoSuchFieldException

ts = twistserver.TwistServer()

ss = ts.server.ServerService
scs = ts.script.ServerScriptService

# This is the same basic authentication scheme used in most of
# my scripts.  You can tear this out and just use the
# ts.authenticate method with the values already filled in.
parser = OptionParser()
parser.add_option("-u","--user",dest="sauser",
                  help="SA login id")
parser.add_option("-p","--pass",dest="sapasswd",
                  help="SA login password")
parser.add_option("-r","--prompt",action="store_true",dest="readstdin",
                  help="Prompt for passwords instead of using arguments")

(options, args) = parser.parse_args()

if not options.sapasswd and not options.readstdin:
        print "You must specify a password to login to SA."
        sys.exit(1)

if not options.sauser:
        print "You must specify a username to login to SA."
        sys.exit(1)

if options.readstdin:
    options.sapasswd = getpass("Enter Opsware Password: ")

ts.authenticate(options.sauser, options.sapasswd)

# Now the real work starts

# Create a reference to a script we know the ID of
# The ID can be obtained from the SA Gui
scriptRef = ServerScriptRef(22530102)

# Create a reference to a server we know about
serverRef = ServerRef(730102)

# In order to run the script, we'll use the startServerScript method
# from the ServerScriptService.  It requires the script ref, an arugments
# object.  We can optionally give it a tag that it will put under
# the ticket ID.  There are also optional arguments for a job notification
# and job schedule that I won't cover here.
#
# We have the reference already, so we need to create the job argument
# object.  We only need to set the list of targets, although there are
# options for setting the username and password of the script

# Creates the object
scriptArgs = com.opsware.script.ServerScriptJobArgs()

# Requires a list of scriptableRefs, which can be ServerRefs,
# DeviceGroupRefs or HypervisorRefs.  In our case, ServerRefs
scriptArgs.targets = [serverRef]

# Now we can run the job
runScript = scs.startServerScript(scriptRef, scriptArgs, 'Ticket ID #001', None, None)
print "Job started as id %d" % runScript.id</pre>
<p>So, besides the basic authentication and argument parsing, there isn&#8217;t too much to this script. We have to create the references needed and we do that by importing the references in from pytwist and then using them as constructors like so:</p>
<pre class="brush:py">from pytwist.com.opsware.server import ServerRef
from pytwist.com.opsware.script import ServerScriptRef
...
scriptRef = ServerScriptRef(22530102)
serverRef = ServerRef(730102)</pre>
<p>In order to run the script, we need to call the startServerScript, which is part of the ServerScriptService interface. But, in order to call it, we need to create one more object, the ServerScriptJobArgs object. We create the object by calling the constructor directly:</p>
<pre class="brush:py">scriptArgs = com.opsware.script.ServerScriptJobArgs()</pre>
<p>You should note that we could have done the same things with the ServerRef and ScriptRef constructors. Instead of importing them and then calling them, we could have simply done this:</p>
<pre class="brush:py">scriptRef = com.opsware.script.ScriptRef(22530102)
serverRef = com.opsware.server.ServerRef(730102)</pre>
<p>Generally I&#8217;m using alot of server refs, so I like to import to save on typing. Either way, we now have a blank ServerScriptJobArgs object that we need to fill. In our case, we only need to fill out the targets attribute, which is actually a list of any Scriptable Ref. This tells our script which targets it&#8217;s going to run on. As mentioned in the comments, a scriptable reference is either a DeviceGroupRef, a ServerRef or a HypervisorRef. Since we have a ServerRef, we just need to contain it in a list and assign it to the targets attribute:</p>
<pre class="brush:py">scriptArgs.targets = [serverRef]</pre>
<p>Everything is setup now, so I can just call the startServerScript method. The method takes 5 arguments, 3 of which are optional. The 3 optional requires are a ticket id tag, a job notification object and a job schedule object. The ticket id tag is just a string, so it&#8217;s easy to create but I&#8217;m not going to bother with the other two, so our call looks like this:</p>
<pre class="brush:py">runScript = scs.startServerScript(scriptRef, scriptArgs, 'Ticket ID #001'
, None, None)</pre>
<p>Remember that the &#8216;scs&#8217; is just a shortcut to the ServerScriptService. We could have called this method another way:</p>
<pre class="brush:py">runScript = scs.startServerScript(scriptRef, scriptArgs, 'Ticket ID #001', None, None)</pre>
<p>Again, I prefer the former just to save on typing if I plan on using the service multiple times. The method returns a Run Server Script instance, which we can do other things with, but that&#8217;ll have to wait for another article. In the example, I print out the job ID so that I can find and verify the job in the GUI easily.</p>
<p>That&#8217;s it for now &#8211; in the next article I&#8217;ll show how you can use the filter to give the user a way to specify the name of the script they want to run and on which servers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2011/08/hp-sa-running-a-known-script-from-pytwist/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>HP SA &#8211; Finding offline agents</title>
		<link>http://www.phase2.net/2011/07/hp-sa-finding-offline-agents/</link>
		<comments>http://www.phase2.net/2011/07/hp-sa-finding-offline-agents/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 22:49:25 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=1492</guid>
		<description><![CDATA[A common issue we experience is that agents often go offline in the SA console. Whether it is because the admin of the system screwed up a gateway, shutdown the &#8230; <a class="more" href="http://www.phase2.net/2011/07/hp-sa-finding-offline-agents/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>A common issue we experience is that agents often go offline in the SA console. Whether it is because the admin of the system screwed up a gateway, shutdown the server without deactivating it from SA or for one of a hundred other reasons it may happen, when you have 20,000+ devices in SA, it becomes painful to track them. Pile on that we don&#8217;t want to track every single offline agent, just ones that have been offline for awhile, meaning the agent has some type of an permanent issue, rather than occasionally flapping.</p>
<p>For our solution, we wrote up the following simple python script to do the job for us.</p>
<pre class="brush:py">import sys
import time
import smtplib
from email.MIMEText import MIMEText
from optparse import OptionParser
from getpass import getpass
sys.path.append('/opt/opsware/smopylibs2')
sys.path.append('/opt/opsware/agent_tools/') 

import agenttools_common
from pytwist import *
from pytwist.com.opsware.search import Filter
from pytwist.com.opsware.server import ServerRef

ts = twistserver.TwistServer()
ses = ts.search.SearchService
ss = ts.server.ServerService
DAY = 86400

parser = OptionParser()
parser.add_option("-u","--user",dest="sauser",
                  help="SA login id")
parser.add_option("-p","--pass",dest="sapasswd",
                  help="SA login password")
parser.add_option("-r","--prompt",action="store_true",dest="readstdin",
                  help="Prompt for passwords instead of using arguments")
parser.add_option("-c","--customer",dest="customer",
                  help="Customer name to search for")
parser.add_option("-d","--days",dest="days",
                  help="Expiration limit in days")

(options, args) = parser.parse_args()

if not options.customer:
        print "You must specify a customer to search for."
        sys.exit(1)

if not options.sapasswd and not options.readstdin:
        print "You must specify a password to login to SA."
        sys.exit(1)

if not options.sauser:
        print "You must specify a username to login to SA."
        sys.exit(1)

if options.readstdin:
    options.sapasswd = getpass("Enter Opsware Password: ")

ts.authenticate(options.sauser, options.sapasswd)

filt = Filter()
filt.objectType = 'device'
filt.expression = "(ServerVO.state = UNREACHABLE) &amp; " \
                  "(ServerVO.opswLifecycle != DEACTIVATED)  " \
                  "(device_customer_name = %s)" % options.customer

offline_servers = ses.findObjRefs(filt)
expired_servers = []

if len(offline_servers) == 0:
    print 'There are no unreachable servers'
    sys.exit(0)
else:
    print "Processing %d servers" % len(offline_servers)

now = int(time.time())
for sref in offline_servers:
    shvo = ss.getServerHardwareVO(sref)
    beginDate = shvo.beginDate
    if (now - int(beginDate)) &gt;= (DAY * int(options.days)):
        server_data = [sref.id, sref.name, beginDate]

        # this sorts the list.  if you don't care about
        # sorting, remove this section.

        # sort while create - could have sorted
        # after create, which would probably been
        # faster, but this was an educational exercise

        # if the list is blank, just append
        if len(expired_servers) == 0:
            expired_servers.append(server_data)
            continue

        # place it in the correct spot
        inserted = None
        for i in range(0,len(expired_servers)):
            if beginDate &lt; expired_servers[i][2]:
                expired_servers.insert(i,server_data)
                inserted = 1
                break

        if not inserted:
            expired_servers.append(server_data)
        # end of sorting

        # if you don't sort, then just uncomment this line
        # expired_servers.append(server_data)

if len(offline_servers) == 0:
    print "All unreachable servers have not been offline for more than %s" \
          "days" % options.days
    sys.exit(0)

report = "\r\n\r\nThe following servers have not registered for more than %s " \
         "days.\r\n\r\n" % options.days

for server in expired_servers:
    datestr = "%s/%s/%s %s:%s:%s" % time.gmtime(float(server[2]))[0:6]
    report += "%s : %s has not registered since %s.  \r\n" % \
            (server[0],server[1],datestr)

# If you want output to the screen
print report

# Create a text/plain message
msg = MIMEText(report)

sender = "root@example.com"
rcptto = ["user1@example.com", "user2@example.com"]
msg['Subject'] = "[opsware] Offline Servers for %s" % options.customer
msg['From'] = sender
msg['To'] = ",".join(rcptto)

# Send the message via our own SMTP server, but don't include the
# envelope header.
s = smtplib.SMTP('localhost')
s.sendmail(sender, rcptto, msg.as_string())
s.quit()</pre>
<p>A couple of notes are probably in order. First, this was written for our environment, so it may require some massaging to get it to work in your own. The multiple &#8216;/r/n&#8217; tags are so that it shows up in Outlook correctly and not as a huge, one line mess. By default, the script will sort by date. There are some comments in there if you&#8217;d like to remove that functionality.</p>
<p>We wanted to be able to run this from any agent, rather than from the cores, so that our internal groups that use SA could run this if they chose to. It only requires that the agent tools and the Python 2 API for Server Modules packages be installed.</p>
<p>To run, use something like the following:</p>
<pre class="terminal">/opt/opsware/smopython2/python ./offline.py -u username -p password -d 30 -c customername</pre>
<p>Make sure to change the bottom of the script to have the email addresses you&#8217;d like to use and then just cron the script.</p>
<p>Comments welcome.</p>
<p>( Thanks to <a href="http://www.stuckincustoms.com">Trey Ratcliffe</a> for the use of the photo used on the header of this post. )</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2011/07/hp-sa-finding-offline-agents/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Opsware Custom Attributes and You.</title>
		<link>http://www.phase2.net/2010/03/opsware-custom-attributes-and-you/</link>
		<comments>http://www.phase2.net/2010/03/opsware-custom-attributes-and-you/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 22:01:36 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Work]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[opsware]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=1027</guid>
		<description><![CDATA[I realize most of the time I end up complaining about Opsware &#8211; that&#8217;s generally because it&#8217;s part of the human condition.  We say stuff when we&#8217;re upset or angry &#8230; <a class="more" href="http://www.phase2.net/2010/03/opsware-custom-attributes-and-you/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>I realize most of the time I end up complaining about Opsware &#8211; that&#8217;s generally because it&#8217;s part of the human condition.  We say stuff when we&#8217;re upset or angry or don&#8217;t like something.  How many times have you ever called up the phone company to tell them &#8216;Great job!&#8217;</p>
<p>Yeah, I thought so.</p>
<p>So I figured I&#8217;d write an article on one of the great things I love about Opsware &#8211; Custom Attributes! Combined with Dynamic Groups, these puppies provide the ability to create scripts that I don&#8217;t have to duplicate for different hosts.</p>
<p>First, however, I should explain what Dynamic Groups are.  Dynamic Groups allow the user to group systems based on certain criteria.  For instance, you want all the systems in a certain network to be grouped together.  Whenever you add a system from that network into Opsware, it automatically becomes a member of that group.  Neat by itself but nothing extraordinary.</p>
<p>However, you can assign Custom Attributes ( further known as CAs ) to the Dynamic Group.  So for my new dynamic group that I created ( for example, a group that pulls in all hosts in the 192.168.0.0/24 network ), I can assign some CAs to the group and the CAs get assigned to each host within the group.</p>
<p>You may ask yourself, &#8216;Why is this useful?&#8217;.  It&#8217;s not yet.  There&#8217;s one more piece that&#8217;s missing from the puzzle.  The piece that is missing is a software package that Opsware comes with &#8211; Agent Tools.  When you install the Agent Tools, it comes with a set of python Opsware APIs and small scripts that use the API to make calls back to the master Opsware system and get information &#8211; including those CAs!</p>
<p>Armed with these 3 pieces, it becomes easy to create a script that uses the CAs that are dynamically assigned to your host to do all sorts of things.  For example, let&#8217;s say you want to create a script that checks your /etc/resolv.conf on any system in that 192.168.0.0/24 network.  First, we&#8217;ll create the dynamic group and assign it the correct device membership.</p>
<p>Next, edit the group and add a CA named something like &#8216;<strong>DNS_SERVERS</strong>&#8216;.  For the value, put in a DNS server on separate lines and then save your group.  Make sure you&#8217;ve got the agent tools package installed and we can run a simple test.</p>
<pre class="terminal">[root@frenzy1a.star.dev:~]# /opt/opsware/agent_tools/get_cust_attr.sh DNS_SERVERS
192.168.0.20
192.168.0.21</pre>
<p>With that information, we can create a pretty simple shell or python script ( pick your poison ) to make sure that our /etc/resolv.conf has those servers defined.  For kicks, here&#8217;s an example script that checks to make sure the IPs in the <strong>DNS_SERVERS</strong> CA are set in /etc/resolv.conf.  You could easily modify this so that it actually inserts the values.</p>
<pre class="brush:py">#!/opt/opsware/agent/bin/python

import sys
sys.path.append('/opt/opsware/agent_tools/')
import agenttools_common
import re
from string import split
from pytwist.com.opsware.custattr import NoSuchFieldException

def searchFile(file,pattern):
    found = 0
    search = re.compile(pattern)
    try:
        f = open(file, "r")
    except IOError:
        sys.stderr.write("Could not open file %s.n" % (file))
        sys.exit(3)

    for line in f.readlines():
        if search.match(line):
            found = 1
        break

    return found

def main(args):
    ts = agenttools_common.ts
    servers = {}
    result = 0
    hostref = agenttools_common.getServerRef()

    try:
        custattr = ts.server.ServerService.getCustAttr(hostref,
        "DNS_SERVERS", 1)
    except NoSuchFieldException:
        sys.stderr.write("Could not find custom attribute DNS_SERVERS.n")
        sys.exit(3)

    servers = split(custattr)
    for s in servers:
        found = searchFile("/etc/resolv.conf","^nameservers+" + s)
        if not found:
            sys.stderr.write("The server %s was not configured in"
            " /etc/resolv.conf" % (s))
        result = 1

    return result

if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))</pre>
<p>Now if I have another network, say, 192.168.120.0/24, I can do the same thing.  Make the group, assign the membership, create the <strong>DNS_SERVERS</strong> CA and assign the script and presto &#8211; it&#8217;s done! No duplication of work involved here and I can control the contents of the file from the Opsware console.</p>
<p>One last thing about CAs &#8211; they do support overrides.  For instance, I can override the CA by creating the same named CA on the host itself.  This will override the CA at the group level.  One thing you need to be careful, however, is that you don&#8217;t assign a host into two groups that define the same CA &#8211; there&#8217;s no priority between the groups and they don&#8217;t combine the contents of the CA to make one CA, so you&#8217;ll get random results.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2010/03/opsware-custom-attributes-and-you/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Restarting Cisco VPN Subsystem on OS X</title>
		<link>http://www.phase2.net/2009/06/restarting-cisco-vpn-subsystem-on-os-x/</link>
		<comments>http://www.phase2.net/2009/06/restarting-cisco-vpn-subsystem-on-os-x/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 06:39:14 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[cisco]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[vpn]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=1014</guid>
		<description><![CDATA[If you&#8217;re like me and you use your MacBook Pro for work, it might stand to reason that you have to VPN into your work network. If so, it also &#8230; <a class="more" href="http://www.phase2.net/2009/06/restarting-cisco-vpn-subsystem-on-os-x/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re like me and you use your MacBook Pro for work, it might stand to reason that you have to VPN into your work network. If so, it also may be a good chance that you use the Cisco VPN client and have run into this annoying message:</p>
<p><strong>Error 51: Unable to communicate with the VPN subsystem</strong></p>
<p>Thankfully, the solution is rather simple. Open up your favorite terminal client and simply type:</p>
<pre class="terminal">sudo /System/Library/StartupItems/CiscoVPN/CiscoVPN restart</pre>
<p>Enter your password and it&#8217;ll restart the subsystem. Then just re-open the Cisco VPN client and you&#8217;re golden.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2009/06/restarting-cisco-vpn-subsystem-on-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gitorious setup: RSTRING_LEN in rdiscount</title>
		<link>http://www.phase2.net/2009/06/gitorious-setup-rstring_len-in-rdiscount/</link>
		<comments>http://www.phase2.net/2009/06/gitorious-setup-rstring_len-in-rdiscount/#comments</comments>
		<pubDate>Tue, 02 Jun 2009 22:29:20 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Unix]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=983</guid>
		<description><![CDATA[Ran into an issue recently where I was trying to install gitorious on a local RHEL5 system. The site would crash every time I tried to view a repo with &#8230; <a class="more" href="http://www.phase2.net/2009/06/gitorious-setup-rstring_len-in-rdiscount/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>Ran into an issue recently where I was trying to install gitorious on a local RHEL5 system.  The site would crash every time I tried to view a repo with the error:</p>
<pre class="terminal">
ruby: symbol lookup error: /usr/lib64/ruby/gems/1.8/gems/rdiscount-1.3.1.1/lib/rdiscount.so: undefined symbol: RSTRING_LEN
</pre>
<p>The solution ended up being the following &#8211; In the file <strong>/usr/lib64/ruby/1.8/x86_64-linux/ruby.h</strong> ( note I&#8217;m running on 64bit, on 32bit it&#8217;d be /usr/lib/ruby/1.8/i386-linux/ ), add these lines somewhere near the top:</p>
<pre class="terminal">
#define RSTRING_LEN(s) (RSTRING(s)->len)
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
</pre>
<p>After that, uninstall and reinstall rdiscount</p>
<pre class="terminal">
gem uninstall rdiscount
gem install rdiscount -v 1.3.1.1
</pre>
<p>And you should be good to go.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2009/06/gitorious-setup-rstring_len-in-rdiscount/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Gallery tutorial</title>
		<link>http://www.phase2.net/2008/07/wordpress-gallery-tutorial/</link>
		<comments>http://www.phase2.net/2008/07/wordpress-gallery-tutorial/#comments</comments>
		<pubDate>Thu, 24 Jul 2008 03:15:51 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=458</guid>
		<description><![CDATA[Unfortunately, I&#8217;ve lost the code to this during my move from one provider to another. The gallery tutorial here was meant for WordPress 2.5 and is no longer relevant anyways. &#8230; <a class="more" href="http://www.phase2.net/2008/07/wordpress-gallery-tutorial/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p><span style="color: #000000;"><strong>Unfortunately, I&#8217;ve lost the code to this during my move from one provider to another.  The gallery tutorial here was meant for WordPress 2.5 and is no longer relevant anyways.  Thanks for all the comments n it though!</strong></span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2008/07/wordpress-gallery-tutorial/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>AIX &#8211; JFS Recovering a deleted file ( undelete )</title>
		<link>http://www.phase2.net/2008/03/aix-recovering-a-deleted-file-undelete/</link>
		<comments>http://www.phase2.net/2008/03/aix-recovering-a-deleted-file-undelete/#comments</comments>
		<pubDate>Tue, 04 Mar 2008 08:21:45 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Unix]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[aix]]></category>
		<category><![CDATA[jfs]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.phase2.net/2008/03/04/aix-recovering-a-deleted-file-undelete/</guid>
		<description><![CDATA[This is a document I wrote a while back for work that I thought I would release in hopes that some people out there would find it useful. Preferably, you &#8230; <a class="more" href="http://www.phase2.net/2008/03/aix-recovering-a-deleted-file-undelete/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>This is a document I wrote a while back for work that I thought I would release in hopes that some people out there would find it useful.</p>
<p>Preferably, you have a backup of the file system that you can use.  If not, the filesystem you are about to try to to recover a file on must meet these requirements:</p>
<ul>
<li>No new files have been created on the filesystem.</li>
<li>No files have been extended.</li>
<li>The filesystem is able to be unmounted.</li>
<li>It is a JFS filesystem, not JFS2</li>
<li>It is not an overly large file, I&#8217;m not exactly sure on the byte limit</li>
</ul>
<p>If so, then please, drink a few more beers and continue, but before you do&#8230;</p>
<p><strong>BACKUP THE CURRENT FILESYSTEM!</strong><br />
<span id="more-85"></span><br />
Also, note that if you are dealing with a directory that has been deleted and would like to recover both the directory and the files under that directory, you should try Recovering a Deleted Directory ( a document I have yet to post.. ).  It follows many of the same steps, but has some very important differences.  Do not try and use this procedure to recover deleted directories and the files that were contained within them.  You will mess up.</p>
<p>Before we begin, I need to note a few things.  I take no responsibility if this screws up your system.  Use this at your own risk.  Also, the example presented here is an actual representation of me recovering a deleted file, this is not just made up numbers.  Also, this only works on jfs filesystems, not jfs2.  The jfs2 fsdb is much different and I haven&#8217;t had a chance to play with it to determine the proper way of doing this.</p>
<p>Now that I&#8217;ve said that, we can begin.  We&#8217;ll use an example directory with some example files.  Our directory is called <strong>/test</strong> and our filesystem is <strong>testlv</strong>, otherwise known as <strong>/dev/testlv</strong>.  In our example, our Junior System Admin, Myron, has accidentally deleted a perl script called <strong>testfile.pl</strong> and needs to recover it.</p>
<p><strong>Note:</strong> If you are performing this operation on a filesystem while in maintenance mode, do <strong>NOT</strong> use option 1 when asked on how to mount the filesystems.  <strong>ALWAYS</strong> use option 2, which specifies to start a shell before mounting the filesystems.  Otherwise, the system will force a <span class="p2code">fsck -y</span> on the filesystem and delete your files.</p>
<h3>Step 1.</h3>
<p>First, run this command:</p>
<pre class='terminal'>ls -id /test</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>[test:/]# ls -id /test
    2 /test/</pre>
<p>This informs us that the inode for the directory /test is 2.  Record this for future use.</p>
<h3>Step 2.</h3>
<p>Unmount /test</p>
<pre class='terminal'>umount /test</pre>
<p><strong>Output: None</strong></p>
<p>We must unmount the directory.  We don&#8217;t want anyone to try and use it while we are attempting to restore the file.</p>
<h3>Step 3</h3>
<p>Now we&#8217;ll start up the filesystem debugger.</p>
<pre class='terminal'>fsdb /dev/testlv</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>[test:/]# fsdb /dev/testlv

File System:                           /dev/testlv

File System Size:                         193200128  (512 byte blocks)
Disk Map Size:                                 1660  (4K blocks)
Inode Map Size:                                 831  (4K blocks)
Fragment Size:                                 4096  (bytes)
Allocation Group Size:                        16384  (fragments)
Inodes per Allocation Group:                   8192
Total Inodes:                              12075008
Total Fragments:                           24150016</pre>
<p>This starts the filesystem debugger on our testlv filesystem.</p>
<h3>Step 4</h3>
<p>Now we look at our inode number.</p>
<pre class='terminal'>2i</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>2i
i#:      2  md: d-g-rwxr-xr-x  ln:    4  uid:    3  gid:    3
szh:        0  szl:      512  (actual size:      512)
a0: 0x25d       a1: 0x00        a2: 0x00        a3: 0x00
a4: 0x00        a5: 0x00        a6: 0x00        a7: 0x00
at: Mon Jan 10 11:19:17 2005
mt: Mon Jan 10 11:11:26 2005
ct: Mon Jan 10 11:11:26 2005</pre>
<p>The INODE in the command is the inode number we recorded in step #1. This will display the inode information for the directory. The field a0 contains the block number of the directory. The following steps assume only field a0 is used. If a value appears in a1, etc, it may be necessary to repeat steps #5 and #6 for each block until the file to be recovered is found.</p>
<h3>Step 5</h3>
<p>Move to the block</p>
<pre class='terminal'>a0b</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>a0b
0x000025d000  :  0x00000000 (0)</pre>
<p>This moves to the block pointed to by field &#8220;a0&#8243; of this inode.</p>
<h3>Step 6</h3>
<p>Now we need to print out some data.</p>
<pre class='terminal'>p256c</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>p256c

0x000025d000:   � � � ? � ? � ? .  � � � � � � ?
0x000025d010:   � ? � ? .  .  � � � � � ? � ? � n
0x000025d020:   l  o  s  t  +  f  o  u  n  d  � � � � � ?
0x000025d030:   � $  � ? m  e  m  _  r  e  p  o  r  t  _  2
0x000025d040:   0  0  4  1  1  0  1  .  d  m  p  .  g  z  � �
0x000025d050:   � � � ? � s � ? o  r  a  s  c  r  a  t
0x000025d060:   c  h  .  c  p  i  o  .  g  z  � � � � � ?
0x000025d070:   � (  � s u  s  e  r  _  a  c  t  i  v  i  t
0x000025d080:   y  _  2  0  0  4  1  1  0  1  .  d  m  p  .  g
0x000025d090:   z  � � � � � � ? � ,  � !  u  s  e  r
0x000025d0a0:   _  a  c  t  i  v  i  t  y  _  d  e  t  _  2  0
0x000025d0b0:   0  4  1  1  0  1  .  d  m  p  .  g  z  � � �
0x000025d0c0:   � ? `  � ? @  � ? E  C  R  1  X  � � �
0x000025d0d0:   � � � ? ? 0  � ? t  e  s  t  f  i  l  e
0x000025d0e0:   .  p  l  � ?    � a t  e  s  t  d  i  r  �
0x000025d0f0:   j  d  u  c  k  o  .  t  x  t  � � � � � ?</pre>
<p>The command p256c stands for &#8216;print 256 bytes in character mode&#8217;.  You could type &#8216;p128c&#8217; and it would print 128 bytes in character mode and so on.  The beginning left column is the address of the first character in that row.  The important thing in this output is to find which line the file to be recovered is on. Our file ( testfile.pl ) is located on line 0x000025d0d0.  Next, we have to find the address of the first character of our filename.  To do this, starting at 0, count in hexidecimal until you reach the first character of the filename.  In our example, the &#8216;t&#8217; of testfile.pl is at address 0x000025d0d8.  Record this address.</p>
<p>If you cannot find your filename here, issue the command again.  It will print the <strong>next</strong> 256 bytes in character mode.  Do this until you find your filename.</p>
<p>Here&#8217;s a layout to help you in figuring out how we got the address:</p>
<pre class='terminal'><strong>Address:        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F</strong>
0x000025d0d0:   � � � ? ? 0  � ? t  e  s  t  f  i  l  e</pre>
<h3>Step 7</h3>
<p>Reset our position.</p>
<pre class='terminal'>a0b</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>a0b
0x000025d000  :  0x00000000 (0)</pre>
<p>This resets our position back to the beginning of the a0 block.  This is necessary whenever you want to reprint out the byte data.  Remember, however, that if you had to use the &#8216;p&#8217; command many times to find your filename, you will probably have to use it many times each time you reset back to the beginning.</p>
<h3>Step 8</h3>
<p>Print our data in decimal</p>
<pre class='terminal'>p256e</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>p256e

0x000025d000:         0       2      12       1   11776       0       0       2
0x000025d010:        12       2   11822       0       0      16      20      10
0x000025d020:     27759   29556   11110   28533   28260       0       0      17
0x000025d030:        36      26   28005   27999   29285   28783   29300   24370
0x000025d040:     12336   13361   12592   12590   25709   28718   26490       0
0x000025d050:         0      18      28      18   28530   24947   25458   24948
0x000025d060:     25448   11875   28777   28462   26490       0       0      19
0x000025d070:        40      29   30067   25970   24417   25460   26998   26996
0x000025d080:     31071   12848   12340   12593   12337   11876   28016   11879
0x000025d090:     31232       0       0      20      44      33   30067   25970
0x000025d0a0:     24417   25460   26998   26996   31071   25701   29791   12848
0x000025d0b0:     12340   12593   12337   11876   28016   11879   31232       0
0x000025d0c0:        18   24576     320       5   17731   21041   22528       0
0x000025d0d0:         0      21     304      11   29797   29556   26217   27749
0x000025d0e0:     11888   27648     288       7   29797   29556   25705   29184
0x000025d0f0:     27236   30051   27503   11892   30836       0       0      23
0x000025d100:       260      16   27233   28005   29549   24947   29537   29281
0x000025d110:     11892   30836       0       0       0       0       0       0
0x000025d120:         0       0       0       0       0       0       0       0
0x000025d130:         0       0       0       0       0       0       0       0
0x000025d140:         0       0       0       0       0       0       0       0</pre>
<p>The command &#8216;p256e&#8217; stands for &#8216;print 256 bytes in decimal word format&#8217;.  This output can be helpful and confusing at the same time.  First, find the beginning address that our file name is on.  In our example, this was 0x000025d0d0.  The line in decimal format reads:</p>
<pre class='terminal'>0x000025d0d0:         0      21     304      11   29797   29556   26217   27749</pre>
<p>For each file, assume the following:</p>
<pre class='terminal'>  {ADDRESS}:  x    x    x    x    x    x    x    x    x
              |    |    |    |    |---- filename -----|
    inode # --+----+    |    |
                        |    +-- filename length
        record LENGTH --+</pre>
<p>Note that the inode # may begin on any part of the line.  The reason we print the data in decimal format is to help us determine where in the line the inode number is.  There are several ways to help you do this, here are some:</p>
<ul>
<li>Count the number of characters in your filename, then try and find that number in our address line.  ( eg: There are 11 characters in the filename &#8216;testfile.pl&#8217;. )  You can see on our line there is a matching number 11.</li>
<li>Recount to the address 0x000025d0d8, assuming each column represents two numbers.  The first column is 0 and 1.  The second column is 2 and 3, then 4 and 5, etc.  When you reach the column that matches your address, go back one column.  The number in this column should match up with your filename length.  Unless, of course, your filename is over 255 characters.</li>
</ul>
<p>Once you are sure you have the the correct column for your filename length, you are going to count back three more columns.  This should put at the first column of the inode number.  We&#8217;ll use our example decimal line to explain this more:</p>
<pre class='terminal'>0x000025d0d0:         0      21     304      11   29797   29556   26217   27749</pre>
<p>Like we mentioned before, testfile.pl is 11 characters.  We find a matching number 11 in the 4th column.  That means that the column with &#8217;304&#8242; is our record length field and the 0 and 21 columns make up our inode.  Now, that we know which columns our inode is in ( columns 1 and 2 ), we must translate this number into our real inode number.</p>
<h3>Step 9</h3>
<p>Calculate our inode.</p>
<p><strong>Thanks to Arthur Dent for this update</strong></p>
<p>In some cases, our inode number may be a lower number and may not need any special treatment, however, for larger inodes, the information will span columns.</p>
<p>Here&#8217;s an example.  The directory ECR1X is on an address above ours.  Its inode number, like ours, is in columns 1 and 2.  However, if you compare the decimal lines, you can immediately see the difference.</p>
<pre class='terminal'>EC1X Decimal:
0x000025d0c0:      18  24576
testfile.pl Decimal:
0x000025d0d0:       0     21</pre>
<p>To calculate the inode if it spans 2 columns, use the following formula:</p>
<pre class='terminal'>firstcolumn * 65536 + secondcolumn = inode</pre>
<p>In our case, we are not using column 1, so all we need is column 2 from the previous step.  It was <strong>21</strong>, so now we know the inode number of the missing file.  We&#8217;re close to recovery!</p>
<h3>Step 10</h3>
<p>We go to our new inode number</p>
<pre class='terminal'>21i</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>21i
i#:     21  md: f---rw-r--r--  ln:    0  uid:    0  gid:    3
szh:        0  szl:       45  (actual size:       45)
a0: 0xeff       a1: 0x00        a2: 0x00        a3: 0x00
a4: 0x00        a5: 0x00        a6: 0x00        a7: 0x00
at: Mon Jan 10 14:16:40 2005
mt: Mon Jan 10 14:16:48 2005
ct: Mon Jan 10 14:16:53 2005</pre>
<p>From this output, you can see that we have a file.</p>
<h3>Step 11</h3>
<pre class='terminal'>21i.ln=1</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>21i.ln=1
0x0000020a88  :  0x00000001 (1)</pre>
<p>This sets the link count of the file back to 1.  You can verify this by reissuing the command from step #10 and noticing that the &#8216;ln&#8217; field has incremented.</p>
<pre class='terminal'>21i
i#:     21  md: f---rw-r--r--  ln:    1  uid:    0  gid:    3
szh:        0  szl:       45  (actual size:       45)
a0: 0xeff       a1: 0x00        a2: 0x00        a3: 0x00
a4: 0x00        a5: 0x00        a6: 0x00        a7: 0x00
at: Mon Jan 10 14:16:40 2005
mt: Mon Jan 10 14:16:48 2005
ct: Mon Jan 10 14:16:53 2005</pre>
<p>We have now told the filesystem that the link count for inode 21 should be 1.  This means that there should be a filename pointing at this inode.  This basically reverses what the OS actually does when deleting files.  It doesn&#8217;t actually erase the file data, instead, it unlinks the filename from its inode number, effectively preventing you from seeing the data.</p>
<h3>Step 12</h3>
<p>Quit.</p>
<pre class='terminal'>q</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>q
[test:/]#</pre>
<p>This quits out of the fsdb.</p>
<h3>Step 13</h3>
<p>Fsck our volume</p>
<pre class='terminal'>fsck /dev/testlv</pre>
<p><strong>Output:</strong></p>
<pre class='terminal'>[test:/]# fsck /dev/testlv

** Checking /dev/rtestlv (/test)
** Phase 1 - Check Blocks and Sizes
** Phase 2 - Check Pathnames
** Phase 3 - Check Connectivity
** Phase 4 - Check Reference Counts
Unreferenced file  I=21  owner=root mode=100644
size=45 mtime=Jan 10 14:16 2005 ; RECONNECT? y
** Phase 5 - Check Inode Map
Bad Inode Map; SALVAGE? y
** Phase 5b - Salvage Inode Map
** Phase 6 - Check Block Map
Bad Block Map; SALVAGE? y
** Phase 6b - Salvage Block Map
18 files 21893872 blocks 171306256 free
***** Filesystem was modified *****</pre>
<p>This does a filesystem check on /dev/testlv.  As you can see, it finds an inode claiming it is linked to, but no file that links to it.  We answer &#8216;y&#8217; to tell it to reconnect the inode to a filename, effectively giving us our file back!</p>
<h3>Step 14</h3>
<p>Remount our directory.</p>
<pre class='terminal'>mount /test</pre>
<p><strong>Output: None</strong></p>
<p>We must remount our filesystem to get back at our file.</p>
<h3>Step 15</h3>
<p>Go into lost and found. It&#8217;s where all lost little kiddies go.  Duh.</p>
<pre class='terminal'>cd /test/lost+found</pre>
<p><strong>Output: None</strong></p>
<p>Our file is now located in lost+found.  If you do an &#8216;ls&#8217; in this directory, you will see something like the following:</p>
<pre class='terminal'>[test:/test/lost+found]# ls -l
total 8
-rw-r--r--   1 root     sys              45 Jan 10 14:16 21</pre>
<p>And if we cat the file 21, we get the following:</p>
<pre class='terminal'>[test:/test/lost+found]# cat 21
#!/usr/bin/perl

print "this is a testn";</pre>
<p>Ta-da! It&#8217;s Myron&#8217;s missing perl script!</p>
<p>As a final aside, I will say that there may be different and much better ways of recovering files on AIX, however, this is the way I constructed from notes I found on various mailing lists and a few days of fooling around with it.  So if you see some mistakes in this document or have some suggestions for better ways of doing this, please, let me know! I will happily update this document with better information as it is provided.</p>
<p>I hope this helps some of you who have to deal with certain people who accidentally delete files on your systems.  Nothing beats a good backup but when you don&#8217;t have one of those, this can always be used as a fallback.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2008/03/aix-recovering-a-deleted-file-undelete/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>How to rename network adapters in AIX</title>
		<link>http://www.phase2.net/2007/06/how-to-rename-network-adapters-in-aix/</link>
		<comments>http://www.phase2.net/2007/06/how-to-rename-network-adapters-in-aix/#comments</comments>
		<pubDate>Fri, 08 Jun 2007 19:18:01 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Unix]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[aix]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.phase2.net/?p=52</guid>
		<description><![CDATA[It seems that lately all that I&#8217;ve written have been docs on how to do stuff at work. Mostly because I&#8217;ve been busy ( scuba, girlfriend, work, soccer, friends, etc. &#8230; <a class="more" href="http://www.phase2.net/2007/06/how-to-rename-network-adapters-in-aix/">Continue reading</a>]]></description>
			<content:encoded><![CDATA[<p>It seems that lately all that I&#8217;ve written have been docs on how to do stuff at work.  Mostly because I&#8217;ve been busy ( scuba, girlfriend, work, soccer, friends, etc. ) unlike some people I know ( hi pierre ).  Anyways, recently while at work, we found that we wanted to switch the names of some of the network adapters on an AIX machine.  However, this turns out to be a very complicated thing to do.  You cannot just rename them.  I also didn&#8217;t want to mess around with moving the cards around in the machine, rebooting, testing, etc.  I just wanted to fix the damn names.</p>
<p>So I did.  Here&#8217;s how.</p>
<p>First, get all the information about the adapters.</p>
<pre class="terminal">for i in ent0 ent1 ent2
do
odmget -q name="$i" CuDv &gt;&gt; /tmp/$i
odmget -q name="$i" CuAt &gt;&gt; /tmp/$i
odmget -q name="$i" CuVPD &gt;&gt; /tmp/$i
done </pre>
<p>Next, down the interfaces and detach them.</p>
<pre class="terminal">
for i in en0 en1 en2 et0 et1 et2
do
ifconfig $i down
ifconfig $i detach
done </pre>
<p>Now, remove all the references to the devices from the ODM</p>
<pre class="terminal">for i in ent0 ent1 ent2 en0 en1 en2 et0 et1 et2
do
odmdelete -q name="$i" -o CuAt
odmdelete -q name="$i" -o CuDv
odmdelete -q name="$i" -o CuVPD
odmdelete -q value3="$i" -o CuDvDr
done </pre>
<p>We can verify that no adapters and no interfaces exist now by issuing the lsdev commands again. All we should see is the loopback interface.</p>
<pre class="terminalt">lsdev -Cc adapter -l ent*
lsdev -Cc if
</pre>
<pre class="output">lo0 Available       Loopback Network Interface</pre>
<p>Edit the files we created the first step and replace every instance of the adapter name with the new adapter name. For instance, I would edit /tmp/ent0 and replace all instances of &#8220;ent0&#8243; with &#8220;ent2&#8243;. We can do this with a sed script.</p>
<pre class="terminal">sed -e "s/ent0/ent1/g" /tmp/ent0 &gt; /tmp/ent1.new
sed -e "s/ent1/ent2/g" /tmp/ent1 &gt; /tmp/ent2.new
sed -e "s/ent2/ent0/g" /tmp/ent2 &gt; /tmp/ent0.new</pre>
<p>Then add the files back to the ODM.</p>
<pre class="terminal">odmadd /tmp/ent0.new
odmadd /tmp/ent1.new
odmadd /tmp/ent2.new</pre>
<p>At this point, our adapters will now be redefined. Issue another lsdev command to check:</p>
<pre class="terminalt">lsdev -Cc adapter -l ent*</pre>
<pre class="output">ent0 Available 05-08 10/100/1000 Base-TX PCI-X Adapter (14106902)
ent1 Available 07-08 2-Port 10/100/1000 Base-TX PCI-X Adapter (14108902)
ent2 Available 07-09 2-Port 10/100/1000 Base-TX PCI-X Adapter (14108902)</pre>
<p>You can see now that ent0 is now the external PCI-X adapter and ent1 and ent2 are the two onboard adapters. But, we still have no interfaces for the adapters. You can verify this by issuing the usual lsdev command again. You should only see the loopback interface.</p>
<pre class="terminalt">
lsdev -Cc if
</pre>
<pre class="output">lo0 Available       Loopback Network Interface</pre>
<p>To fix this ( and to make sure our changes stick upon a reboot&#8230; ), run a cfgmgr, then check for our interfaces.</p>
<pre class="terminalt">
cfgmgr
lsdev -Cc if
</pre>
<pre class="output">en0 Defined   05-08 Standard Ethernet Network Interface
en1 Defined   07-08 Standard Ethernet Network Interface
en2 Defined   07-09 Standard Ethernet Network Interface
et0 Defined   05-08 IEEE 802.3 Ethernet Network Interface
et1 Defined   07-08 IEEE 802.3 Ethernet Network Interface
et2 Defined   07-09 IEEE 802.3 Ethernet Network Interface
lo0 Available       Loopback Network Interface</pre>
<p>As you can see, we have successfully gotten our interfaces back. We&#8217;re almost done! All you need to do now is reboot the system.</p>
<pre class="terminal">shutdown -Fr</pre>
<p>Once the reboot has completed, issue one last check to verify that the adapters have changed:</p>
<pre class="terminalt">entstat -d ent0 | grep "Device Type"</pre>
<pre class="output">Device Type: 10/100/1000 Base-TX PCI-X Adapter (14106902)</pre>
<p>Looks good!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phase2.net/2007/06/how-to-rename-network-adapters-in-aix/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

