Monthly Archives: February 2009

Changing Hostname on CentOS

I needed this information earlier for CentOS (which Trixbox uses) and found it on this page: http://rutmandal.info/infotalk/2008/07/10/change-host-name-for-trixbox-shell/

Re-posting here so I don’t forget…

Changing hostname commands —

[trixbox1.localdomain ~]# sysctl kernel.hostname

kernel.hostname = trixbox1.localdomain

[trixbox1.localdomain ~]# sysctl kernel.hostname=veejansh.ivr

kernel.hostname = veejansh.ivr

You also need to edit your network file to make this change permanent i.e. persistent across reboots.

[veejansh.ivr ~]# vi /etc/sysconfig/netowrk

Here, edit “HOSTNAME” to “veejansh.ivr”, and save the file.

Now, restart your shell and you will have new name for your shell prompt or HOSTNAME.

MOSS Farm Monitoring – Everybody online?

Before a deployment, I’m working on a “health check” to determine whether or not some common ‘gotcha’s in a farm are going to be a problem. One problem in particular that I needed to solve is determining whether or not a MOSS Farm Member server is actually online and functioning – specifically its Timer Service.

(Slight detour – Solution Deployment in a farm environment totally relies on Timer Jobs – when you deploy a solution, MOSS creates a Solution Deployment Timer Job that every server in the farm executes. If a server is offline, that solution deployment job will hang indefinitely until the offline server comes back – by design, so that you don’t consider a solution deployment “successful” without all servers receiving the deployment.)

There are obviously the normal “Windows” ways to figure this out – can you ping each member, access a file share, etc. But I actually wanted to know that the member was not only running, but actively communicating with MOSS.

My goal was to come up with, for lack of a better term, a “Farm Ping” — Whereas I would kick off some kind of “dummy” timer job that all farm members would need to run in order to consider the “ping” completed. If I queued this job, and all member servers ran it fine, then I would know everybody was online. If it didn’t finish, then I’d know I have a problem.

The only issue with this technique is that I would need to create some type of custom timer job, package it up in a solution, and deploy it whenever I wanted to test this. But really, that just adds another moving piece to my equation. However, looking around, I found a great alternative that MOSS already does – the Config Refresh Timer Job.

After watching my Timer Job Monitoring Utility for a couple minutes, I noticed a pattern. Every farm member that runs Timer Jobs runs the “Config Refresh” job every 30 seconds or so. If I stop the Timer service on a member server, the Config Refresh job will continue to age. Start the Timer service again, and within a minute or so the Config Refresh job gets run and back on its 30-second schedule.

What’s this mean? Well, we can simply get SPFarm.Local.TimerService.RunningJobs, take a look at the “Config Refresh” jobs in that collection, and if they’re more than 30 seconds old, we know that the server it belongs to is not online. Simple, easy, and surprisingly accurate.

SQL Server Connectivity when Configuration Manager is broken

An awesome admin told me about a cool trick today… Needed to add a SQL Alias to SQL 2005 via SQL Server Configuration Manager. However, upon starting SQL Server Configuration Manager, received the following error:

Cannot connect to WMI provider. You do not have permission or the server is unreachable. Note that you can only manage SQL Server 2005 servers with SQL Server Configuration Manager.

Invalid Class [0x80041010]

Well, removing and reinstalling the SQL components was not a good option in this case. The solution?

Run c:\windows\system32\cliconfg.exe

This is a SQL Server Client Network Utility that allows you to access some of the basic SQL Server Configuration options.

Sometimes the ancient way just works better

For an application in .NET Compact Framework, I need to load about 10MB worth of data stored in XML files into datasets. On a desktop, it takes approximately no time to load that data into a dataset, or write it back out to a XML file.

I thought to myself, “since this worked in less than 1 second on a PC, I should be able to do this on a mobile device in maybe 5-10 seconds” – acceptable for an application startup time. Right? Wrong. Try over 4 minutes. Nothing fancy, just a DataSet.ReadXml() and then iterating through and validating data.

