Tuesday, July 06, 2010

Diagnosing 401.3 errors with a new IIS 7 website deployment

I recently worked to help diagnose why a new website we deployed was getting 401.3 errors on its site images. It used forms authentication, and we could get some of the pages to load, but none of the images would load. I had confirmed that the application pool identity was a member of IIS_IUSRS, but the problem persisted.

Process Monitor was invaluable in diagnosing this issue. After filtering its process name to w3wp, It revealed that we were getting 'access denied' messages trying to fetch the images running under the context of NT AUTHORITY\IUSR:



After researching this a bit ("401.3 Unauthorized Due to ACL on Resource," "Thread: IUSR Built-in Account Associated with Users Group?" ) I took a look at the ACL for the images folder. In building the server, someone had removed the built-in Users group from having any permissions on C:\inetpub or its descendants. NT AUTHORITY\IUSR relies on its intrinsic membership in the built-in Users group to get rights to any anonymous access folders, so NT security was shutting us down. I replaced the rights at C:\inetpub with the defaults I found on another unmodified web server and the site began to work:



Thursday, June 10, 2010

Android, Eclipse, and Windows 7 x64

I'm diving into Android development these days. While the platform shows a lot of promise and provides many compelling features, I had a few speed bumps getting started with Android development in Eclipse, the predominant IDE. I had a fairly recent version (dated Dec. 2009, I believe) of Eclipse Galileo installed from a previous project to which I wanted to add the Android SDK and plugin. My initial installation attempt was not successful--while the SDK installed properly and would load the Android SDK and AVD Manager, and the plugin itself also reported a successful installation, there was no evidence of Eclipse knowing anything about Android--there were no project templates, samples, or preferences.

Thinking that this was due to the age of my Eclipse installation, I renamed the Eclipse installation folder and fetched a fresh download of the latest version. My second installation attempt appeared to work with the new copy; the Android plugin registered properly this time and I was able to create and debug projects. Then I tried to install a second plugin--the Team Explorer Everywhere 2010 plugin for Eclipse--and voila, not only did all of the Android bits vanish, but the TFS plugin didn't register either.

I started looking at my folder locations. My workstation is a Windows 7 x64 with UAC enabled. Eclipse was deployed to C:\Program Files (x86)\Eclipse, and I had dropped the Android SDK folder into C:\Program Files (x86)\Eclipse\android-sdk-windows ("put it anywhere," I thought...). I had a suspicion that UAC was interfering with Eclipse's plugin management, so I moved the entire Eclipse installation folder including the Android bits to my user folder, adjusted the Android Eclipse plugin setting and system path entry for the SDK location, and tried again. This time, I was able to get the Android plugin to function, but when I tried to create projects from the Android samples, I got access control errors on the .project file of anything I tried to open.

In the end, the following cookbook worked:
  • Eclipse installed to %USERPROFILE%\Documents\eclipse
  • Android SDK installed to %USERPROFILE%\Documents\android-sdk-windows and set up in that location (ran the tool to download all of the SDK components directly there)
  • Plugins installed in Eclipse via the standard method (Help | Install New Software)
After doing this, all of the plugins played nicely with each other, and I no longer got warnings creating the Android sample projects.

Saturday, April 17, 2010

Someone please tell me...

...why the Adobe Reader updater, popping up on a freshly-rebooted Windows system, says a system restart is required? What, is PDF functionality part of the kernel?

Wednesday, March 17, 2010

Error moving the Zenoss database to a new MySQL server

We recently grew our Zenoss 2.3.3 installation by installing a dedicated MySQL server and moving the events database to that server. Events were being collected and written, but we could not move any events to history, and the zenactions log showed the following:
2010-03-17 05:31:26 ERROR zen.Events: (1449, "The user specified as a definer ('zenoss'@'localhost') does not exist")
It turns out this error was coming from MySQL. There is a trigger, status_delete, on the events.status table that controls moving events to history; apparently, the application code is designed to simply delete the status table rows when instructed, and the trigger then moves the rows to the history table. The trigger has a definer specified that indicates the zenoss user must be @locahost (yes, that bold code is commented out):

