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:
DELIMITER ;
I fixed it by changing it to the following, and then dropping and recreating the trigger:
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.

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():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.
print dev.id
dev.deleteDevice()
commit()
reindex()
commit()
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:
You can download the sample application here.

There seem to be two key things you must do to get Caliburn properly registered and listening in this context:
- 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.
- 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 : FormI 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.
{
public Form1()
{
CaliburnFramework.ConfigureCore()
.WithAssemblies(System.Reflection.Assembly.GetExecutingAssembly())
.WithPresentationFramework()
.Start();
InitializeComponent(); // must come after the above
}
}
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:
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:
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.
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:
Enjoy!

1) Create an administrative installation
Insert/explode your MapPoint DVD/iso and get a command prompt open to that location. Run:
Setup.exe /aThis 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]3) Edit data.msi to disable browser settings changes
INCLUDE_LIVETOOLBAR=0
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
- INSTALLLIVETOOLBAR: 0
- SETLIVEHOMEPAGE: 0
- SETLIVESEARCHSERVICE: 0
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 /quietYou 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!
Monday, September 07, 2009
Best practice around Zenoss template bindings
After working with Zenoss Core for a few years now, I wanted to pass along a tip that would have saved me a lot of time had I known it in the beginning: do not bind performance templates to individual devices, or make local modified copies of templates on devices. Once you do this, the device no longer inherits template bindings from the parent device class, but you have no good way to know that this condition exists unless you drill into the device and examine its template bindings.
When you move a device from one class to another, if it lacks local bindings or overridden templates, it will inherit the bindings of the new class. However, this does not occur if you have made any local changes as above. Also, if you bind new performance templates to its parent, it ignores these new bindings if you have made any local changes. I highly recommend that if you need local changes to a device, make a new device class and make the template binding changes to the class. Then, move the device to the new class, and it will pick up the new bindings.
To clear this condition on a device once you have made local changes, you must reset bindings to be those of its container. On the device, go to More | Templates, then use the drop-down arrow next to "Performance templates for device," and finally Reset Bindings.
When you move a device from one class to another, if it lacks local bindings or overridden templates, it will inherit the bindings of the new class. However, this does not occur if you have made any local changes as above. Also, if you bind new performance templates to its parent, it ignores these new bindings if you have made any local changes. I highly recommend that if you need local changes to a device, make a new device class and make the template binding changes to the class. Then, move the device to the new class, and it will pick up the new bindings.
To clear this condition on a device once you have made local changes, you must reset bindings to be those of its container. On the device, go to More | Templates, then use the drop-down arrow next to "Performance templates for device," and finally Reset Bindings.
Updating the UI from a BackgroundWorker in WPF
This approach enabled me to flexibly send messages to objects on the UI thread while processing from a BackgroundWorker object in WPF. Otherwise, the UI thread doesn't update if the BackgroundWorker code tries to manipulate its objects during processing. First I created this UIUpdater:
public delegate void UpdateTextDelegate(string message);To use it, in the BackgroundWorker_DoWork event handler, initialize it and pass it into your objects that implement the background work. Give it a reference to your dispatcher and a delegate that will handle updates from the background thread:
///
/// Sends messages to the UI thread via the dispatcher.
///
class UIUpdater
{
#region ctor
///
/// Initializes a new instance of theclass.
///
/// The dispatcher in scope for the UI.
/// Function that will apply the message to the appropriate control(s).
public UIUpdater(Dispatcher uiDispatcher, UpdateTextDelegate uiUpdateDelegate)
{
if (default(Dispatcher) == uiDispatcher) throw new ArgumentNullException("uiDispatcher");
if (default(UpdateTextDelegate) == uiUpdateDelegate) throw new ArgumentNullException("uiUpdateDelegate");
dispatcher = uiDispatcher;
updateTextDelegate = uiUpdateDelegate;
}
#endregion
#region member variables
Dispatcher dispatcher = default(Dispatcher);
UpdateTextDelegate updateTextDelegate = default(UpdateTextDelegate);
#endregion
#region methods
///
/// Sends the message.
///
/// The message.
public void SendMessage(string message)
{
if (default(string) == message) throw new ArgumentNullException("message"); // allow string.Empty
dispatcher.BeginInvoke(
DispatcherPriority.Normal,
(ThreadStart)delegate() {
updateTextDelegate(message);
});
}
#endregion
}
UIUpdater updater = new UIUpdater(mainWindow.Dispatcher, new UpdateTextDelegate(UpdateStatus));Then from the code doing the background work, you can call the SendMessage delegate to safely pass along the message:
DoMyWork(updater);
updater.SendMessage("Deleting all items from the " + listName + " list...");
Subscribe to:
Posts (Atom)
