Windows Azure Startups

Una de las cosas que más me gustan de la plataforma Windows Azure es que nuestras soluciones se convierten en un paquete capaz de acondicionar su entorno de vida :) Todos aquellos pasos previos, como la instalación de librerías, configuración de puertos en el firewall, etcétera, podemos definirlos gracias a la sección Startup del archivo ServiceDefinition.csdef.

Esta sección nos permite ejecutar cualquier tipo de acción desatendida que sea necesaria para cada una de las instancias de nuestro rol. Para verlo con un ejemplo, voy a mostrar cómo sería posible la instalación de las librerías de ASP.NET MVC 3, ya que, a día de hoy, estas no están disponibles por defecto en las imágenes que utilizan las instancias de Windows Azure.

En primer lugar, creamos un projecto de tipo cloud sin seleccionar ningún rol. Para poder añadir un proyecto del tipo ASP.NET MVC 3, seleccionamos con el botón derecho sobre la solución y hacemos clic sobre Add -> New Project…

por último seleccionamos la plantilla ASP.NET MVC 3 Web Application (En mi caso la plantilla que he utilizado fue Internet Application) y esperamos a que la misma se genere.

Si llegados a este punto pulsamos F5 para ejecutar la aplicación, Visual Studio nos informará del siguiente error:

El motivo es que, si bien hemos añadido una aplicación web a nuestro proyecto, la misma no está asociada con el proyecto cloud. Para ello, nos posicionamos en la carpeta Roles y, haciendo clic con el botón derecho sobre ella, seleccionamos Add -> Web Role Project in solution…

Pulsamos F5 para comprobar que en local todo funciona correctamente :)

Una vez que tenemos nuestro proyecto listo, descargamos el ejecutable para la instalación llamado AspNetMVC3ToolsUpdateSetup.exe desde el siguiente enlace.

Este archivo debemos incluirlo dentro del proyecto y modificar las propiedades del mismo para que sea copiado en el paquete que posteriormente subiremos a la nube.

¡Perfecto! Ya tenemos nuestra solución con una aplicación ASP.NET MVC 3 y el ejecutable que instalará las librerías necesarias para que el sitio web funcione en Windows Azure. Como último paso, debemos definir el apartado Startup y definir una tarea donde indiquemos que es necesario instalar ASP.NET MVC 3 antes de que la aplicación esté disponible para los usuarios. Para ello, abrimos el archivo ServiceDefinition.csdef donde añadimos la sección Startup con los siguientes valores:

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="Startups" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="MyASPNETMVC3">
<Startup >
<Task commandLine ="installaspnetmvc3.cmd" executionContext="elevated" taskType="simple"></Task>
</Startup>
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
</Endpoints>
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
</WebRole>
</ServiceDefinition>

Dentro del apartado Startup podemos tener tantas tareas como sean necesarias con los siguiente parámetros:

  • commandLine: Recibe como valor el nombre del programa o script que queremos ejecutar. En este caso vamos a invocar a un archivo llamado installaspnetmvc3.cmd, el cual situaremos en la raiz del proyecto web.

    En él vamos a incluir la llamada al archivo AspNetMVC3ToolsUpdateSetup.exe con la opción /q para indicar que debe ser una instalación “silenciosa” o desatendida ;)
    E:approotfilesAspNetMVC3ToolsUpdateSetup.exe /q
  • Nota: Existe un problema a la hora de generar scripts desde Visual Studio, el cual añade un byte para marcar todos los ficheros por defecto. Para evitar incidentes, recomiendo crear estos archivos con Notepad o modificar las opciones de guardado en File -> Advanced Save Options… donde deberemos seleccionar Unicode (UTF-8 without signature) – Codepage 650001 encoding.

  • executionContext: Nos permite indicar el nivel de permisos que queremos que tenga la tarea (limited o elevated)
  • taskType: Dependiendo de la implicación que tenga nuestra tarea en relación con el rol, podemos elegir entre:
    • simple: Se trata del tipo de tarea síncrona, la cual paraliza cualquier proceso hasta que la misma termina. Si no especificamos ningún tipo, esta es la opción por defecto.
    • background: Nuestra tarea se ejecutará a la par que otras (la ejecución de nuestro rol por ejemplo).
    • foreground: A diferencia del tipo anterior, cuando especificamos una tarea foreground esta se ejecutará de manera asíncrona como la anterior. La peculiaridad consiste en que el rol no podrá detenerse hasta que dicha tarea haya finalizado.