CREATE
    /*!50017 DEFINER = 'zenoss'@'localhost' */
    TRIGGER `status_delete` BEFORE DELETE ON `status`
    FOR EACH ROW INSERT INTO history SET
            dedupid=OLD.dedupid,
            evid=OLD.evid,
            device=OLD.device,
            component=OLD.component,
            eventClass=OLD.eventClass,
            eventKey=OLD.eventKey,
            summary=OLD.summary,
            message=OLD.message,
            severity=OLD.severity,
            eventState=OLD.eventState,
            eventClassKey=OLD.eventClassKey,
            eventGroup=OLD.eventGroup,
            stateChange=OLD.stateChange,
            firstTime=OLD.firstTime,
            lastTime=OLD.lastTime,
            COUNT=OLD.count,
            prodState=OLD.prodState,
            suppid=OLD.suppid,
            manager=OLD.manager,
            agent=OLD.agent,
            DeviceCLass=OLD.DeviceClass,
            Location=OLD.Location,
            Systems=OLD.Systems,
            DeviceGroups=OLD.DeviceGroups,
            ipAddress=OLD.ipAddress,
            facility=OLD.facility,
            priority=OLD.priority,
            ntevid=OLD.ntevid,
            ownerid=OLD.ownerid,
            deletedTime=NULL,
            clearid=OLD.clearid,
            DevicePriority=OLD.DevicePriority,
            eventClassMapping=OLD.eventClassMapping,
            monitor=OLD.monitor;
$$

DELIMITER ;

I fixed it by changing it to the following, and then dropping and recreating the trigger:

CREATE
    TRIGGER `status_delete` BEFORE DELETE ON `status`
    FOR EACH ROW INSERT INTO history SET
            dedupid=OLD.dedupid,
            evid=OLD.evid,
            device=OLD.device,
            component=OLD.component,
            eventClass=OLD.eventClass,
            eventKey=OLD.eventKey,
            summary=OLD.summary,
            message=OLD.message,
            severity=OLD.severity,
            eventState=OLD.eventState,
            eventClassKey=OLD.eventClassKey,
            eventGroup=OLD.eventGroup,
            stateChange=OLD.stateChange,
            firstTime=OLD.firstTime,
            lastTime=OLD.lastTime,
            COUNT=OLD.count,
            prodState=OLD.prodState,
            suppid=OLD.suppid,
            manager=OLD.manager,
            agent=OLD.agent,
            DeviceCLass=OLD.DeviceClass,
            Location=OLD.Location,
            Systems=OLD.Systems,
            DeviceGroups=OLD.DeviceGroups,
            ipAddress=OLD.ipAddress,
            facility=OLD.facility,
            priority=OLD.priority,
            ntevid=OLD.ntevid,
            ownerid=OLD.ownerid,
            deletedTime=NULL,
            clearid=OLD.clearid,
            DevicePriority=OLD.DevicePriority,
            eventClassMapping=OLD.eventClassMapping,
            monitor=OLD.monitor;
$$

DELIMITER ;

I did try just dropping and recreating the trigger without the change, but it seems the "commented out" definer was responsible for our error, as I duplicated the same error when trying to delete events from the mysql client directly as user zenoss. I then removed the comment completely and recreated the trigger, and the “move to history” function began working.

Note that the age_events stored procedure also has a localhost definer. If you script it out and change the definer specification to the IP of the Zenoss server, that too will function.






Monday, March 08, 2010

Deleting all devices from Zenoss with zendmd

We upgraded our Zenoss 2.3.3 installation to 2.5.2 in a test environment, but wanted to retain only a few of the hundreds of devices that were monitored by the system. We tried deleting these from the web UI, but it would not complete--it always timed out and never seemed to delete anything. I then turned to a zendmd script, which worked wonders:
for dev in dmd.Devices.getSubDevices():
  print dev.id
  dev.deleteDevice()
commit()
reindex()
commit()
This ran quickly and took out all of our devices. We then added back in the ones we wanted. Note: this does not delete performance graphs or events for the affected devices, so you can add them back in and still have this information available.

Friday, February 05, 2010

Using Caliburn inside of Windows Forms with WPF UserControls/ElementHost

I'm working to have a little MVVM action inside of our application, but it's Windows Forms, so I am using an ElementHost to get the WPF UserControl objects loaded. There are aspects to MVVM that cry out for frameworks to help you (binding double-click events to ListViewItem objects being one important one for me). I tried about a million things to get the very powerful Caliburn WPF application framework to do something--anything--in this hybrid context. It was the last thing I tried that worked! ;)

There seem to be two key things you must do to get Caliburn properly registered and listening in this context:
  1. You have to use the "WithAssemblies" option on the framework configuration call, passing in a reference to the current assembly, along with the "WithPresentationFramework" call.
  2. You must spin up Caliburn before the entry point UserControl is initialized and assigned to the ElementHost. If the UserControl is set as the Child via the Windows Forms designer, this means that you must initialize Caliburn in the Form containing the ElementHost's constructor before its InitializeComponent call.
    public partial class Form1 : Form
    {
        public Form1()
        {
            CaliburnFramework.ConfigureCore()
                .WithAssemblies(System.Reflection.Assembly.GetExecutingAssembly())
                .WithPresentationFramework()
                .Start();
            InitializeComponent(); // must come after the above
        }
    }