Right now, you’re thinking to yourself (because I’m writing this I get to choose), “why not use SQL CE or something?” – because the sole purpose of this data is to get enough data loaded into memory to get a head start on synchronizing it with the server, and SQL CE is not worth getting into as a dependency for this task. It’s supposed to be as simple of a process as possible.

“Oh, that makes sense,” you think. Thank you.

Knowing that 4 minutes for an applicaiton startup was a little bit excessive, I spent a few minutes turning it into a tab-delimited file instead.

The results? All the data loaded in 20 seconds. It’s not fancy, it’s not flexible, but it works. And that’s what I care about at the end of the day.

LINQ to SQL – Update Issues

This morning was a rude awakening.

Suddenly an application that has been running pretty solid using LINQ to SQL for basic CRUD operations for the last few months was throwing errors this morning about “Row not found or changed.”

Resolution? Manually retrieving another context copy of the object and ‘manually’ copying properties from one to the other, then calling .SubmitChanges().

I think I could do without many more of those!

MOSS Object Guids – Case Matters

Learned something today – the hard way.

In my deployment utility (which is a glorified way of simply deploying a solution by using the MOSS API), when I do an upgrade, I get the existing solution by ID via GetSolutionByID(string id) so that I can use the SPSolution object to perform the necessary actions.

However, in the middle of deployment, to my surprise, MOSS started yelling back at me, saying “Can’t find solution with ID <solutionID>”, but then declares “A solution with the name <SolutionName> already exists”.

It appears that MOSS cares whether or not the ID you pass into GetSolutionByID() is lowercase. Otherwise, MOSS won’t find the solution. I would have thought that this would be case insensitive, but it is apparently not.

Timer Job Monitoring Utility

One of the problems that seems to repeat itself over and over again in MOSS deployments / pushes, is that eventually you have trouble with Timer Jobs. The way to know if something is working or not is to keep refreshing the Jobs list in Central Administration, which gets to be a really clunky task, especially with more than a couple servers in the farm.

Soren Nielsen again has written an excellent post about how to fix them.

So yesterday I put together a little utility in Windows Forms that is designed to just give a little better visualization over what’s happening across the MOSS farm with Timer Jobs and SharePoint Services.

Timer Job Monitoring/Dashboard Utility

This utility simply connects to the local farm, categorizes all the running timer jobs (from SPFarm.Local.TimerService.RunningJobs) and puts them into one of 3 lists – Running / Incomplete / Idle. Also, I’ve tried to take an additional step out of problem diagnosis by showing the status of all SharePoint services across all servers in the farm. This is done through WMI by querying the Win32_Service class.

Everything is updated in 2-second intervals (since the point of this is to detect problems quickly in a deployment process).

If you’d like to try this out, you can download it here. (Just make sure you have the .NET Framework installed – which you should, if you’re running MOSS – and run from one of the farm servers.)

SPFarm.Local is null… what?

This comes from the “Captain Obvious” department, but took me a few minutes nonetheless. When running a utility application (which will probably be the next post), SPFarm.Local didn’t throw any exceptions but simply returned as null.

A quick Google for “SPFarm null” brings you to the conclusion that this is a 64-bit problem. And indeed, I was trying to use a .NET application compiled in a 32-bit environment (under “Any CPU” target) on a 64-bit server. However, changing the target to 64-bit and recompiling did not fix the problem.

As it turns out, the account I was running it under didn’t have permissions to access the farm. I would have expected SharePoint to throw some kind of UnauthorizedAccess exception, however in this scenario SPFarm.Local simply returns null. A quick “Run as…” and it came up fine, regardless of the target CPU.

Lesson learned – if you start seeing “Object reference not set to an instance of an object” exceptions with the SPFarm object, check the account permissions that you’re running under.

Propagating Content Type Changes in MOSS 2007

First, a short intro – I’m starting this blog for 2 reasons – 1, I’m learning a lot of stuff right now that if not used regularly, I’ll forget – and need a quick way to document some of it, and 2, if it weren’t for the other people out there doing the same, I wouldn’t have learned a lot of what I have. So hopefully my experiences will help someone else out there, too.