Si desplegamos nuestra aplicación en Windows Azure, podremos disfrutar de ASP.NET MVC 3 gracias a Startup section :D

Espero que haya sido de utilidad :)

¡Saludos!

Zune: No installation media. Can’t find the media for installation package Windows Media Format SDK

Ahora que he vuelto de nuevo a mi Windows Phone 7, necesitaba instalar Zune para poder sincronizar todo mi stuff. Una vez descargado el paquete de instalación de la página oficial de Zune, me encuentro con el siguiente error:

Despues de pasarme un buen rato navegando, descubro que el problema es mi versión del sistema operativo: Windows 7 Ultimate N
A día de hoy existen distintos tipos de ediciones:

  • Windows 7: Esta edición sería la “estándar” donde incluye todo el repertorio típico de los sistemas operativos Windows para aquellos clientes que residen en países pertenecientes al Espacio Económico Europeo, Croacia y Suiza.
  • Windows 7 K: Sería la edición estándar, al igual que la anterior, pero para Corea.
  • Windows 7 N: Con esta edición podemos elegir nuestro propio reproductor multimedia y el software que queramos utilizar para administrar y reproducir CDs, DVDs, etcétera, es decir, no incluye Windows Media Player 12 por defecto como las dos versiones anteriores. Esta edición está pensada para los clientes del Espacio Económico Europeo, Croacia y Suiza al igual que la edición Windows 7.
  • Windows 7 KN: Exactamente igual que la versión anterior pero para Corea.

