<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Error: No Error</title>
	
	<link>http://robpetti.com</link>
	<description>Rob's Blog of Computery Things</description>
	<lastBuildDate>Fri, 10 May 2013 19:12:14 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ErrorNoError" /><feedburner:info uri="errornoerror" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly></feedburner:browserFriendly><item>
		<title>Resizing Solaris Partitions</title>
		<link>http://robpetti.com/?p=150</link>
		<comments>http://robpetti.com/?p=150#comments</comments>
		<pubDate>Fri, 10 May 2013 19:12:14 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Solaris]]></category>
		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=150</guid>
		<description><![CDATA[I&#8217;m currently in the process of resizing a partition in Solaris 10. So far, the instructions that I&#8217;ve found have been quite incorrect, so I&#8217;m documenting the steps I&#8217;m taking here. In my particular case, I&#8217;m resizing a single partition on a non-root disk after increasing it&#8217;s size through VMWare. Partitions in Solaris work quite <a href='http://robpetti.com/?p=150' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m currently in the process of resizing a partition in Solaris 10. So far, the instructions that I&#8217;ve found have been quite incorrect, so I&#8217;m documenting the steps I&#8217;m taking here. In my particular case, I&#8217;m resizing a single partition on a non-root disk after increasing it&#8217;s size through VMWare.</p>
<p><span id="more-150"></span></p>
<p>Partitions in Solaris work quite a bit differently from partitions in other *nix platforms. First we have the partition. This is what we normally resize using utilities such as gparted. Within the Solaris partition, are slices. These can be thought of as &#8216;sub partitions&#8217; that contain the filesystems to be mounted in the OS. In fact, Solaris often refers to slices as partitions, which can get a bit confusing at times. First we need to resize the overall Solaris partition, then resize the slice(s) within it.</p>
<p>It&#8217;s worth noting that my case is exceptionally simple. I have a single filesystem, on a single slice, on a single partition, on a single disk separate from the root one. I don&#8217;t recommend trying any of these steps on a root disk or root partition. Consider yourself warned.</p>
<p>First, we need to find out the device name:</p>
<pre class="code">
$ df -h /disk1
/dev/dsk/c2t1d0s0      148G   112G    34G    77%    /disk1
</pre>
<p>Right now, we&#8217;re interested not in the slice being mounted but the partition containing the slice. In this case it is c2t1d0p0. I&#8217;m sure there&#8217;s some other way to figure this out, but in my case I only have one slice and one partition on this particular disk (c2t1d0), so it was easy to figure it out.</p>
<p>Unmount all slices:</p>
<pre class="code">
# umount /disk1
</pre>
<p>Dump the disk geometry:</p>
<pre class="code">
# fdisk -G /dev/rdsk/c2t1d0p0 > /tmp/geom
</pre>
<p>Then dump the current partition table:</p>
<pre class="code">
# fdisk -W /tmp/ptbl.tmp /dev/rdsk/c2t1d0p0
</pre>
<p>I recommend backing up the partition table at this point, in case you need it later.</p>
<p>Also, you will want to record the current slice map. Solaris has a command to help you do this, but it refers to slices as &#8216;partitions&#8217;. These partitions are actually slices in the Solaris partition that (should) encompass the entire disk, and are not to be confused with the disk&#8217;s partition table that you will modify using fdisk. You can print the current slices using the <code>format</code> command, selecting your disk, and printing the partition map (&#8216;p&#8217; from the partition menu). It should look something like this:</p>
<pre class="code">
Part      Tag    Flag     Cylinders         Size            Blocks
  0 unassigned    wm       1 - 19577      149.97GB    (19577/0/0) 314504505
  1 unassigned    wm       0                0         (0/0/0)             0
  2     backup    wu       0 - 19577      149.98GB    (19578/0/0) 314520570
  3 unassigned    wm       0                0         (0/0/0)             0
  4 unassigned    wm       0                0         (0/0/0)             0
  5 unassigned    wm       0                0         (0/0/0)             0
  6 unassigned    wm       0                0         (0/0/0)             0
  7 unassigned    wm       0                0         (0/0/0)             0
  8       boot    wu       0 -     0        7.84MB    (1/0/0)         16065
  9 unassigned    wm       0                0         (0/0/0)             0
</pre>
<p>Keep this somewhere safe for referencing later.</p>
<p>Edit the ptbl.tmp file you created. At the top, you&#8217;ll see your disks geometry. At the bottom is the layout. The ONLY field you are interested in modifying at the bottom is the number of sectors (Numsect).</p>
<pre class="code">
* /dev/rdsk/c2t1d0p0 default fdisk table
* Dimensions:
*    512 bytes/sector
*     63 sectors/track
*    255 tracks/cylinder
*   22192 cylinders
* Id    Act  Bhead  Bsect  Bcyl    Ehead  Esect  Ecyl    Rsect    Numsect
  191   128  0      1      1       254    63     1023    16065    314552700
</pre>
<p>In my case, I needed to expand the partition to fill the entire disk. I did this by taking the number of cylinders, subtracting one (since the partition starts at cylinder one and not 0 (Bcyl)), multiplying that number by tracks/cylinder, and multiplying that by sectors/track. So the new Numsect value is: 22191*255*63 = 356498415.</p>
<p>Once that&#8217;s been changed, write the new partition table to disk:</p>
<pre class="code">
# fdisk -S /tmp/geom -F /tmp/ptbl.tmp -I /dev/rdsk/c2t1d0p0
</pre>
<p>You can run fdisk normally (<code>fdisk /dev/rdsk/c2t1d0p0</code>) in order to verify your changes. Once that is done, run <code>format</code> again, since the solaris partition (slices) map may have been lost. In my case, slice 0 lost it&#8217;s information, so I recreated it to start at the same start cylinder as before (1), and take up the rest of the disk. Modify it using &#8217;0&#8242; from the partition menu, and save the new map using the &#8216;label&#8217; command from within the partition menu.</p>
<pre class="code">
Part      Tag    Flag     Cylinders         Size            Blocks
  0 unassigned    wm       1 - 22188      169.97GB    (22188/0/0) 356450220
  1 unassigned    wm       0                0         (0/0/0)             0
  2     backup    wu       0 - 22188      169.98GB    (22189/0/0) 356466285
  3 unassigned    wm       0                0         (0/0/0)             0
  4 unassigned    wm       0                0         (0/0/0)             0
  5 unassigned    wm       0                0         (0/0/0)             0
  6 unassigned    wm       0                0         (0/0/0)             0
  7 unassigned    wm       0                0         (0/0/0)             0
  8       boot    wu       0 -     0        7.84MB    (1/0/0)         16065
  9 unassigned    wm       0                0         (0/0/0)             0
</pre>
<p>The slice should now have been resized. Next is to verify that no data was lost:</p>
<pre class="code">
# fsck /dev/rdsk/c2t1d0s0
</pre>
<p>And finally, grow the filesystem to take up the rest of the slice:</p>
<pre class="code">
# growfs /dev/rdsk/c2t1d0s0
</pre>
<p>And that&#8217;s it! Hopefully this helps people understand Solaris partitioning schemes a little bit better. I learned quite a bit while figuring this out.</p>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=150&amp;md5=435da2668ca37994f76f3ebeb6aea6d2" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=150</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D150&amp;language=sq_AL&amp;category=text&amp;title=Resizing+Solaris+Partitions&amp;description=I%26%238217%3Bm+currently+in+the+process+of+resizing+a+partition+in+Solaris+10.+So+far%2C+the+instructions+that+I%26%238217%3Bve+found+have+been+quite+incorrect%2C+so+I%26%238217%3Bm+documenting+the+steps+I%26%238217%3Bm+taking...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>Perforce Oddities: cannot submit unicode type file using non-unicode server</title>
		<link>http://robpetti.com/?p=145</link>
		<comments>http://robpetti.com/?p=145#comments</comments>
		<pubDate>Tue, 07 May 2013 18:30:50 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Perforce]]></category>
		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=145</guid>
		<description><![CDATA[Ran into this little gem today&#8230; I&#8217;ve got a project that I&#8217;m currently trying to branch. It&#8217;s a very simple integration operation from one location to another, nothing crazy. Of course Perforce needs to make it as complicated as possible by throwing me this error for a couple of our files: cannot submit unicode type <a href='http://robpetti.com/?p=145' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>Ran into this little gem today&#8230; I&#8217;ve got a project that I&#8217;m currently trying to branch. It&#8217;s a very simple integration operation from one location to another, nothing crazy. Of course Perforce needs to make it as complicated as possible by throwing me this error for a couple of our files:</p>
<p><code>cannot submit unicode type file using non-unicode server</code></p>
<p>Now, this is incredibly nonsensical. I&#8217;m integrating an <i>already submitted</i> file from one location to another, and checking it in. Why does Perforce reject it if it&#8217;s already been submitted successfully once before?</p>
<p>It turns out that the way perforce handles unicode filetypes changed at some point. Before this change, you could submit unicode files without any problems. After this change, your server needs to be reconfigured as a &#8216;unicode server&#8217; in order to check in unicode files, even though it&#8217;s clearly handling already checked-in files just fine. To me, this seems like an artificial restriction, but I digress.</p>
<p>To resolve this, you just need to reopen the files as text, and resubmit them.</p>
<pre class="code">
$ p4 reopen -t text <FILE>
</pre>
<p>After that, you can work on the files again as normal. I&#8217;m not sure what effect this has on the encoding of the files themselves, so as always, YMMV, but at least you&#8217;ll be able to get on with your life.</p>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=145&amp;md5=93995674fe5f5d2b393da58362f7f0e0" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=145</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D145&amp;language=sq_AL&amp;category=text&amp;title=Perforce+Oddities%3A+cannot+submit+unicode+type+file+using+non-unicode+server&amp;description=Ran+into+this+little+gem+today%26%238230%3B+I%26%238217%3Bve+got+a+project+that+I%26%238217%3Bm+currently+trying+to+branch.+It%26%238217%3Bs+a+very+simple+integration+operation+from+one+location+to+another%2C+nothing+crazy.+Of...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>Perfmerge++ Warnings are not actually warnings!</title>
		<link>http://robpetti.com/?p=139</link>
		<comments>http://robpetti.com/?p=139#comments</comments>
		<pubDate>Fri, 15 Feb 2013 00:15:46 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Perforce]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=139</guid>
		<description><![CDATA[I recently did a migration of source code from one perforce server to another. During the merge process, I ran into an odd warning: perfmerge++ warning: No mapping for change 293174 in database /x/sourceserver/server/. Rejecting. Thinking that it was just a dead or missing changeset, I skipped right along and proceeded to put the server <a href='http://robpetti.com/?p=139' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>I recently did a migration of source code from one perforce server to another. During the merge process, I ran into an odd warning:</p>
<pre class="code">
perfmerge++ warning:
        No mapping for change 293174 in database /x/sourceserver/server/. Rejecting.
</pre>
<p>Thinking that it was just a dead or missing changeset, I skipped right along and proceeded to put the server into production. Verify came back ok, so I figured everything was fine.</p>
<p>It was not&#8230;<br />
<span id="more-139"></span></p>
<p>It seems that perfmerge has an annoying tendency to quit at the first sign of trouble, then throw a &#8216;warning&#8217; rather than a full blown error message. In this case, it was about to write out the db.changes* tables, then decided against it. When I brought the server back online, there were file revisions, but no changesets or change descriptions to speak of. This is obviously a huge problem!</p>
<p>I checked both source p4 roots, but couldn&#8217;t find the changes in question. Out of desperation, I took checkpoints of both roots, and grepped the entire checkpoint looking for the changeset numbers that were throwing warning. There were two things that I found.</p>
<p>The first thing was that somehow, someone had managed to open files under a pending changeset that didn&#8217;t exist. I&#8217;m not entirely sure how that happened, but it did. Once that was found, it was a simple matter of reverting all the files opened under that missing changeset.</p>
<p>The second thing I found wrong was that perfmerge apparently had an issue with the way my job names were formatted, which caused any changeset tied to that job to fail to merge. In my case, we don&#8217;t make heavy use of jobs, and the one with the issue appeared to be accidentally created. After removing the fix tying the changeset to it and deleting it, the merge proceeded to work fine.</p>
<p>Hopefully this helps some people. I regret that I didn&#8217;t save my entire solution somewhere, but the perforce documentation should cover most of what&#8217;s required to do the same.</p>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=139&amp;md5=4896725db95b532fb1e04519186a3cd6" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=139</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D139&amp;language=sq_AL&amp;category=text&amp;title=Perfmerge%2B%2B+Warnings+are+not+actually+warnings%21&amp;description=I+recently+did+a+migration+of+source+code+from+one+perforce+server+to+another.+During+the+merge+process%2C+I+ran+into+an+odd+warning%3A+perfmerge%2B%2B+warning%3A+No+mapping+for+change...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>Adding a Windows slave to Jenkins the hard way</title>
		<link>http://robpetti.com/?p=121</link>
		<comments>http://robpetti.com/?p=121#comments</comments>
		<pubDate>Thu, 22 Nov 2012 22:09:30 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Jenkins]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=121</guid>
		<description><![CDATA[Jenkins makes adding slaves really easy. For unix machines, the preferred method is to use SSHD, which only requires that the master be able to contact the slave. On windows, however, you are stuck using a JNLP based solution, which requires that the slave be able to access master over the network. I got stuck <a href='http://robpetti.com/?p=121' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>Jenkins makes adding slaves really easy. For unix machines, the preferred method is to use SSHD, which only requires that the master be able to contact the slave. On windows, however, you are stuck using a JNLP based solution, which requires that the slave be able to access master over the network.</p>
<p>I got stuck in the awkward situation where I had to add a windows machine to our master, but the slave could not even ping it. This could be resolved by updating our routing tables on the slave side, but unfortunately that wasn&#8217;t an option here. Instead I chose to try and start the slave using a Windows SSHD solution.<br />
<span id="more-121"></span></p>
<p><b>Edit:</b> <em>I&#8217;ve found that the data throughput on FreeSSHD using the method I&#8217;ve outlined below leaves much to be desired. I&#8217;ve since switched over to installing cygwin and using it&#8217;s sshd server instead. If you are using this pipe to send or archive files, I highly recommend using cygwin&#8217;s sshd server instead, as it&#8217;s several orders of magnitude faster. For example, I went from a 45 minute transfer, down to only 1 minute.</em></p>
<p>First things first, we need to install an ssh server onto the master. This was pretty easy, as I just used <a href="http://www.freesshd.com/" title="FreeSSHD"></a>. Once installed, you need to make sure to stop the service, and run it by hand as administrator in order to change the settings. It&#8217;ll show up in the toolbox on your system, so just right click it and click settings. From there you can set up your new user.</p>
<p>A few gotchas: You&#8217;ll want to DISABLE &#8220;Use new console engine&#8221; on the SSH tab, seen below:<br />
<img src="http://robpetti.com/wp-content/uploads/2012/11/freesshd-001.png" alt="Disable 'Use new console engine'" /><br />
Also, when setting up pubkey authentication, you&#8217;ll want to put the key into a file in the &#8220;Pubkey folder&#8221; that&#8217;s defined in the Authentication tab of FreeSSHD. The file needs to have the exact same name as the new user you created. In my case, my user was called &#8220;releng&#8221; so I made a new text file called &#8220;releng&#8221; (no extension!) with the contents of my jenkins user&#8217;s public key.</p>
<p>Test the connection from the master user by sshing into the slave as the jenkins user:<br />
<code><br />
jenkins@jenkins-master:~$ ssh releng@windows-slave-hostname<br />
</code></p>
<p>Once you&#8217;ve verified that passwordless authentication works, now it&#8217;s time to set up the slave. Copy the slave.jar from your jenkins install (http://yourjenkinsurl/jnlpJars/slave.jar) onto the slave somewhere. In this example, I&#8217;ll assume you placed it into C:\jenkins\.</p>
<p>Give it a shot again:</p>
<pre class="code">
jenkins@jenkins-master:~$ ssh releng@windows-slave-hostname java -jar C:/jenkins/slave.jar -text
</pre>
<p>It should return something like:</p>
<pre class="code">
<===[JENKINS REMOTING CAPACITY]===>rO0ABXNyABpodWRzb24ucmVtb3RpbmcuQ2FwYWJpbGl0eQAAAAAAAAABAgABSgAEbWFza3hwAAAAAAAAAAY=<===[HUDSON TRANSMISSION BEGINS]===>rO0ABQ==
</pre>
<p>That means it&#8217;s working, but there&#8217;s still more work to be done to get jenkins talking to it properly. First, set up a new Dumb slave in jenkins like you normally would, and select &#8220;Launch slave via execution of command on the Master&#8221;. Unfortunately the built-in ssh functionality doesn&#8217;t work because of the way FreeSSHD handles stdout and stderr.</p>
<p>Here&#8217;s the launch command you need it to run:</p>
<pre class="code">
bash -c 'ssh releng@windows-slave cmd /c "java -jar C:/jenkins/slave.jar -text 2>C:/jenkins/slave.junk.txt"'
</pre>
<p>The redirect to slave junk is necessary because the slave.jar outputs informational messages to it&#8217;s stderr. Normally these messages are not sent back to the master, but in this case FreeSSHD just pipes stderr into stdout, which would cause problems with the master as it parses the output. I&#8217;m not 100% sure if wrapping it in bash is necessary, but it seems to work fine.</p>
<p>Good luck!</p>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=121&amp;md5=3f19bd893b4cf0aff816034397e1364b" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=121</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D121&amp;language=sq_AL&amp;category=text&amp;title=Adding+a+Windows+slave+to+Jenkins+the+hard+way&amp;description=Jenkins+makes+adding+slaves+really+easy.+For+unix+machines%2C+the+preferred+method+is+to+use+SSHD%2C+which+only+requires+that+the+master+be+able+to+contact+the+slave.+On+windows%2C...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>Quick Script: Email all recent Perforce users</title>
		<link>http://robpetti.com/?p=115</link>
		<comments>http://robpetti.com/?p=115#comments</comments>
		<pubDate>Thu, 23 Aug 2012 22:29:40 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Perforce]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=115</guid>
		<description><![CDATA[Here&#8217;s a script I whipped up in order to send an email to all recent Perforce users. I needed this because my company uses a shared license, so all user accounts are shared between our perforce servers. When a server needs to go down for maintenance, I like to email only those people who actually <a href='http://robpetti.com/?p=115' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s a script I whipped up in order to send an email to all recent Perforce users. I needed this because my company uses a shared license, so all user accounts are shared between our perforce servers. When a server needs to go down for maintenance, I like to email only those people who actually use it. This uses python, but it does not require the p4python api (though I imagine it would be quite simpler using it). I&#8217;m sure there are some imports that need to be cleaned up, but whatever, it&#8217;s just a quickie.<br />
<span id="more-115"></span></p>
<pre name="code" class="brush: python">
#!/usr/bin/python

import marshal
import subprocess, shlex
import re
import os
from datetime import datetime
import time
import smtplib
from email.mime.text import MIMEText

today = int(time.time())

window = 60*60*24*30 #30 days

mailhost = "mailhost"
me = "you@yoursite.com"

maxmails = 10

msg = MIMEText("Perforce server is going down! Lookout!")
msg['Subject'] = "Perforce downtime this weekend"
msg['From'] = me

def getRecentUsersList():
    args = shlex.split("p4 -G users")
    p = subprocess.Popen(args, stdout=subprocess.PIPE)
    userList = []
    while True:
        try:
            user = marshal.load(p.stdout)
            if int(user['Access']) > (today-window):
                userList.append(user)
        except:
            break
    return userList

def getUniqueEmails(userList):
    emails = {}
    for user in userList:
        emails[user['Email']] = 1
    print "got " + str(len(emails.keys())) + " emails"
    return emails.keys()

def sendEmail(emails):
    print "sending email to "+str(emails)
    s = smtplib.SMTP(mailhost)
    s.sendmail(me, emails, msg.as_string())
    s.quit()

def sendEmails(emails):
    emailsubset = []
    for email in emails:
        emailsubset.append(email)
        if len(emailsubset) >= maxmails:
            sendEmail(emailsubset)
            emailsubset = []
    if len(emailsubset) > 0:
        sendEmail(emailsubset)

def main():
    userList = getRecentUsersList()
    emails = getUniqueEmails(userList)
    sendEmails(emails)

main()
</pre>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=115&amp;md5=1c062de69c0d0cc7131a6fd0d42109d9" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=115</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D115&amp;language=sq_AL&amp;category=text&amp;title=Quick+Script%3A+Email+all+recent+Perforce+users&amp;description=Here%26%238217%3Bs+a+script+I+whipped+up+in+order+to+send+an+email+to+all+recent+Perforce+users.+I+needed+this+because+my+company+uses+a+shared+license%2C+so+all+user...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>Reverting All Files In Perforce</title>
		<link>http://robpetti.com/?p=105</link>
		<comments>http://robpetti.com/?p=105#comments</comments>
		<pubDate>Mon, 23 Jan 2012 20:34:23 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Perforce]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=105</guid>
		<description><![CDATA[I often find myself in the situation where I need to delete the perforce account of a user who has left the company. Unfortunately I&#8217;m usually unable to do so because they have left files open, resulting in this error: $ p4 user -d -f SOMEUSER User SOMEUSER has file(s) open on 2 client(s) and <a href='http://robpetti.com/?p=105' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>I often find myself in the situation where I need to delete the perforce account of a user who has left the company. Unfortunately I&#8217;m usually unable to do so because they have left files open, resulting in this error:</p>
<pre name="code" class="brush: bash">
$ p4 user -d -f SOMEUSER
User SOMEUSER has file(s) open on 2 client(s) and can't be deleted.
</pre>
<p>The solutions posted online usually involve either deleting the clients, or &#8216;masquerading&#8217; as the client host and reverting the files by hand. This is very tedious, so I wrote a python script to do it instead. It&#8217;s a bit crude, but all it does is take usernames off the command line, and proceeds to revert all the files that user has open on the server.</p>
<p><span id="more-105"></span></p>
<pre name="code" class="brush: python">
#!/usr/bin/python

import marshal
import subprocess, shlex
import re
import os
import sys

def getPerforceResponse(command):
	lst = []
	args = shlex.split(command)
	p = subprocess.Popen(args, stdout=subprocess.PIPE)
	try:
		while 1:
			dictionary = marshal.load(p.stdout)
			lst.append(dictionary)
	except EOFError:
		pass
	return lst

def getOpenedFiles():
	return getPerforceResponse("p4 -G opened -a //...")

def getOpenedFilesForUser(userID, opened):
	openedByUser = []
	for i in opened:
		if i['user'] == userID:
			openedByUser.append(i)
	return openedByUser

def getClient(clientID):
	return getPerforceResponse("p4 -G client -o \"" + clientID + "\"")[0]

def main():
	print "Getting list of open files..."
	opened = getOpenedFiles()
	for user in sys.argv[1:]:
		openedByUser = getOpenedFilesForUser(user, opened)
		print "Found " + str(len(openedByUser)) + " opened files for " + user
		print "reverting..."
		for f in openedByUser:
			print "Reverting " + f['depotFile'] + " on " + f['client']
			client = getClient(f['client'])
			host = client.get('Host', 'p4client')
			response = getPerforceResponse("p4 -G -H " + host + " -c " + f['client'] + " -u " + user + " revert -k \"" + f['depotFile'] +"\"")
			print response

main()
</pre>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=105&amp;md5=98a00e6121127140a75fb5a517142315" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=105</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D105&amp;language=sq_AL&amp;category=text&amp;title=Reverting+All+Files+In+Perforce&amp;description=I+often+find+myself+in+the+situation+where+I+need+to+delete+the+perforce+account+of+a+user+who+has+left+the+company.+Unfortunately+I%26%238217%3Bm+usually+unable+to+do+so...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>100% cpu usage in Oneiric (Ubuntu 11.10)</title>
		<link>http://robpetti.com/?p=100</link>
		<comments>http://robpetti.com/?p=100#comments</comments>
		<pubDate>Fri, 02 Dec 2011 18:17:42 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=100</guid>
		<description><![CDATA[I recently upgraded my work PC from Natty to Oneiric, and discovered that whenever I had a window open that wasn&#8217;t maximized, it&#8217;s backend process and xorg would use up 100% of the cpu. I was nearly about to rebuild my machine when I discovered that it only happened for non-maximized GTK windows. As a <a href='http://robpetti.com/?p=100' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>I recently upgraded my work PC from Natty to Oneiric, and discovered that whenever I had a window open that <em>wasn&#8217;t</em> maximized, it&#8217;s backend process and xorg would use up 100% of the cpu.</p>
<p>I was nearly about to rebuild my machine when I discovered that it only happened for non-maximized <em>GTK</em> windows. As a last ditch effort, I ran gtk-theme-switch2, and switch my theme. Magically, this fixed the problem!</p>
<p>Part of the issue was that I&#8217;m running in Fluxbox, not Gnome or Unity. I think somehow it got the theme messed up during the upgrade, and since neither Gnome nor Unity had the chance to set it to a correct theme, it borked.</p>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=100&amp;md5=be7c7e6f96558b568db80dd686387ba7" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=100</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D100&amp;language=sq_AL&amp;category=text&amp;title=100%25+cpu+usage+in+Oneiric+%28Ubuntu+11.10%29&amp;description=I+recently+upgraded+my+work+PC+from+Natty+to+Oneiric%2C+and+discovered+that+whenever+I+had+a+window+open+that+wasn%26%238217%3Bt+maximized%2C+it%26%238217%3Bs+backend+process+and+xorg+would+use+up...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>Dual booting Ubuntu and ChromiumOS</title>
		<link>http://robpetti.com/?p=92</link>
		<comments>http://robpetti.com/?p=92#comments</comments>
		<pubDate>Sun, 05 Jun 2011 07:04:10 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=92</guid>
		<description><![CDATA[Yes, I know there is a handy and rather well thought out guide here, but I thought I would post my experiences, especially given that blindly following the aforementioned tutorial resulted in my existing Ubuntu installation being wiped&#8230; First, go read the tutorial so you know what I&#8217;m talking about. Essentially you will need to <a href='http://robpetti.com/?p=92' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>Yes, I know there is a handy and rather well thought out guide <a href="http://chromeos.hexxeh.net/wiki/doku.php?id=multiboot">here</a>, but I thought I would post my experiences, especially given that blindly following the aforementioned tutorial resulted in my existing Ubuntu installation being wiped&#8230;<br />
<span id="more-92"></span><br />
First, go read the tutorial so you know what I&#8217;m talking about. Essentially you will need to make room on your hard disk for the C-STATE and C-ROOT ChromiumOS partitions, create them, and copy them from your USB stick using dd.</p>
<p>I know what you are thinking, &#8220;Oh, you probably just gave dd the incorrect parameters and wiped your existing system partition.&#8221; Not so, actually. I successfully copied all the data to the right partitions on my disk, and was able to boot into ChromiumOS.</p>
<p>The madness started once ChromiumOS started booting. I was using the latest vanilla version, which worked in live mode fine. When I booted off my main disk, however, it started performing some sort of automated recovery. That&#8217;s when my Ubuntu partition got wiped.</p>
<p>I had 3 partitions at the time:</p>
<ul>
<li>/dev/sda1 &#8211; Ubuntu</li>
<li>/dev/sda2 &#8211; C-STATE</li>
<li>/dev/sda3 &#8211; C-ROOT</li>
</ul>
<p>Now apparently, the vanilla version of ChromiumOS doesn&#8217;t like this setup much. It will always try to use the first available partition as the C-STATE. In this case it was my Ubuntu partition. Since it was the wrong label and filesystem type, ChromiumOS decided to go ahead and reformat it without confirmation.</p>
<p>I also tried having C-ROOT installed on sda1, and it didn&#8217;t seem to like that much either. In the end, I had to set up my partitions like this:</p>
<ul>
<li>/dev/sda1 &#8211; C-STATE</li>
<li>/dev/sda2 &#8211; C-ROOT</li>
<li>/dev/sda3 &#8211; Ubuntu</li>
</ul>
<p>That seemed to work fine, with one minor exception. There was no initrd.img available on the root for some reason, and specifying the root disk using the label wasn&#8217;t working either. The following grub entry was what I ended up using:</p>
<pre class="brush: bash">menuentry "ChromiumOS" {
	insmod ext2
	set root=(hd0,2)
	linux   /boot/vmlinuz root=/dev/sda2 rw noresume noswap i915.modeset=1 loglevel=1 quiet
}</pre>
<p>Note that I had to change the root parameter, as well as completely remove the initrd line. Apparently these two problems are related (a certain something needs to be included in the initrd in order to resolve filesystem labels, and since there is no initrd it doesn&#8217;t work).</p>
<p>So that&#8217;s it! Word to the wise, it&#8217;s always a good idea to do a full backup before trying any of this.</p>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=92&amp;md5=96576b96e02ab4b9f338eed1f2555989" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=92</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D92&amp;language=sq_AL&amp;category=text&amp;title=Dual+booting+Ubuntu+and+ChromiumOS&amp;description=Yes%2C+I+know+there+is+a+handy+and+rather+well+thought+out+guide+here%2C+but+I+thought+I+would+post+my+experiences%2C+especially+given+that+blindly+following+the+aforementioned+tutorial...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>Mounting NFS results in nobody:nobody owned files</title>
		<link>http://robpetti.com/?p=85</link>
		<comments>http://robpetti.com/?p=85#comments</comments>
		<pubDate>Thu, 21 Apr 2011 20:44:10 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=85</guid>
		<description><![CDATA[So I ran into this problem earlier this week. Basically we have a Solaris 10 server hosting files over NFS. The NFS server that comes with Solaris 10 supports NFSv4, but doesn&#8217;t seem to include idmapd, which is responsible for mapping user and group ids. Everything I&#8217;ve read suggests that idmapd is required on both <a href='http://robpetti.com/?p=85' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>So I ran into this problem earlier this week. Basically we have a Solaris 10 server hosting files over NFS. The NFS server that comes with Solaris 10 supports NFSv4, but doesn&#8217;t seem to include idmapd, which is responsible for mapping user and group ids. Everything I&#8217;ve read suggests that idmapd is required on both the client and server in order for it to work correctly. Since I had no real desire to screw with the server configuration (and since other machines could mount it correctly) I kept searching.</p>
<p>The solution I found is a bit hacky, but it works for me. Basically it boils down to adding <code>nfsvers=3</code> to the mount parameters. In my case, I was using automount, so I just added the option to every line in my /etc/auto.master. This just forces it to mount using NFSv3, which works because of it&#8217;s simplicity, but is possibly more insecure (and not all NFS servers will support it).</p>
<p>If possible, you should really just consider doing things the proper way, and getting idmapd set up on your servers and clients. This is just a quick work-around for when you are backed into a corner like I am.</p>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=85&amp;md5=862c2a49cd9a5a3d2c6262a2cfea8551" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=85</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D85&amp;language=sq_AL&amp;category=text&amp;title=Mounting+NFS+results+in+nobody%3Anobody+owned+files&amp;description=So+I+ran+into+this+problem+earlier+this+week.+Basically+we+have+a+Solaris+10+server+hosting+files+over+NFS.+The+NFS+server+that+comes+with+Solaris+10+supports+NFSv4%2C...&amp;tags=blog" type="text/html" />
	</item>
		<item>
		<title>Moving on to Jenkins</title>
		<link>http://robpetti.com/?p=79</link>
		<comments>http://robpetti.com/?p=79#comments</comments>
		<pubDate>Tue, 08 Feb 2011 21:27:28 +0000</pubDate>
		<dc:creator>Rob Petti</dc:creator>
				<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://robpetti.com/?p=79</guid>
		<description><![CDATA[So in case you haven&#8217;t heard, there was some drama between the Hudson community and Oracle. I won&#8217;t go into detail as there are plenty of articles about what went on. All of the issues that were opened on the Hudson Jira for the Perforce plugin are still open, but I&#8217;m unassigning those that are <a href='http://robpetti.com/?p=79' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>So in case you haven&#8217;t heard, there was some drama between the Hudson community and Oracle. I won&#8217;t go into detail as there are <a href="http://jenkins-ci.org/content/hudsons-future">plenty</a> of <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=317610">articles</a> about what went on.</p>
<p>All of the issues that were opened on <a href="http://issues.hudson-ci.org/"> the Hudson Jira</a> for the Perforce plugin are still open, but I&#8217;m unassigning those that are assigned to me. I&#8217;ll continue maintaining the Perforce plugin against Jenkins, so bugs will be tracked <a href="http://issues.jenkins-ci.org/">there</a>, and any fixes I make will be made in the Jenkins repository. Note that the Jenkins version <i>will</i> still work for Hudson until Oracle/Sonatype and/or the Jenkins Community decide to break cross-compatibility.</p>
<p>I&#8217;m not saying the Hudson version is dead, just that it doesn&#8217;t have an active maintainer. Someone may take over maintaining it, but as far as I know, only one person has been assigned to working on Hudson and the hundreds of plugins written for it.</p>
 <p><a href="http://robpetti.com/?flattrss_redirect&amp;id=79&amp;md5=2fa33df1a4af80ab494392e86c44174f" title="Flattr" target="_blank"><img src="http://robpetti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://robpetti.com/?feed=rss2&amp;p=79</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=rpetti&amp;popout=1&amp;url=http%3A%2F%2Frobpetti.com%2F%3Fp%3D79&amp;language=sq_AL&amp;category=text&amp;title=Moving+on+to+Jenkins&amp;description=So+in+case+you+haven%26%238217%3Bt+heard%2C+there+was+some+drama+between+the+Hudson+community+and+Oracle.+I+won%26%238217%3Bt+go+into+detail+as+there+are+plenty+of+articles+about+what+went...&amp;tags=blog" type="text/html" />
	</item>
	</channel>
</rss>