Now, on to the good stuff. The problem I’ve been tackling this week is in MOSS 2007 – specifically, the deployment and propagation of Content Types in an enterprise environment, using the Features & Solutions Framework. Here’s the background:

  1. MOSS is being used as a publishing platform for a very large project. (Hundreds of thousands of webs).
  2. Following best practices for enterprise MOSS architecture, Content Types are being deployed through Features, and are inherited by pages (list items) in subwebs.

The challenge is that MOSS really doesn’t support updates to content types through the Features & Solutions framework (i.e., you are using XML Based Content Types). Once you’ve deployed your feature, it’s going to be a little bit of a fight to update a content type by upgrading the solution. On the other hand, MOSS’s editing capabilities of content types through the UI works extremely well. So, my goal has been to come up with a way to replicate the “UI” behavior within the confines of the Features & Solutions framework.

The first thing I discovered is that if you Deactivate your feature, Retract it, Delete it, Install it, Deploy it, and Activate your feature again, new fields that you’ve added to the Content Type in XML do, in fact, appear. The only problem is, everything that inherits from that Content Type (let’s say, oh, a few million list items?) does not see any of the changes. This is because a new “list” Content Type is created any time you assign a content type to a list, and the new List Content Type inherits from the “real” one that you deployed through your feature. Soren Nielsen describes this briefly in his blog post.

So, at this point, the problem that still remains is that we need a way to propagate changes from a Parent Content Type down to its Child Content Types (in this case, pages in a publishing web that inherit from it). Microsoft’s MSDN article on Updating Child Content Types pretty much spells this out for us:

“You cannot add columns to an existing site content type declaratively, in other words, by updating the Feature XML files.”

Unfortunately, we simply can’t create a business requirement in an enterprise MOSS installation that says “once we deploy content types, they can never change.”

There are a few blogs out there that have proposed the same solution, as well as a Microsoft engineer that worked with me on this issue – use the MOSS Object Model to recurse individually through each subweb, check each list, compare fields, and programmatically add the field links that don’t exist. Some have even integrated this into a STSADM command. I gave this a shot, and it takes between 0.2 – 0.4 seconds to check and compare fields on a list item. This may not sound like a lot (and will work fine for a smaller MOSS install), but for this particular environment, this technique would take at least 66 hours (2.7 days) to propagate Content Type fields.

You may notice, though, that MOSS 2007 out of the box has a special little radio button in the UI where you add a new column to a content type – “Update all content types that inherit from this content type” (yes/no). Propagating new columns/fields this way works dramatically faster – about 0.04 seconds per WEB. This is much more acceptable.

Kicking this around with a team member, we eventually understood what MOSS was actually doing. MOSS, out of the box, during a Content Type update, creates a list of changes to a content type, and then will propagate those changes via the SPContentType.Update() method. The cool thing, is that .Update() takes an optional boolean parameter – “UpdateChildren”. This will propagate the current set of changes to child content types (which in our case are lists). Tested it, and it works! Essentially, there’s no way to make the Features & Solutions framework call .Update(true) – if we can find a way to do this, we have our solution.

At the end of the day, we need to update the Content Type XML files, but programmatically add or make changes to the fields ourselves in the Object Model. So I’ve modified the steps to deploy a solution with a small utility to go along with it. Here is the procedure:

  1. Upgrade the revised solution in-place (no deactivating features). At this point you will NOT see any new fields/columns in the content type.
  2. Compare the fields in your revised solution (WSP) file with the fields and field links that currently exist in your “Live” Content Type as it currently exists in the MOSS farm. I wrote a utility to accomplish this by extracting and parsing the contents of the WSP package and make a class model of the fields.
  3. For any fields that don’t exist, create the field (SPField) and add a field link (SPFieldLink) to the Content Type.
  4. Call SPContentType.Update(true).

As long as you can make field/column changes programmatically and .Update(true) them in one shot, MOSS does the rest (and much faster than enumerating through every list).