El problema reside en que es necesario tener instalado Windows Media Player 12 para poder instalar Zune en el sistema :( . Tanto si tenéis la versión N como la KN y aún así quereis tener Zune en vuestro equipo, es necesario descargar e instalar Media Feature Pack for Windows 7 N with Service Pack 1 and Windows 7KN with Service Pack 1 (KB968211)

Para más información sobre las ediciones N puedes consultar esta página.

Espero que sea de utilidad :D

¡Saludos!

Windows Azure Accelerator for Umbraco

Meses atrás explicaba en un artículo que escribí para MSDN España cómo era posible subir el CMS de Umbraco a Windows Azure. Si bien vimos que era posible, existían diversas dificultades que hacían de este gestor un funcionamiento algo desorientado a las aplicaciones escalables. El mayor problema era que el propio CMS almacenaba parte del contenido del sitio web en local, por lo que hacía imposible aumentar el número de frontales/instancias sin tocar el código fuente de Umbraco :( .

Después de la presentación en el MIX 2011 ya disponemos de un nuevo acelerador, con el que conseguimos desplegar la última versión del CMS adaptada de la siguiente manera:


Utilizando este esquema lo que se consigue es disponer de múltiples instancias de nuestro sitio web sincronizadas en todo momento (cada segundo) a través de un método llamado SyncForever dentro de la clase WebRole, típica  de los proyectos de Windows Azure como punto de entrada.

public override void Run()
{
    this.SyncForever(TimeSpan.FromSeconds(1));
}

Para descargar esta herramienta se puede hacer desde su sitio en codeplex.

Más información

¡Saludos!

Windows Azure Diagnostics (SDK 1.4)

En este post vamos a pararnos un poco más en profundidad en cada una de las fuentes de diagnóstico disponible a través de Microsoft.WindowsAzure.Diagnostics.dll.
Un punto importante a la hora de utilizar el sistema de diagnósticos de Windows Azure es que este trabaja conjuntamente con Windows Azure Storage, donde vamos a almacenar toda la información que cada una de las fuentes disponibles nos facilite.
Antes de centrarnos en la configuración, veamos qué podemos recuperar de nuestras instancias y dónde se almacena:
Fuente Descripción Destino
Windows Azure Logs En estos logs se guardan todas aquellas trazas registradas a través de la clase System.Diagnostics.Trace. Tabla
Performance Counters Se almacenan los contadores de rendimiento configurados previamente. Tabla
Windows Azure Diagnostic Infrastructure Logs Son todos aquellos registros relacionados con el servicio de Windows Azure. Tabla
Windows Event Logs Podemos añadir tanto fuentes predeterminadas de Windows, como System o Application, como aquellas dadas de alta programáticamente. Tabla
Crash Dumps Volcados de memoria de nuestra aplicación. Blob
Custom Error Logs Esta opción nos permite dar de alta nuestros propios logs dentro del proceso de transferencia de Windows Azure Diagnostics para poder recuperar los mismos a través del storage. Blob
IIS 7.0 Logs Podemos recuperar toda la información generada de forma automática relacionada con IIS Blob
Failed Request Logs Almacena información sobre aquellas peticiones fallidas de IIS Blob
Si bien cada una de las fuentes tiene su propia configuración, lo primero que debemos recuperar es la configuración inicial por defecto de los diagnósticos de la siguiente manera:
//We need to get default initial configuration
var config = DiagnosticMonitor.GetDefaultInitialConfiguration();

Generalmente esta configuración se recupera y se modifica en el archivo WebRole.cs o WorkerRole.cs en el método OnStart ya que es el punto de entrada de nuestra aplicación y se ejecuta cuando nuestras instancias se están iniciando.

En los siguientes apartados utilizaremos el objeto config para configurar cada una de las fuentes.

Windows Azure Logs

Esta primera fuente lo que nos va a permitir es almacenar en una tabla, generada de forma automática por el sistema de diagnósticos llamada WADLogsTable, todas aquellas líneas de registro que realicemos en nuestro código a través de System.Diagnostics.Trace, como por ejemplo:

Trace.WriteLine("WorkerRole_Diag entry point called", "Information");

Para poder recuperar estas trazas, debemos añadir el siguiente código:

//Windows Azure Logs. Table: WADLogsTable
config.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
config.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(5);

Performance counters

Una de las fuentes más importantes para poder conocer el rendimiento de nuestros sistemas trata de los contadores de rendimiento. Para poder conocer cuál sería el nombre del contador que queremos añadir, podemos localizarlos en nuestro propio sistema:

Una vez elegidos los que queramos auditar, los agregamos al sistema de diagnóstico de la siguiente manera:

//Performance counters. Table: WADPerformanceCountersTable
 config.PerformanceCounters.DataSources.Add(
    new PerformanceCounterConfiguration
    {
        CounterSpecifier = @"Processor(*)*",
        SampleRate = TimeSpan.FromSeconds(1)
    }
 );

 config.PerformanceCounters.DataSources.Add(
    new PerformanceCounterConfiguration
    {
        CounterSpecifier = @"Memory*",
        SampleRate = TimeSpan.FromSeconds(1)
    }
 );

config.PerformanceCounters.ScheduledTransferPeriod = TimeSpan.FromMinutes(5);

Windows Azure Diagnostic Infrastructure Log

Cuando trabajamos en local con development fabric podemos visualizar una consola por cada instancia que tengamos de nuestros roles donde nos facilita información de su estado.

Para poder recuperar esta información utilizaremos DiagnosticInfrastructureLogs para recuperar esta información en forma de tabla, la cual recibirá el nombre WADDiagnosticInfrastructureLogsTable:

//Windows Azure Diagnostic Infrastructure Logs. Table: WADDiagnosticInfrastructureLogsTable
config.DiagnosticInfrastructureLogs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
config.DiagnosticInfrastructureLogs.ScheduledTransferPeriod = TimeSpan.FromMinutes(5);

Windows Event Logs

El visor de eventos de Windows creo que es algo que no necesita presentación :D . También podemos recuperar esta información a excepción de la fuente Security. Estos datos se nos presentarán a través de la tabla WADWindowsEventLogsTable.

//Windows Event Logs. Table: WADWindowsEventLogsTable
config.WindowsEventLog.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
config.WindowsEventLog.DataSources.Add("Application!*");
config.WindowsEventLog.DataSources.Add("System!*");
config.WindowsEventLog.ScheduledTransferPeriod = TimeSpan.FromMinutes(5);

Crash Dumps

Uno de los clásicos no podía faltar :) Todo lo relacionado con los volcados de memoria se puede conseguir utilizando estas líneas:

//Crash Dumps. Blob. Container: wad-crash-dumps
CrashDumps.EnableCollection(true);
config.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);

