Archiv für Kategorie Entwicklung
Arbeiten bei gefühlten 45 Grad
Verfasst von Schakko unter Ajax, BibaBlog intern, Entwicklung, Java, PHP am 31. Juli 2008
Sommerzeit bedeutet nicht immer Ferienzeit – für mich hieß es in den letzten Tagen: Fehler in unserer IT-Infrastruktur fixen, bis die Tastatur glimmt. Unter anderem konnte die Administrationsoberfläche des McAfee ePO 3.61 nicht mehr aufgerufen werden. Überraschenderweise stellte ich nach einiger Zeit fest, dass unsere MSSQL MSDE-Instanz, auf der das ePO liegt, alle Benutzer aus der Datenbank gedroppt hat. Ich konnte mich weder mit Domänen-Administrator, noch mit sa einloggen. Wie das Problem zustande gekommen ist, ist mir ein Rätsel – aber jetzt läuft wieder alles und ich habe gleich auf das ePO 4.0 geupgradet.
Nebenbei etabliert sich langsam aber sicher Trac als ein gutes Bugtracking-System. Unsere komplette Infrastruktur wird über das Trac-Wiki dokumentiert, alle aufgetretenen Fehler kommen inkl. Lösung in den Bugtracker. Unsere Scripte für Backup, Tools u.s.w. liegen in einem zentralen SVN-Repository, das an das Trac angebunden ist.
Sicherlich ist dieser Lösungsansatz nicht unbedingt ITIL-konform, aber er funktioniert und das ganz gut.
Vor zwei Tagen ist in mir auch langsam die Idee des Deployens unserer Anwendungen gereift. Da alle bestehenden Deployment-Tools nicht direkt unseren Anforderungen entsprechen, habe ich beschlossen, etwas eigenes zu bauen.
Unser Deployment-Client läuft als Java-Tool auf den jeweiligen Deploy-Server. Sobald von einem zentralen Server über REST ein Deployment-Prozess getriggert wird, lädt sich das Tool das jeweils zu deployende Artefakt aus unserem Artefakt-Repository und führt die Installation aus. Alle Artefakte sind als ZIP-Datei verfügbar und besitzen eine deploy.xml-Datei. Diese wiederum benutzt Ant-Tasks.
Florian kümmert sich um den Client, damit er auch mal in den Geschmack einer zu programmierenden Servlet-Anwendung unter Java kommt (eingesetzt wird Java 1.5, Jetty und Ant)
Unser momentaner Praktikant hat in den letzten Tagen von mir die Aufgabe bekommen, sich mit dem Zend Framework, CakePHP, Doctrine und Propel auseinander zu setzen. Für den Serverteil unseres Deyploment-Tools, den ich entwickle, habe ich mich für das Zend Framework und Doctrine entschieden.
Was mir besonders beim Zend Framework fehlt, ist die Möglichkeit des Scaffoldings. Zwar existiert ein Proposal, das ist aber weder ausgereift, noch für den Einsatz mit Doctrine gedacht. Im Internet existiert bis dato auch keine vernünftige Zend_Doctrine_Scaffolding-Klasse.
Deshalb habe ich mich heute Nachmittag daran gesetzt, und eine rudimentäre Klasse zusammenzuschustern. Die Ergebnisse lassen sich sicherlich hier in ein paar Tagen bestaunen.
Die Scaffolding-Klasse werde ich übrigens auch für meinen neuen Blog einsetzen. Sobald die Tage wieder etwas länger und dunkler werden, werde ich die komplette Seite auf das Zend Framework und ebenfalls Doctrine umstellen. Unter anderem ist für die neue Seite Google Maps-Integration, Post-Deployment über XML-RPC an andere Blogs, eine neue Bildergalerie, eventuell Anbindung an das Active Directory der Firma und ein bissel AJAX geplant. Das Design soll weiter bestehen bleiben und natürlich bleiben auch alle Einträge erhalten.
ServiceConsoleControl
Verfasst von Schakko unter C#, Dies und das, Entwicklung, Publikationen am 29. Juli 2008
Gestern habe ich ein alt-bekanntes Problem gelöst. Des öfteren muss ich über die Konsole Windows-Dienste neu starten. Da “net restart” nicht existiert, muss man auf
net stop $SERVICE && net start $SERVICE
zurückgreifen.
Außerdem haben wir in unseren Backup-Scripts einige Dienste, die Abhängigkeiten zu anderen Diensten haben (z.B. McAffe EPO, das von MSSQL abhängt). Hier wäre der pragmatische Lösungsansatz
net stop "McAfee Alert Manager" >> %log% net stop "McAfee ePolicy Orchestrator 3.6.1 Application Server" >> %log% net stop "McAfee ePolicy Orchestrator 3.6.1 Server" >> %log% net stop "McAfee ePolicy Orchestrator 3.6.1 Event Parser" >> %log% net stop "McAfee Outbreak Manager" >> %log% net stop "McAfee Log Service" >> %log% net stop "McAfee SpamKiller" >> %log% net stop "SQLAgent$EPOSERVER" >> %log% net stop "MSSQL$EPOSERVER" >> %log% REM Am Ende alles wieder starten
Viel einfacher wäre ein einfaches
net stop MSSQL$EPOSERVER
wodurch alle von diesem Dienst abhängigen Dienste ebenfalls beendet werden.
Soweit so gut, ich habe mich gestern also hingesetzt und das ganze in C# heruntergetippert. scc (angelehnt an sc) unterstützt die Befehle “start, stop und restart”. Der Code dafür lautet:
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceProcess;
using System.Threading;
namespace ServiceConsoleControl
{
/// <summary>
/// Main entry class
/// </summary>
class Program
{
private static String NAME = "scc";
static void Main(string[] args)
{
if (args.Length != 2)
{
ShowUsageAndExit(null);
}
try
{
Command cmd = Command.Factory(args[0]);
cmd.SetServiceName(args[1]);
cmd.Execute();
}
catch (Exception e)
{
ShowUsageAndExit("Error: " + e.Message);
}
}
/// <summary>
/// Shows the usage of this program and exits with code 0
/// </summary>
/// <param name="_line">additional line to print before usage is shown</param>
public static void ShowUsageAndExit(String _line)
{
if (_line != null)
{
Program.LogLine(_line);
}
Program.LogLine(Program.NAME + " starts, stops and restarts services with all dependencies to other services");
Program.LogLine("Usage: " + Program.NAME + " [" + Command.CMD_START + ", " + Command.CMD_STOP + ", " + Command.CMD_RESTART + "] [Service]");
Environment.Exit(0);
}
/// <summary>
/// Write string to console
/// </summary>
/// <param name="_msg">string to write</param>
public static void LogLine(String _msg)
{
Console.WriteLine(_msg);
}
}
/// <summary>
/// Interface for executable service commands
/// </summary>
interface IServiceCommand
{
/// <summary>
/// Execute the command
/// </summary>
void Execute();
/// <summary>
/// Sets name of service
/// </summary>
/// <param name="_name">name of service</param>
void SetServiceName(String _name);
/// <summary>
/// Retrieves name of service
/// </summary>
/// <returns>name of service</returns>
string GetServiceName();
}
/// <summary>
/// Abstract class for commands, implements IServiceCommand
/// </summary>
abstract class Command : IServiceCommand
{
private String _name;
protected ServiceController sc = new ServiceController();
public static String CMD_STOP = "stop";
public static String CMD_START = "start";
public static String CMD_RESTART = "restart";
/// <summary>
/// Factory method for command.
/// Given command will be lowered.
/// If the command is not supported, an exception will be thrown
/// </summary>
/// <param name="_cmd">Command to execute - this can be one of this.CMD_*</param>
/// <returns>Instance of Command</returns>
public static Command Factory(String _cmd)
{
_cmd = _cmd.ToLower();
if (_cmd.Equals(CMD_RESTART))
{
return new RestartCommand();
}
else if (_cmd.Equals(CMD_START))
{
return new StartCommand();
}
else if (_cmd.Equals(CMD_STOP))
{
return new StopCommand();
}
throw new Exception("Unsupported command: " + _cmd);
}
/// <summary>
/// Sets service name, required by IServiceCommand
/// </summary>
/// <param name="_serviceName">Service name to set</param>
public void SetServiceName(String _serviceName)
{
_name = _serviceName;
sc.ServiceName = _serviceName;
}
/// <summary>
/// Gets service name, required by IServiceCommand
/// </summary>
/// <returns>Service name</returns>
public String GetServiceName()
{
return _name;
}
/// <summary>
/// Abstract execute command which is required by IServiceCommand
/// </summary>
abstract public void Execute();
}
/// <summary>
/// Abstract class for recursive commands, can be used for solving dependencies between services
/// </summary>
abstract class RecursiveCommand : Command
{
/// <summary>
/// Depth of dependency
/// </summary>
private int _depth = 0;
/// <summary>
/// Stringbuilder with prefixing spaces
/// </summary>
private StringBuilder sb;
/// <summary>
/// Timespan to wait for service
/// </summary>
protected TimeSpan tsWait = new System.TimeSpan(10000000000000);
/// <summary>
/// Abstract method which retrieves the recursive command
/// </summary>
/// <returns>RecursiveCommand</returns>
abstract protected RecursiveCommand GetCommand();
/// <summary>
/// Depth value
/// </summary>
public int Depth
{
set { _depth = value; }
get { return _depth; }
}
/// <summary>
/// Return depth as spaces
/// </summary>
/// <returns>String with depth as spaces</returns>
protected String GetSpaces()
{
if (sb == null)
{
sb = new StringBuilder();
for (int i = 0; i < _depth; i++)
{
sb.Append(" ");
}
}
return sb.ToString();
}
/// <summary>
/// Executes GetCommand() on all given ServiceController[]
/// </summary>
/// <param name="scs">Array of ServiceController on which the GetCommand() will be executed</param>
protected void ExecuteCommandOnServiceControllers(ServiceController[] _scs)
{
Program.LogLine(GetSpaces() + "Service dependencies: " + _scs.Length);
for (int i = 0, m = _scs.Length; i < m; i++)
{
RecursiveCommand rc = this.GetCommand();
rc.Depth = this.Depth + 1;
rc.SetServiceName(_scs[i].ServiceName);
rc.Execute();
}
}
/// <summary>
/// Returns true if service is of ServiceType Win32ShareProcess or Win32OwnProcess. Other types cannot be killed
/// </summary>
protected bool IsKillable
{
get
{
if (sc.ServiceType.Equals(ServiceType.Win32ShareProcess) || sc.ServiceType.Equals(ServiceType.Win32OwnProcess))
{
return true;
}
Program.LogLine(GetSpaces() + this.DisplayName + " is of type " + sc.ServiceType.ToString() + ". These services can not be processed.");
return false;
}
}
/// <summary>
/// Returns display name
/// </summary>
public String DisplayName
{
get
{
return "Service " + sc.DisplayName + " (" + sc.ServiceName + ")";
}
}
}
/// <summary>
/// Command for restarting a service
/// </summary>
class RestartCommand : Command
{
/// <summary>
/// Stops the service and then restarts
/// </summary>
public override void Execute()
{
IServiceCommand stopCmd = new StopCommand();
IServiceCommand startCmd = new StartCommand();
stopCmd.SetServiceName(this.GetServiceName());
startCmd.SetServiceName(this.GetServiceName());
stopCmd.Execute();
startCmd.Execute();
}
public override String ToString()
{
return CMD_RESTART;
}
}
/// <summary>
/// Command for starting a service with all its dependencies
/// </summary>
class StartCommand : RecursiveCommand
{
public override String ToString()
{
return CMD_START;
}
/// <summary>
/// Retrieve a new instance of myself
/// </summary>
/// <returns></returns>
protected override RecursiveCommand GetCommand()
{
return new StartCommand();
}
/// <summary>
/// Starts a service. The service could only be started if it is Win32[Own|Share]Process. KernelDriver or other types of services are not allowed.
/// At first all services will be started which this service depends on. At second the service itself will be started.
/// After that all services are started which depends on this service.
/// </summary>
public override void Execute()
{
if (this.IsKillable)
{
if (sc.Status.Equals(ServiceControllerStatus.Stopped))
{
Program.LogLine(GetSpaces() + "Starting " + this.DisplayName);
Program.LogLine(GetSpaces() + "Starting all services that " + this.DisplayName + " depends on ...");
ExecuteCommandOnServiceControllers(sc.ServicesDependedOn);
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, tsWait);
Program.LogLine(GetSpaces() + "Service is now in status " + sc.Status.ToString());
Program.LogLine(GetSpaces() + "Starting all services that depends on " + this.DisplayName + " ... ");
ExecuteCommandOnServiceControllers(sc.DependentServices);
}
else
{
Program.LogLine(GetSpaces() + this.DisplayName + " has status " + sc.Status.ToString() + " - nothing to do");
}
}
}
}
/// <summary>
/// Command for stopping a service with all its dependencies
/// </summary>
class StopCommand : RecursiveCommand
{
public override String ToString()
{
return CMD_STOP;
}
/// <summary>
/// Returns an instance of myself
/// </summary>
/// <returns>New instance of StopCommand</returns>
protected override RecursiveCommand GetCommand()
{
return new StopCommand();
}
/// <summary>
/// Executes the command. The service could only be stopped if it is Win32[Own|Share]Process. KernelDriver or other types of services are not allowed.
/// At first all services will be stopped that depends on this service. Then this service is stopped.
/// </summary>
public override void Execute()
{
if (this.IsKillable)
{
if (sc.Status.Equals(ServiceControllerStatus.Running))
{
Program.LogLine(GetSpaces() + "Stopping " + this.DisplayName);
Program.LogLine(GetSpaces() + "Stopping all services that depends on " + this.DisplayName + " ...");
ExecuteCommandOnServiceControllers(sc.DependentServices);
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped, tsWait);
Program.LogLine(GetSpaces() + "Service is now in status " + sc.Status.ToString());
}
else
{
Program.LogLine(GetSpaces() + this.DisplayName + " has status " + sc.Status.ToString() + " - nothing to do");
}
}
}
}
}
Fixe Idee: Wie man die Firefox-Einstellungen per Gruppenrichtlinie verteilt
Verfasst von Schakko unter Active Directory / LDAP, Entwicklung am 3. Juni 2008
Christoph und ich hatten uns heute Mittag über die Erstellung von MSI-Paketen unterhalten – ich hatte vor einigen Tagen unsere Fonts per MSI und Active Directory deployt.
Nun kamen wir wieder einmal auf das Thema “Deployment von Firefox” und Setzen der Einstellungen.
Mein erster Gedanke war, ein eigenes XPCOM-Modul zu schreiben. XPCOM ist wie DCOM auch ein Komponentenmodell und wird von der Mozilla-Truppe voran getrieben. Die XPCOM-Module werden in C++ entwickelt und sind so plattformunabhängig.
Das fiktive XPCOM-Modul würde nun die Daten aus der Registry laden und dementsprechend alle Einstellungen des Firefoxes setzen.
So weit, so gut. Es geht aber auch einfacher: Nach einer kurzen Recherche habe ich heraus gefunden, dass Firefox ab der Version 1.5 das XPCOM-Interface nsIWindowRegKey bereitstellt. Unter http://developer.mozilla.org/en/docs/Accessing_the_Windows_Registry_Using_XPCOM findet sich dazu ein ausführlicher Artikel.
Über das Interface nsIPrefService lassen sich Einstellungen des Firefoxes lesen und schreiben, siehe dazu auch http://developer.mozilla.org/en/docs/nsIPrefService.
Das weitere Vorgehen ist eigentlich trivial. Anstatt eines in C++ geschriebenes XPCOM-Modul wird einfach eine Firefox-Extension in JavaScript geschrieben.
Diese lädt beim Start alle Einstellungen aus z.B. HKCU\Software\Mozilla\Firefox, überprüft die Typen (DWORD, Boolean, String) und setzt über nsIPrefService die Einstellungen.
Damit die Einstellungen über das AD verteilt werden können, ist etwas Handarbeit nötig: eine neue .adm-Datei hält die definierten Einstellungen vor. Mit dieser Vorlage lassen sich alle Einstellungen ganz einfach per Active Directory verteilen.
Mal sehen, ob einer aus unserer Truppe dafür irgendwann mal Zeit hat.
Patch for mod_auth_sspi
Verfasst von Schakko unter Active Directory / LDAP, Apache, Entwicklung, Publikationen am 7. Mai 2008
I finished my patch for mod_auth_sspi. With this patch you get the additional directive SSPIUseActiveDirectoryStyle. You must set SSPIOmitDomain to ‘off’ for using it:
# ... httpd.conf SSPIOmitDomain Off SSPIUseActiveDirectoryStyle On
If enabled, the REMOTE_USER-variable will store the domain-username combination as $USER@$DOMAIN and not $DOMAIN\$USER.
I made this patch, because I am currently working on a seamleas authentication integration for Mediawiki and the extension Auth_remoteuser.
The developers of mod_auth_sspi are contacted and I hope the patch will be accepted.
Kompilieren von mod_auth_sspi unter Visual Studio 2005
Verfasst von Schakko unter Apache, Entwicklung am 29. April 2008
Damit sich mod_auth_sspi unter Visual Studio 2005 kompilieren lässt, muss in mod_auth_sspi.h, Zeile ~32 folgendes hinzugefügt werden:
typedef int pid_t;
Weiterhin muss mod_auth_sspi.rc, Zeile 24 auskommentiert werden:
// #include "version.h"
Was für ein Gefrickel.
Extreme Faulheit – Das DRY-Prinzip in Reinkultur
Verfasst von Schakko unter Effizient arbeiten, Entwicklung, GWT, Java am 18. März 2008
Meine Faulheit hat ein nicht mehr feierliches Maß angenommen: Ich habe gestern für eines unserer Projekte ein Meta-Tool in PHP geschrieben, das aus allen Java-TOs die zugehörigen Dateien erzeugt.
Mit zugehörigen Dateien meine ich damit: BOs, GWT-Service-Implentations, GWT-Service-Definitions, Model-Assemblers, sowie Einträge für web.xml und gwt.xml.
Trotz der Entwicklungszeit des Scripts von ca. 6h habe ich dadurch insgesamt knapp eine Woche an Entwicklungszeit für das Projekt an sich gespart.
Ich bin so faul
Release of Ecw_Java_* 1.0
Verfasst von Schakko unter Eclipse, Entwicklung, PHP am 17. März 2008
I proudly present the Ecw_Java_* classes! The archive includes a README with a short explanation of how to install all corresponding items (BIRT, php-/Java-bridge, Ecw_Java_*).
Comments are welcome.
phpUnderControl: Klick auf Dokumentation führt zu “artifacts… Invalid Directory”
Verfasst von Schakko unter Effizient arbeiten, Entwicklung am 24. Februar 2008
Ich hatte vor ein paar Tagen eine Mail bekommen, in der ich um Hilfe bezüglich phpUnderControl geboten wurde. Einer der Fehler war, dass beim Klick auf “Documentation” nur der Fehler “artifacts… Invalid directory” erschien. Aus zeitlichen Gründen hatte ich das Thema CruiseControl/phpUnderControl auf Eis gelegt, mich heute Abend aber mal an die Problemlösung gemacht.
Der Fehler tritt auf, wenn im
Die beiden artifactspublisher müssen folgendermaßen aussehen:
<artifactspublisher dir="projects/${project.name}/build/api" dest="artifacts/${project.name}" subdirectory="api"/>
<artifactspublisher dir="projects/${project.name}/build/coverage" dest="artifacts/${project.name}" subdirectory="coverage"/>
Bitte das dest-Attribut mit dem richtigen Verzeichnis beachten!
PropertyPage-Extension für MMC “Active Directory Benutzer und Computer” in C#
Verfasst von Schakko unter Entwicklung, Windows am 29. Januar 2008
Ausgangspunkt dieses Artikels war ein Gespräch vor ein paar Tagen: “Wäre schön, wenn wir jedem unserer Mitarbeiter eine Mitarbeiter-Nummer im ActiveDirectory vergeben könnten.”
Ich googelte im Internet und fand diesen Artikel auf InformIT.
Er erklärt recht gut, wie man die Mitarbeiter-Nummer in das passende MMC “Active Directory Benutzer und Computer” einbindet.
Allerdings war ich von der Darstellung nicht sonderlich begeistert: Ich wollte in den Eigenschaften der Mitarbeiter ein eigenes Tab haben. Zuerst suchte ich bei Microsoft und fand einige Dokumente auf den MSDN-Seiten. Allerdings hatte ich kein Nerv auf C++ und entschied mich, MMC 3.0 und .NET bzw. C# zu verwenden.
Mit der Installation des .NET Frameworks 3.5 sollte das MMC-Assembly mitinstalliert werden. Danach suchte ich mir im Internet ein paar Code-Schnippsel zusammen:
Auf einer französische Seite fand ich den Code zum rudimentären Erzeugen einer PropertyPage. Für die Benutzung des Codes muss das MMC-Assembly von C:\WINDOWS\system32\microsoft.managementconsole.dll eingebunden werden.
Mir stellte sich nun die Frage: Wie komme ich an den ausgewählten Benutzer heran?
Die Newsgroup microsoft.public.management.mmc war hilfreich. Ich hatte nun den LDAP-DN des ausgewählten Benutzers. Der Rest war trivial: Mit System.DirectoryServices stellte ich eine Verbindung zum Active Directory her und zog mir die Daten des Benutzers:
DirectoryEntry oUser = new DirectoryEntry(_searchDSN); String employeeNumber = oUser.Properties["employeeNumber"].Value.ToString();
und konnte mit oUser.CommitChanges() meine Änderungen zurück ins AD schreiben.
Mit Hilfe des Tools InstallUtil lässt sich das erstellte Assembly in der Registry verankern und benutzen.
PDT & Auto-Completion mit Interfaces
Verfasst von Schakko unter Eclipse, Entwicklung am 27. Januar 2008
Ich schrieb vor einiger Zeit über den PDT-Bug, dass bei Variablen, die mehr als ein Interface implementieren, die Code-Completion nicht funktioniert.
Gestern kam dann ein Mail vom Entwickler. Workaround ist:
/** * @var if1|if2 */
Siehe auch Eclipse-Bugtracker.
Sag was!