Wednesday, May 27, 2015

Handling Errors from Non-cmdlets in PowerShell

Lately I have found myself implementing multiple builds with TFS that basically just call PowerShell scripts. One of the issues that I have with these scripts is getting good error reporting back to TFS.

Specifically, the issue comes down to the fact that non-cmdlet commandline tools generally return error codes and are incapable of throwing PowerShell errors when they fail. To get the commandline tools working like cmdlets, I took a page out of James Kovacs book (blog?) and implemented a Exec function:

function Exec([scriptblock]$cmd) { 
    $result = & $cmd 
    if ($LastExitCode -ne 0) {
        throw $result
    } 
    else {
        foreach ($line in $result) {
            Write-Host $line
        }
    }
}

Which you can simply call with:

Exec { sometool.exe "with parameters" }    

In the case of an error, it will throw an exception. Otherwise, the output will be written to standard output.

In the context of TFS, I put together a nice sequence that will fail the build if an exception is thrown.

First, I include the Exec function. You can find it on github gist. This one is slightly modified to output the last 50 lines of output when an error occurs.

Next, wrap all of your Exec calls in a try/catch like so:

try {    
    Exec { sometool.exe "with parameters" }    
} catch {
    Write-Error $_
    Exit 1
}

Now presumably, you will be calling your PowerShell script with an InvokeProcess activity from your Build Process Template. In the scope that the activity will be run, create a variable called ExitCode of type Int32:

Adding an exit code

Now set the Result field of the InvokeProcess activity to the new variable:

Setting the exit code

This will set the return code of your PowerShell build script into the variable you created.

Now add a SetBuildProperties activity after the InvokeProcess activity. In the properties of the SetBuildProperties activity, in the PropertiesToSet field check off Status. Then set the Status field to

If(ExitCode = 0, BuildStatus.Succeeded, BuildStatus.Failed)

Setting the build property

Now when your script throws an error, it will return an exit code of 1 and that will be caught by TFS which will fail the build. I acknowledge that it is ironic to convert the tool’s return code to an exception and then back to a return code, but that is what is necessary to have it flow through to TFS correctly.

Wednesday, May 20, 2015

Octopus Deploy: Protecting Yourself from Variable Replacement Errors

Almost every one of my deployments with Octopus Deploy involves a step where variables are replaced in configuration files. Frequently we encounter the case where a variable has not been properly replaced. Now I am not implying there is a bug in Octopus, but rather that mistakes happen. Regularly.

Some time we misspell a variable in either Octopus or the config file, or we add a variable to the config and not Octopus, etc… The deployment succeeds, but the application doesn’t work. It’s common enough, that one of the first troubleshooting steps we perform is to search the config file for #{ and see if anything is found.

I got a little bit of time a few weeks ago and put together a script to help resolve this issue in the future.

Source code for Find-Unreplaced PowerShell cmdlet

The script will look in the files you specify for the pattern #{...}. You can also specify the folder to look in, if you want the cmdlet to search recursively, and if matches should throw an error. The output includes the full path of the file, the unreplaced variables that it found and the line number they were found on.

Here are a few examples:

Find-Unreplaced -Path $OctopusOriginalPackageDirectoryPath -Exclude *.Release.config -Recurse -TreatAsError

This will look recursively through the path your package was install to and if any unreplaced variables are found, it will throw an error. You could put this at the end of you Deploy.ps1 and this would actually cause the deployment to fail. The -Exclude *.Release.config is because we should have unreplaced variables in the in files like web.release.config.

Find-Unreplaced -Path .\ -Recurse

In this case the script is looking the current directory, and again, recursing. No files are excluded and it’s just using the default Files parameter of *.config. It will issue a warning if matches are found. You might put this in your PostDeploy.ps1

Now I commonly use this script with the -TreatAsError flag set and catch this type of error immediately during the deployment.

Wednesday, May 13, 2015

KDE Multiple Monitors

Where Did my Monitor Go?

I was having an issue with blurry fonts on my workstation. To test if it was user specific, I created a new user and logged in. After determining that it wasn’t, I logged out and deleted the user. That is when things went pear-shaped. Suddenly my multiple monitors were not working correctly. Somehow xorg or KDE had swapped the two monitors around and now my left monitor acted as though it was on the right.

I started playing around with the NVidia settings and that just made things worse. Suddenly, my two desktops had different backgrounds (where they used to be the same image). The right monitor had an image I had set months and months ago. The weird thing is that although the monitor was on and I could move my mouse to it, I could not drag any windows onto it. Xorg saw the monitor, but KDE did not. Or that is as far as I figured.

When I ran xrandr it was said the second monitor was disconnected. At this point I deleted the .kde/share/config/krandrrc file, because in the past these files have interfered with my config. Of course, that did nothing because xrandr could not even see the second monitor.