I went down several dead-ends before discovering this, such as thinking I needed a non-null System.Windows.Application.Current class, thinking I needed to initialize the framework inside of the UserControl's constructor, etc. I hope this helps someone.

You can download the sample application here.


Wednesday, January 20, 2010

Silent Installation of Microsoft MapPoint 2009 -- without changing browser settings

I had the pleasure of working with a friend of mine on performing silent installations of Microsoft MapPoint 2009. Out of the box, MapPoint's installer prompts the user for several settings, and by default has checked to change the home page and default search provider to Live/Bing Search as well as to install the Live Search toolbar. While you can get it to perform a silent installation without too much trouble and omit the toolbar as part of this, it still changes the browser settings during the installation, unless you perform the following procedure we discovered...

1) Create an administrative installation
Insert/explode your MapPoint DVD/iso and get a command prompt open to that location. Run:
Setup.exe /a
This will prompt you for a location in which to place the administrative/server installation.

2) Edit Setup.ini to turn off Live Toolbar installation
Working now in the server installation folder, edit Setup.ini in its root and change the following setting from 1 to 0:
[LIVETOOLBAR]
INCLUDE_LIVETOOLBAR=0
3) Edit data.msi to disable browser settings changes
There are no settings we could find exposed in the setup.ini to turn off taking over the browser settings. To disable this behavior, we edited data.msi (at .\mappoint\MSMap\data.msi in the admin installation folder), which is one of the MSI files called by MapPoint setup. Editing the MSI requires a tool called Orca that is part of the Windows SDK (we used version 6.0a). After installing the Windows SDK, I found Orca's installation MSI located at C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\Orca.Msi. First, double-click this MSI to install Orca, then run the tool.

In Orca then, open data.msi from the admin installation folder. This shows you the series of tables and components within the MSI with their values used. There are several components you need to change under the tables listed below. You are editing the Condition field. HINT: sort the tables on condition and all of these will be grouped together.
  • Component > MP_NA_IE_Homepage: SETLIVEHOMEPAGE<>"0" AND NOT Installed
  • InstallExecuteSequence > SetLiveSearchAsIE6SearchEngine: SETLIVESEARCHSERVICE<>"0" AND IEBUILDVERSION<70000 AND NOT Installed
  • InstallExecuteSequence > ResetDefaultSearchProvider: SETLIVESEARCHSERVICE<>"0" AND IEBUILDVERSION>70000 AND (LIVESEARCHSTATE=0 OR LIVESEARCHSTATE=1) AND NOT Installed
  • InstallExecuteSequence > InstallAndSetLiveSearchProviderAsIE7Default: SETLIVESEARCHSERVICE<>"0" AND IEBUILDVERSION>70000 AND LIVESEARCHSTATE=0 AND NOT Installed
  • InstallExecuteSequence > SetLiveSearchInstallAndSetAsDefaultGuid: SETLIVESEARCHSERVICE<>"0" AND IEBUILDVERSION>70000 AND LIVESEARCHSTATE=0 AND NOT Installed
  • InstallExecuteSequence > SetLiveSearchProviderAsIE7Default: SETLIVESEARCHSERVICE<>"0" AND IEBUILDVERSION>70000 AND LIVESEARCHSTATE=1 AND NOT Installed
  • InstallExecuteSequence > SetLiveSearchSetAsDefaultGuid: SETLIVESEARCHSERVICE<>"0" AND IEBUILDVERSION>70000 AND LIVESEARCHSTATE=1 AND NOT Installed
  • InstallExecuteSequence > GetLiveSearchProviderState: SETLIVESEARCHSERVICE<>"0" AND IEBUILDVERSION>70000 AND NOT Installed
Finally, edit the Value field of the Property table to put those zeroes into the stored settings:
  • INSTALLLIVETOOLBAR: 0
  • SETLIVEHOMEPAGE: 0
  • SETLIVESEARCHSERVICE: 0
The INSTALLLIVETOOLBAR setting may not need to be tweaked as it does seem to respond to the Setup.ini setting, but we turned it off for good measure.

Once you are done editing the values, save the MSI as data.msi and replace the one in the MapPoint admin installation folder.

4) Perform a silent installation

With your shiny new modified administrative installer, get a command prompt open and run:
Setup.exe /quiet
You will see msiexec.exe running in Task Manager but there will be no visible prompts. Once those terminate, MapPoint 2009 is installed, and it should have left your browser settings alone.

Enjoy!