A utilização do Windows PowerShell oferece uma alternativa bastante flexível para estender as funcionalidades do Team Foundation Build 2010. A partir da customização de um build process template é possível realizar chamadas a scripts que podem executar diferentes tipos de tarefas. A abordagem deste artigo é a utilização desses recursos para realizar a implantação de um projeto do tipo Windows Service em um servidor de testes a partir da execução de uma build.
O processo de build de uma aplicação em desenvolvimento pode incluir sua implantação em um determinado ambiente, como o ambiente de testes. Através do Team Foundation Build você pode realizar a implantação de projetos do tipo ASP.NET Web Application, por exemplo, utilizando o Web Deploy. Com ele é possível passar argumentos ao MSBuild na definição da build e a partir daí, como parte do seu processo de execução, fazer com que o MSDeploy seja chamado a fim de que seja realizada a implantação da aplicação no servidor IIS desejado.
Para projetos do tipo Windows Service é necessário um pouco mais de trabalho. Para poder realizar a instalação de um serviço, caso o serviço já esteja instalado, é preciso realizar primeiro a desinstalação da versão atual antes de substituir os arquivos desta pelos arquivos da nova build e realizar sua instalação através do utilitário installutil do .NET Framework.
A solução apresentada tem como objetivo realizar a implantação, em um servidor de testes, de um projeto do tipo Windows Service a partir da execução de uma definição de build do Team Foundation Build 2010. Para realizar essa tarefa, foi customizado um build process template de forma a incluir em seu fluxo de trabalho uma chamada a um script do Windows PowerShell. Este script por sua vez, tem a capacidade de executar comandos remotamente no servidor de testes para desinstalar a versão do serviço instalada atualmente e em seguida instalar a nova versão gerada pela execução da build. Outro recurso importante implementado na solução é a capacidade de realizar “config transformation”. Este recurso foi incluído na versão 2010 do Visual Studio somente para web applications (conhecido como Web.config Transformation) e permite realizar transformações no arquivo de configuração da aplicação, o Web.config, substituindo informações presentes nele de acordo com a configuração de compilação do projeto (Debug, Release ou outra criada pelo usuário), gerando assim um arquivo com configurações próprias para cada uma delas. Apesar deste recurso não estar disponível explicitamente na interface do Visual Studio 2010 para outros tipos de projetos, você verá que é possível utilizá-lo modificando o arquivo de definição do projeto.
A Figura 1 ilustra os componentes envolvidos na solução apresentada. A definição de build MyBuildDefinition, configurada para utilizar o modelo WindowsServiceTemplate.xaml e copiar o resultado para a pasta \\SRV_BUILD\Drop, está configurada também para compilar o projeto MyWindowsServices.csproj em modo RELEASE a fim de que as transformações definidas no arquivo App.Release.config sejam aplicadas sobre o arquivo App.config no sentido de gerar o arquivo de configuração correspondente ao ambiente de testes.
Figura 1 - Componentes da solução
Ao executar a build, de acordo com a customização realizada no modelo, o script WindowsServiceTemplate.ps1 é chamado e, ao ser executado, pára os serviços definidos no projeto que estão atualmente em execução no servidor de testes, SRV_TESTE, e em seguida executa o comando installutil –u neste servidor para proceder a desinstalação. Depois disso, copia o conteúdo da nova build a partir da pasta compartilhada \\SRV_BUILD\Drop para a pasta C:\MyWindowsService do servidor SRV_TESTE, sobreescrevendo os arquivos atuais, e finalmente executa o comando installutil novamente para instalar a nova versão.
Alguns comandos do Windows PowerShell precisam ser executados nos servidores envolvidos no processo para permitir a execução do script desta solução.
Primeiramente pode ser necessário configurar o Windows Remote Management e habilitar a execução de comandos remotos para o Windows PowerShell entre os servidores. Os comandos da Listagem 1 devem ser executados nos servidores SRV_BUILD e SRV_TESTE.
Listagem 1. Habilitando a execução de comandos remotos
O comando listado a seguir é executado no servidor SRV_BUILD e permite que o script da solução seja executado neste servidor sem restrições.
Listagem 2. Habilitando a execução do script no servidor de build
Outra configuração importante diz respeito a permissões. A chamada ao script será realizada pela execução da definição da build, logo, o script será executado no servidor de build. Porém, o comando para cópia dos arquivos da build (neste caso o comando utilizado é o ROBOCOPY) será executado no servidor de testes, SRV_TESTE. Assim nosso cenário é o seguinte:
Neste cenário, a credencial informada precisa ser passada pelo script do servidor SRV_BUILD para o servidor SRV_TESTE e logo em seguida, pelo execução do comando ROBOCOPY, do servidor SRV_TESTE para o servidor SRV_BUILD, conforme mostrado na Figura 2.
Figura 2 - Copiando os arquivos da build
O problema com este cenário é que esse “salto duplo” da credencial não é permitido. Esta questão é conhecida como double-hop e é uma característica do modelo de autenticação utilizado em redes baseadas no Active Directory.
Entretanto, o Windows PowerShell oferece uma solução para este problema. Através da execução de comandos apropriados nos servidores envolvidos, é possível permitir a delegação de credenciais de um servidor para outro, conforme listado a seguir.
Listagem 3. Habilitando delegação de credenciais
#No servidor de testes (SRV_TESTE) Enable-WSManCredSSP -Role Server -Force
#No servidor de build (SRV_BUILD) Enable-WSManCredSSP -Role Client -DelegateComputer SRV_TESTE -Force
O primeiro comando, executado no servidor SRV_TESTE, habilita este servidor a delegar credenciais para outros servidores. O segundo comando, executado em SRV_BUILD, habilita este servidor a aceitar credenciais delegadas pelo servidor SRV_TESTE.
Com o ambiente configurado, o passo seguinte é a criação do script Windows PowerShell responsável pela implantação do projeto. Para criação do script do arquivo WindowsServiceTemplate.ps1 foi utilizado o Windows PowerShell ISE, disponível nativamente no Windows 7 e Windows Server 2008 R2. Este editor, além de exibir o código com cores, semelhante ao Visual Studio, permite realizar a depuração passo a passo do código, permitindo inclusive adicionar breakpoints.
Como vimos anteriormente, o script precisará de uma credencial com permissões específicas para cópia dos arquivos da build e instalação do serviço no servidor de testes. Além do nome do usuário e a senha correspondentes a essa credencial, outros parâmetros precisarão ser passados ao script para sua execução, sendo eles:
Listagem 4. Passando parâmetros
Todos os parâmetros são sequências simples de caracteres, à execção do parâmetro $serviceNames que é um string array; isso porque um projeto do tipo Windows Service pode conter vários serviços e será necessário passar o nome de cada um deles. O comando installutil irá instalar todos os serviços, mas posteriormente eles deverão ser iniciados um a um. Importante destacar aqui que o nome a ser informado é o correpondente à propriedade “ServiceName” e não “DisplayName”. Ambas as propriedades são definidas no instalador de cada serviço incluído no projeto.
Após definir os parâmetros (esta definição precisa ser obrigatoriamente a primeira linha do script), são definidas algumas variáveis globais que serão utilizadas pelo script.
Listagem 5. Variáveis: credencial e caminhos utilizados
A variável $credential, criada a partir do usuário e senha informados como parâmetros, representa a credencial que será utilizada para copiar os arquivos da build e instalar o serviço. A variável $installUtil representa o caminho para o executável do utilitário installutil e $localFolderPath corresponde à pasta local do servidor de testes para onde os arquivos da build serão copiados.
Iniciando o processo de implantação, o script verifica se o executável do projeto já está instalado. Caso ele esteja, define que ele precisará ser desinstalado. Entretanto, antes de proceder a desinstalção, é possível que algum processo correspondente aos serviços do projeto continue em execução por um tempo ainda após a desinstalação; isso pode ocasionar problemas posteriormente. Por isso, conforme se vê na Listagem 6 , cada um dos serviços é parado e em seguida um loop é executado a cada cinco segundos até que o processo esteja definitivamente encerrado.
Listagem 6. Encerrando os processos em execução
Somente após o encerramento de todos os processos a desinstalação é realizada. Perceba que a variável $uninstallService foi criada para indicar se é necessário desinstalar o serviço. Seu valor é definido para $true apenas se algum serviço for encontrado.
Na sequência, caso algum serviço tenha sido encontrado, é executado o comando para desinstalação do executável. Caso contrário, no caso da primeira instalação, é criada a pasta no servidor de testes para receber os arquivos da nova build. Repare que caso a pasta já exista, o processo é encerrado através do retorno de uma exceção pelo comando Throw.
Listagem 7. Desinstalando
O passo a seguir é a cópia dos arquivos da nova build do servidor de build para a pasta correspondente no servidor de testes através do comando ROBOCOPY.
Listagem 8. Copiando arquivos da build
Com os arquivos copiados, o comando installutil é executado para realizar a instalação dos serviços, conforme se vê na Listagem 9.
Listagem 9. Instalando os serviços
Com os serviços devidamente instalados, eles são iniciados através do código da Listagem 10.
Listagem 10. Iniciando os serviços
Com o script pronto, o próximo passo é criar um build process template que seja capaz de executá-lo.
O modelo utilizado nesta solução é uma cópia do modelo DefaultTemplate.xaml que é gerado automaticamente durante a criação de um novo team project no Team Foundation Server. A cópia foi nomeada como WindowsServiceTemplate.xaml e foi modificada para incluir uma chamada ao script conforme você verá a seguir.
Primeiro são definidos os argumentos que a definição da build deverá receber para ser executada, conforme se vê na Figura 3.
Figura 3 - Argumentos
Repare que todos os argumentos são do tipo String, à exceção do argumento ServiceNames que é um string array. Os valores desses argumentos serão passados como parâmetros ao script e por isso é necessário manter a consistência com os tipos de dados definidos nele, conforme visto na Listagem 4. Passando parâmetros.
Para fins de organização, a Figura 4 mostra que para cada argumento é possível definir como ele será exibido na janela de definição da build, definindo um nome amigável, uma categoria e um texto explicativo. Isso é feito através da edição do argumento Metadata.
Figura 4 - Organizando os parâmetros
Em seguida, o modelo é customizado no sentido de incluir as atividades necessárias para a execução do script. Conforme mostrado na Figura 5, logo abaixo da atividade já existente “Try Compile, Test, and Associate Changesets and Work Items”, são incluídas essas novas atividades. A Figura 6 mostra as propriedades definidas para cada nova atividade incluída.
Figura 5 - Atividades
Figura 6 - Propriedades das atividades
Repare que a chamada ao script é feita através da atividade InvokeProcess, que permite a execução de uma linha de comando. O que ela faz é executar o comando PowerShell passando como parâmetros o caminho para o arquivo de script criado e os argumentos definidos para ele.
O último passo antes de executar a build é preparar o projeto MyWindowsService.csproj para que ele seja implementado no servidor de testes com as configurações apropriadas ao ambiente.
Suponha que o arquivo App.config do projeto possua uma string de conexão a um banco de dados local (localhost), conforme mostrado na Listagem 11, que é utilizado para desenvolvimento.
Listagem 11. Arquivo App.config de desenvolvimento
No ambiente de testes, a string de conexão deverá apontar para o banco de dados de testes. Para criar um arquivo de transformação, da mesma forma como é feito em projetos web utilizando o recurso Web.config Transformations do Visual Studio 2010, é preciso realizar algumas modificações no arquivo do projeto.
Com o projeto aberto no Visual Studio, as modificações necessárias são as seguintes:
Listagem 12. Transformação do arquivo App.Release.config
Listagem 13. Referências iniciais aos arquivos de configuração
Listagem 14. Implementação da dependência entre os arquivos de configuração
Listagem 15. XML responsável pela transformação
Agora o projeto está pronto para ser compilado e implantado no servidor de testes.
Com toda a estrutura preparada, finalmente é possível criar uma nova definição de build baseada no modelo customizado. As propriedades a serem definidas conforme a Figura 1 - Componentes da solução são as seguintes:
Figura 7 – Definição de build
Ao executar a definição de build MyBuildDefinition, o projeto MyWindowsServices.csproj será compilado em modo RELEASE. Isso resultará na aplicação das transformações definidas no arquivo App.Release.config sobre o arquivo App.config. Os arquivos resultantes da compilação do projeto, incluindo o arquivo de configuração transformado, serão copiados para a pasta C:\MyWindowsService do servidor SRV_TESTE e o arquivo MyWindowsService.exe será instalado nesse servidor, via utilitário installutil. Finalmente, encerrando o procedimento, os serviços MyWindowsService1 e MyWindowsService2 definidos no projeto são iniciados.
Todos os servidores desta solução utilizaram o Windows Server 2008 R2 como sistema operacional por já possuir suporte nativo ao Windows PowerShell 2.0 e ao WinRM 2.0. O Team Foundation Server 2010 e o Team Foundation Build 2010, instalados nesses servidores, estão perfeitamente integrados à plataforma de 64 bits, que aliada ao .NET Framework 4 oferece um ambiente estável e seguro para execução do processo de build de aplicações. O projeto MyWindowsServices.csproj utilizado como exemplo foi criado com o Visual Studio 2010.
Assim como aconteceu com outros produtos da Microsoft, como SharePoint e Exchange, a integração entre o Windows PowerShell e o Team Foundation Server é uma tendência natural para a próxima versão do TFS, o que demonstra a consolidação do Windows PowerShell como recurso fundamental para a administração de servidores.
O Windows PowerShell foi criado primeiramente para ser um shell de linha de comando e linguagem de script para a administração de sistemas. Este artigo mostra que é possível utilizá-lo para muito mais do que isso. Por ser baseado no .NET Framework, permite utilizar o seu modelo de objetos e estender as funcionalidades de outros produtos baseados nessa arquitetura de uma maneira bastante rápida e flexível. Por isso ele se torna cada vez mais uma ferramenta indispensável tanto pra profissionais de infraestrutura quanto para desenvolvedores.
Clique aqui para baixar o código fonte deste artigo.
Eduardo Assis edited Revision 3. Comment: Alteração da URL de download do código fonte
Luciano Lima [MVP] Brazil edited Revision 1. Comment: Corrigido erro de digitação na nota no inicio do artigo.
Eduardo Assis edited Original. Comment: Correção do link para download do código fonte que não estava aparecendo e do título errado para "Implementando config transformation"