I have seen this issue before and I know it is a problem with X, so I did the only thing I could think of and deleted the xorg.conf file (if you see a pattern here… yeah, I pretty much just start deleting config files at random when stuff goes haywire). I re-ran the NVidia settings and created a new config file. That seemed to fix the issue. Running xrandr showed that both monitors were connected.

A Love Letter to KScreen

Now when I booted into KDE my desktop was cloned/mirrored. Of course I do not want two views of the same thing, so I loaded the System Settings and went to Display and Monitors.

Actually, on a side note… there used to be a different config tool that came up when you selected this. When I upgraded from 12.04 to 14.04 it disappeared. What was really awesome about that was that, apparently, it was replaced with a tool called KScreen. Unfortunately, it seems as though someone forgot to tell the Kubuntu team, because the upgrade uninstalled the old tool, but did not install KScreen. That meant that after the install there was nothing in Display and Monitors but Screensavers. I really like how they litter the upgrades with these little Easter eggs, so that every once and a while, you can take a break from getting work done and solve a neat little puzzle.

Still with me? Okay, so I loaded up Display and Monitors, which is really KScreen. Aaaaaand, only one monitor is there. You gotta love it when you solve a problem and the problem is still there. So, at first only one monitor is detected and that is why KScreen shows one. Now both are detected and it is still showing only one. What do I do now?

KScreen only showing one monitor

So I searched Google again, but this time I had to ignore all the results talking about Xorg, because I had that working. After sifting through a few results, I find someone who says that if you’re in the situation I was in, it is probably because both screens ARE ON TOP OF EACH OTHER IN KSCREEN!!! That is right, this crazy program will actually dump both monitors on top each other! I cannot imagine under what would that be helpful, Apparently that is how it represents cloned displays. I think the author(s) of this software really need to rethink the usability of this particular “feature”.

Oh there's my other monitor, duh!

Alright, I moved the screens next to each other to solve this little problem. Finally, I put my computer to sleep and went to bed myself. The next day I loaded up the computer. Since I was actually working on a Font problem… yes, maybe one day I would be able to get some real work done… I wanted to see if it was maybe my monitors that were the issue. So I brought my laptop over and connected it to one of my monitors. If anyone cares at this point, the font problem does seem related to the monitors.

So I disconnected my laptop and plugged the monitor back into my computer and guess what happened? That’s right, they are mirrored again. So I fixed them in my new favourite program. This time I logged out and back in to see if the change stuck. Nope, of course it did not. They are mirrored again. I tried changing it, logging out, back in and again they are mirrored. So, I checked for a .kde/share/config/krandrc and sure enough there is not one.

So here is the deal:

  1. The old configuration tool, that was intuitive and worked, is gone.
  2. It has been replaced with KScreen, which is not installed by default.
  3. KScreen devs think that hiding one of your monitors is a good way to demonstrate that it is cloned.
  4. Settings applied in KScreen only apply to the current session and are not persisted.

So how do I get my settings persisted? I do not know how to author a krandrrc file from scratch. I do not know where they come from. I thought it was KScreen, but apparently not. I did more searching and found about 17 different ways to hack your system to run xrandr commands at bootup, login, etc… Nobody suggested writing a krandrrc file and letting KDE handle it.

One of the guides noted that if you want to get your settings to take and not be overridden by KScreen, you have to disable it as a service:

Shutting KScreen service off

I got thinking that when I boot up, everything seems fine until I log in. As in, xorg is configured correctly and KDM is working correctly (not mirrored), it’s only when I log in that things go off the rails. On a hunch, I decided to do nothing with xrandr and simply turn off the “KScreen 2” service. I figured that it is probably loading at login, not finding a config file and resetting to the defaulted cloned configuration. Not loading it should keep everything configured by X. I gave it a try and rebooted. Voila, everything is working as it should.

Conclusion

I think that maybe now I know why KScreen was not added during the upgrade. It appears that KDE is completely incapable of handling multiple monitor support for you. What was wrong with the old tool? I do not know. But KScreen is a useless in my case. The way it defaults to cloned and hides one of your monitors is asinine. So is the fact that it does not actually store your settings anywhere so that they persist between sessions. Finally, the fact that, because it doesn’t store you settings, it always stomps over your system settings is simply infuriating. To say that it is broken is an understatement.

Linux advocates are always talking about Linux on the desktop. Well, when KDE’s multiple monitor support, in 2014, is behind what you got out of the box with Windows XP in 2001, it’s obvious Linux is not “ready for the desktop”. I have been running Linux for 16 years and I can barely tolerate this nonsense. Put the average computer user through this and watch their heads explode.