En este caso debemos tener en cuenta dos pasos: CrashDumps.EnableCollection nos permite habilitar la recolección tanto de mini dumps (parámetro a false) o full dumps (parámetro a true). Si sólo indicamos esta línea lo que vamos a conseguir es el almacenamiento local de estos volcados de memoria, pero no serán transferidos a nuestro storage. Para conseguir este segundo paso debemos especificar cada cuánto tiempo vamos a realizar la transferencia de los directorios de diagnóstico a través de config.Directories.ScheduledTransferPeriod como se indica en la segunda línea del código anterior.

Custom Error Logs

Imaginemos que ya tenemos un sistema de diagnóstico de terceros que no deseamos modificar, pero aun así queremos recuperar los ficheros generados de todas las instancias para poder procesarlos. En este caso podemos crear nuevos directorios de diagnóstico, lo cual nos va a permitir que los mismos sean transferidos cada cierto tiempo a los blobs de nuestra cuenta de storage:

//Custom Error Logs
var localResource = RoleEnvironment.GetLocalResource("CustomErrorStorage");
var directoryConfiguration = new DirectoryConfiguration
{
    Container = "wad-mycustom-log-container",
    DirectoryQuotaInMB = localResource.MaximumSizeInMegabytes,
    Path = localResource.RootPath
};

config.Directories.DataSources.Add(directoryConfiguration);
config.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);

IIS Logs

En el caso de los logs de IIS basta con configurar el tiempo de transferencia del apartado Directories, ya que se genera una carpeta donde almacena de forma automática la información:

config.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(5);

Failed Request Logs

Esta fuente está relacionada también con Internet Information Services tras la cual podemos recuperar todas aquellas peticiones fallidas. A excepción del resto, para poder configurar la misma debemos modificar el archivo web.config de nuestro web role para añadir la sección tracing dentro de system.webServer:
<system.webServer>
   <!-- Blob. Container: wad-iis-failedreqlogfiles -->
     <tracing>
       <traceFailedRequests>
          <add path="*">
             <traceAreas>
                <add provider="ASP" verbosity="Verbose" />
                <add provider="ASPNET"
                     areas="Infrastructure,Module,Page,AppServices"
                     verbosity="Verbose" />
                <add provider="ISAPI Extension" verbosity="Verbose" />
                <add provider="WWW Server"
                areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module"
                verbosity="Verbose" />
            </traceAreas>
            <failureDefinitions timeTaken="00:00:15" statusCodes="400-599" />
          </add>
        </traceFailedRequests>
      </tracing>
 <modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>

Al generar esta información dentro de un archivo, necesitamos indicar el tiempo de transferencia de los directorios de diagnóstico como en los casos anteriores:

config.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(5);

Nota: Todas aquellas fuentes que se almacenan en blobs generan una carpeta dentro del directorio DiagnosticStore para almacenar los archivos con la información. Para poder ser transferidos necesitamos indicar cada cuánto tiempo queremos que se envíe la información a Windows Azure Storage. Este tiempo de transferencia basta con definirlo una vez para todas las fuentes que usen este sistema.

Para que todos estos cambios tengan efecto, debemos iniciar la nueva configuración tomando como parámetros el nombre de la cadena de conexión que utilizará Windows Azure Diagnostics (por defecto Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString) y el objeto config que hemos personalizado:

//Start with new configuration
DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", config);

Por último, como recomendación, existe una aplicación de Cerebrata llamada Azure Diagnostics Manager la cual nos va a facilitar mucho la interpretación de toda esta información de una forma muy visual y organizada.

Adjunto un proyecto de ejemplo donde podemos probar cada uno de los casos ;)

Espero que sea de utilidad :D

¡Saludos!