#WhereIsTheCode?
Un lugar mas para los que siempre estamos buscando código.. ;-)
jueves, 16 de julio de 2015
I've moved
Eso, voy a seguirla un tiempo en un Ghost hosteado como Web App Service sobre Microsoft Azure... vamos a ver como resulta =D
viernes, 3 de abril de 2015
Could not load file or assembly Microsoft.WindowsAzure.Packaging
Luego de instalar la última actualización del Azure SDK 2.5.1 para Visual Studio 2013 ya no pude volver a publicar mi Cloud Service. El error reportado era:
Buscando en diferentes sitios pude dar con una comentario de Wayne Kuo en StackOverflow explicando que el problema era originado por un problema en el instalador de la nueva versión del Azure SDK, y que pudieron comprobar que quitando y volviendo a instalar las Microsoft Azure Authoring Tools 2.5.1 el problema se solucionaba.
Las Microsoft Azure Authoring Tools 2.5.1 pueden bajarse desde:
En mi caso bastó con ejecutar la opción Repair del instalador de las Authoring Tools, no fue necesario hacerlo en dos pasos (desinstalar y volver a instalarlas).
Una vez finalizada la reparación de las Microsoft Azure Authoring Tools 2.5.1 pude volver a publicar mi Cloud Service normalmente.
Could not load file or assembly 'Microsoft.WindowsAzure.Packaging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
Error al intentar publicar mi Cloud Service |
Buscando en diferentes sitios pude dar con una comentario de Wayne Kuo en StackOverflow explicando que el problema era originado por un problema en el instalador de la nueva versión del Azure SDK, y que pudieron comprobar que quitando y volviendo a instalar las Microsoft Azure Authoring Tools 2.5.1 el problema se solucionaba.
Azure Authoring Tools Installer |
Las Microsoft Azure Authoring Tools 2.5.1 pueden bajarse desde:
http://download.microsoft.com/download/1/E/7/1E76DD6F-66F1-47E0-A76A-3BBAAC617316/MicrosoftAzureAuthoringTools-x64.msi
http://download.microsoft.com/download/1/E/7/1E76DD6F-66F1-47E0-A76A-3BBAAC617316/MicrosoftAzureAuthoringTools-x86.msi
En mi caso bastó con ejecutar la opción Repair del instalador de las Authoring Tools, no fue necesario hacerlo en dos pasos (desinstalar y volver a instalarlas).
Opción de reparación |
Una vez finalizada la reparación de las Microsoft Azure Authoring Tools 2.5.1 pude volver a publicar mi Cloud Service normalmente.
martes, 17 de marzo de 2015
Como compilar Docker Client en Windows
Desde noviembre de 2014, cuando Ahmet Alp Balkan anunció la disponibilidad de compilar Docker Client sobre Windows, han cambiado algunas cosas.
Acá dejo los comandos que utilicé para compilar el cliente Docker sobre un Windows 8.1 usando Git for Windows, y obviamente Go, el lenguaje en el cual está programado Docker.
Para poder compilar Docker es necesario tener instalado previamente Git for Windows y Go.
Por default el instalador para Windows deja Go en la carpeta C:\Go, y en el ejemplo a continuación se muestra así. Si cambias la carpeta de instalación de Go entonces modifica también la carpeta del primer comando (export GOPATH="c:\go").
Si no queres hacer todo esto podes bajarte el Docker 1.18 compilado en Windows desde esta ubicación: https://seketman.blob.core.windows.net/docker/docker_1.18.exe... mucho mas rápido.
Acá dejo los comandos que utilicé para compilar el cliente Docker sobre un Windows 8.1 usando Git for Windows, y obviamente Go, el lenguaje en el cual está programado Docker.
Requisitos
Para poder compilar Docker es necesario tener instalado previamente Git for Windows y Go.
Por default el instalador para Windows deja Go en la carpeta C:\Go, y en el ejemplo a continuación se muestra así. Si cambias la carpeta de instalación de Go entonces modifica también la carpeta del primer comando (export GOPATH="c:\go").
Procedimiento
- Abrir una consola de Git Bash desde el disco donde está instalado el Go. Para esto dale clic derecho sobre el icono del disco en cualquier explorador de archivos, y selecciona la opción Git Bash que agregó la instalación del Git for Windows.
- En la consola de Git Bash ejecuta los siguientes comandos:
# Get the Docker source export GOPATH="c:\go" cd $GOPATH go get github.com/docker/docker # Compile go-autogen export GOPATH="$GOPATH;$GOPATH\src\github.com\docker\docker\vendor" cd src/github.com/docker/docker hack/make/.go-autogen # Finally compile Docker Client export DOCKER_CLIENTONLY=1 cd docker go build -v
..y listo, en la carpeta $GOPATH\src\github.com\docker\docker\docker te quedó el archivo docker.exe que estabas buscando.
Consola de Git Bash |
Si no queres hacer todo esto podes bajarte el Docker 1.18 compilado en Windows desde esta ubicación: https://seketman.blob.core.windows.net/docker/docker_1.18.exe... mucho mas rápido.
sábado, 14 de marzo de 2015
Microsoft Azure Cloud Service - VIP swap feature
Esto es grandioso porque permite implementar un servicio en el entorno de Staging, probarlo, y cuando está todo ok hacer el swap que lo dejará en Production, pero hay que tener en cuenta que este 'intercambio de implementaciones', o 'promoción del servicio en ensayo al entorno de producción', tal como se nombra en varios documentos, en verdad es solamente un intercambio de punteros (la VIP y URL de cada uno de los entornos), las implementaciones en sí no se ven modificadas por este proceso en su configuración ni estado.
- Cada uno de los entornos de un Cloud Service poseen tres atributos propios:
- Su denominación: Staging o Production
- Una virtual IP pública, o VIP.
- ..y una URL: <nombredns>.cloudapp.net (Production), o <guid>.cloudapp.net (Staging)
- Tanto la VIP como la URL de Staging se mantienen durante todo el ciclo de vida de la implementación mientras no sea borrada (no cambia entre deploys).
- Cuando una implementación es borrada de un entorno recién entonces se liberan estos valores, y al hacer una nueva implementación sobre ese entorno siempre se asigna un nuevo valor de VIP. La URL de Staging <guid>.cloudapp.net solo cambia si este proceso de borrado y nueva implementación se lleva a cabo sobre el entorno de Staging.
- Antes de ejecutar el VIP swap debemos asegurarnos de que la configuración de la implementación en Staging sea la adecuada para pasarla a Production, ya que el proceso no altera ninguno de los valores en cuanto a cantidad de instancias de los roles, ni configuración de autoscaling.
- Las conexiones establecidas con cada implementación al momento de ejecutar el VIP swap se mantendrán así hasta su cierre por parte del cliente o servidor, no serán canceladas por el proceso de intercambio. Solo las nuevas conexiones son dirigidas a la nueva implementación que ocupa cada entorno.
- La opción de VIP swap aún no está disponible en el Preview Portal; para ejecutarlo tendremos que servirnos del Management Portal, o invocando la Microsoft Azure Management Service Rest API directamente, o a través del wrapper que conforman las Microsoft Azure Management Libraries, o MAML.
Sección del Management Portal - Cloud Service Dashboard |
Bueno, sigo leyendo el Exam Ref 70-532 Developing Microsoft Azure Solutions a ver como continúa la historia de los Cloud Services.
sábado, 31 de enero de 2015
Tienda online en ASP.NET 5 sobre Docker
Intro
Entusiasmado con la posibilidad que brinda ASP.NET 5 de correr mis sitios web sobre distintas plataformas, me puse a averiguar y escribir un resumen de como levantar un sitio y correrlo sobre Docker dentro de una VM Ubuntu de Microsoft Azure... la sorpresa fue que no te lleva mas de 10 minutos, y funciona de maravillas.Requisitos
- Suscripción de Microsoft Azure.
- Una VM Ubuntu Trusty 14.04 como mínimo, con el puerto 80 habilitado.
- Estar registrado en Docker.com si queremos salvar allí la nueva imagen creada.
Contenido
- Preparar el contenido de la nueva imagen.
- Construir la imagen Docker con nuestra aplicación.
- Levantar un nuevo container con nuestra imagen.
- Salvar nuestra imagen en Docker Hub.
1. Preparar los componentes de la nueva imagen
La imagen Docker que vamos a crear para correr nuestra aplicación MVC MusicStore estará basada en la microsoft/aspnet publicado por Microsoft meses atrás que, si bien aún está en preview, sirve perfectamente para nuestro propósito.Actualizamos nuestro Ubuntu; instalamos Docker según se explica en docs.docker.com/installation/ubuntulinux; y también nos aseguramos de contar con Git:
sudo apt-get update sudo apt-get install docker.io sudo apt-get install git-core
Por último clonamos en la carpeta local storeapp el proyecto MVC MusicStore de GitHub, con el comando:
git clone http://github.com/aspnet/MusicStore storeapp
2. Construir la imagen Docker de nuestra aplicación
Nos movemos a la carpeta storeapp/src/MusicStore y ahí creamos el archivo Dockerfile que usaremos para configurar nuestra imagen. Podes crear el archivo con nano o el editor que prefieras:cd storeapp/src/MusicStore nano Dockerfile
Copia el siguiente contenido dentro del archivo Dockerfile (las lineas que comienzan con # son comentarios):
# Base image FROM microsoft/aspnet # Copy project folder into image and restore Nuget packages COPY . /app WORKDIR /app RUN ["kpm", "restore"] # Run de web site EXPOSE 5004 ENTRYPOINT ["k", "kestrel"]
..y creamos la imagen usando el comando:
sudo docker build -t storeapp .
Esto demora un poco, paciencia.
3. Levantar un nuevo container con nuestra imagen
Podemos ver las imágenes en nuestro sistema mediante el comando Docker images, luego levantamos nuestra imagen en un nuevo container con run, y por ultimo listamos los containers con el comando ps:sudo docker images sudo docker run -t -d -p 80:5004 --restart=on-failure:10 storeapp sudo docker ps -a
Y ya tenemos nuestra imagen corriendo en un container de Docker en nuestra VM, publicado en el puerto 80 de Ubuntu (no olvides configurar el endpoint en Azure).
4. Salvar nuestra imagen en Docker Hub
Ahora si queremos salvar la imagen en Docker Hub para utilizarla desde cualquier otra VM, o publicarla para la comunidad, podemos agregarle un tag y hacerle un push (previamente tenemos que registrarnos en Docker.com).Tanto el image id (934e56caf9b8), como el nombre de la cuenta registrada (seketman), deben cambiarse por los valores que corresponden:
sudo docker tag 934e56caf9b8 seketman/storeapp:demo sudo docker push seketman/storeapp:demo
Nuestro sitio funcionando |
Pueden ver este sitio corriendo en soundstore.cloudapp.net
Mucha de la info mostrada se basa en el post Running ASP.NET 5 applications in Linux Containers with Docker de Ahmet Alp Balkan.
miércoles, 3 de diciembre de 2014
Universal PredicateBuilder... tunned for Azure AD Graph API queries
Las consultas a la Azure AD Graph API no admiten le sean provistos valores nulos o vacíos, y las opciones de filtro soportadas al día de hoy se limitan a and, or, eq, ge, le, Startswith, y Any.
La Microsoft Azure Active Directory Graph Client Library facilita notablemente el manejo de estas consultas desde las aplicaciones .NET, pero aún es algo incomodo la construcción dinámica de predicados, debido a lo cual recurrí para esta labor al PredicateBuilder generosamente compartido por Pete Montgomery allá por febrero del 2011.
Afortunadamente todo el entorno de Microsoft Azure está evolucionando rápidamente así que es de esperar estas limitaciones no perduren por mucho tiempo, pero comparto esta pequeña solución por si algún otro desarrollador se encuentra ante la misma situación.
Los ajustes introducidos a la versión de Pete fueron mínimos, y solo para asegurar la compatibilidad con los operadores lógicos and y or (Pete usó AndAlso, y OrElse, no soportados por la Graph API).
Consulta de usuarios
Basada en AzureADSamples/ConsoleApp-GraphAPI-DotNetIPagedCollection<IUser> searchResults = null; var predicate = GraphAPIPredicateBuilder.Create<IUser>(u => u.AccountEnabled == true); if (!string.IsNullOrWhiteSpace(canonicalUser.Name)) predicate = predicate.And(u => u.UserPrincipalName.StartsWith(canonicalUser.Name)); if (!string.IsNullOrWhiteSpace(displayname)) predicate = predicate.And(u => u.DisplayName.StartsWith(displayname)); if (!string.IsNullOrWhiteSpace(description)) predicate = predicate.And(u => u.GivenName.StartsWith(givenname)); try { ActiveDirectoryClient activeDirectoryClient = AzureADAuthenticationHelper.GetActiveDirectoryClientAsApplication(); IUserCollection userCollection = activeDirectoryClient.Users; searchResults = userCollection.Where(predicate).ExecuteAsync().Result; } catch (Exception e) { Debug.WriteLine(string.Format("Error searching users - {0} {1}", e.Message, e.InnerException != null ? e.InnerException.Message : "")); }
GraphAPIPredicateBuilder
/// <summary> /// Enables the efficient, dynamic composition of query predicates... tunned for Azure AD Graph API /// /// Based on the work of Pete Montgomery at February 10, 2011 /// http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/ /// </summary> public static class GraphAPIPredicateBuilder { /// <summary> /// Creates a predicate that evaluates to true. /// </summary> public static Expression<Func<T, bool>> True<T>() { return param => true; } /// <summary> /// Creates a predicate that evaluates to false. /// </summary> public static Expression<Func<T, bool>> False<T>() { return param => false; } /// <summary> /// Creates a predicate expression from the specified lambda expression. /// </summary> public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; } /// <summary> /// Combines the first predicate with the second using the logical "and". /// </summary> public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) { return first.Compose(second, Expression.And); } /// <summary> /// Combines the first predicate with the second using the logical "andAlso". /// </summary> public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) { return first.Compose(second, Expression.AndAlso); } /// <summary> /// Combines the first predicate with the second using the logical "or". /// </summary> public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) { return first.Compose(second, Expression.Or); } /// <summary> /// Combines the first predicate with the second using the logical "orElse". /// </summary> public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) { return first.Compose(second, Expression.OrElse); } /// <summary> /// Negates the predicate. /// </summary> public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression) { var negated = Expression.Not(expression.Body); return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters); } /// <summary> /// Combines the first expression with the second using the specified merge function. /// </summary> static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) { // zip parameters (map from parameters of second to parameters of first) var map = first.Parameters .Select((f, i) => new { f, s = second.Parameters[i] }) .ToDictionary(p => p.s, p => p.f); // replace parameters in the second lambda expression with the parameters in the first var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // create a merged lambda expression with parameters from the first expression return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters); } class ParameterRebinder : ExpressionVisitor { readonly Dictionary<ParameterExpression, ParameterExpression> map; ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) { this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); } public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) { return new ParameterRebinder(map).Visit(exp); } protected override Expression VisitParameter(ParameterExpression p) { ParameterExpression replacement; if (map.TryGetValue(p, out replacement)) { p = replacement; } return base.VisitParameter(p); } } }
That's all folks!
jueves, 6 de noviembre de 2014
TFS - MSBuild scripts en el Custom Assembly Path?
Desde el TFS 2010 se introdujo un nuevo parámetro Custom Assembly Path (o Ruta de acceso de control de versiones a ensamblados personalizados en español... uf! que quedó largo), al Build Controller para poder especificar allí la ubicación de aquellas dll´s que queremos tener disponibles en todos nuestros Build Definitions, sin tener que estar bajándolas del TFS para cada compilación.
Lo interesante es que cualquier archivo que se guarde en ese path del TFS, lo mismo que las carpetas y sus contenidos, es bajado automáticamente a un directorio del Build Server inmediatamente luego de cada Check In. Así podemos dejar ahí scripts de MSBuild (o lo que se nos ocurra), para ejecutar rutinas en diferentes Build Process Templates usando la activity InvokeProcess.
La carpeta en la que queda el contenido del Custom Assembly Path es:
Donde username corresponde al usuario bajo el cual corre el Team Foundation Build Service. y el ultimo numero al Build Agent.
Para acceder desde un Build Process Template a esta carpeta se debe agregar un activity del tipo GetBuildEnvironment al workflow, y luego asignar su atributo Result a una variable con un scope apropiado.
Una vez creada la variable se puede acceder a todos los atributos que expone la clase BuildEnvironment, incluido el CustomAssemblyPath. en cualquier expresión VB que esté dentro del scope especificado.
Todos los links de este post quedaron apuntando a la documentación del TFS 2010 porque ese fue la versión de servidor usada en el ejemplo, pero entiendo aplica totalmente a la siguientes versiones.
Custom Assembly Path en el Build Controller
Lo interesante es que cualquier archivo que se guarde en ese path del TFS, lo mismo que las carpetas y sus contenidos, es bajado automáticamente a un directorio del Build Server inmediatamente luego de cada Check In. Así podemos dejar ahí scripts de MSBuild (o lo que se nos ocurra), para ejecutar rutinas en diferentes Build Process Templates usando la activity InvokeProcess.
La carpeta en la que queda el contenido del Custom Assembly Path es:
C:\Users\%username%\AppData\Local\Temp\BuildAgent\1\
Donde username corresponde al usuario bajo el cual corre el Team Foundation Build Service. y el ultimo numero al Build Agent.
Para acceder desde un Build Process Template a esta carpeta se debe agregar un activity del tipo GetBuildEnvironment al workflow, y luego asignar su atributo Result a una variable con un scope apropiado.
GetBuildEnvironment Activity como parte del workflow
Una vez creada la variable se puede acceder a todos los atributos que expone la clase BuildEnvironment, incluido el CustomAssemblyPath. en cualquier expresión VB que esté dentro del scope especificado.
Usando la variable buildEnvironment previamente creada
Todos los links de este post quedaron apuntando a la documentación del TFS 2010 porque ese fue la versión de servidor usada en el ejemplo, pero entiendo aplica totalmente a la siguientes versiones.
Suscribirse a:
Entradas (Atom)