Corrigindo problemas de instalação do SQL Server relacionados à arquivos corrompidos ou ausentes no Windows Installer cache

Olá, pessoal! Tudo bem com vocês? Espero que sim.

Recentemente trabalhei em um caso em que o setup do Service Pack 4 do SQL Server 2012 mostrava o seguinte erro:

 

Investigando o log do setup, localizado no diretório C:\Program Files\Microsoft SQL Server\110\Setup Bootstrap, encontramos as seguintes entradas:

 

Slp: Package sql_engine_core_inst_Cpu64: - The path of cached MSI package is: C:\Windows\Installer\132686.msi . The RTM product version is: 11.0.2100.60

Slp: (01) 2020-12-02 09:54:48 Slp: Error: Action "Microsoft.SqlServer.Configuration.SetupExtension.InitializeUIDataAction" threw an exception during execution.

Slp: Microsoft.SqlServer.Setup.Chainer.Workflow.ActionExecutionException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list. ---> Microsoft.SqlServer.Chainer.Infrastructure.ChainerInfrastructureException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list. ---> System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.

 

Notem que o erro surge quando o setup vai verificar o pacote sql_engine_core_inst_Cpu64, armazenado como o arquivo 132686.msi na pasta C:\Windows\Installer. Esta pasta contém arquivos importantes das aplicações instaladas com o Windows Installer e não deve ter o seu conteúdo apagado. Aqui temos duas possibilidades: o pacote foi apagado, ou está presente, porém corrompido. Como então recuperar este pacote?

 

FixMissingMSI tool / FindSQLInstalls script

A Microsoft possui um artigo que mostra algumas formas de recuperar arquivos de instalação apagados ou corrompidos no cache do Windows Installer, irei mostrar duas delas: usando um utilitário chamado FixMissingMSI, ou através de um script chamado FindSQLInstalls.vbs.

 

Em meu ambiente vou simular as duas opções e mostrar como contornar o problema tanto com o utilitário como através do script.

 

Situação 1 – Arquivo existe no C:\Windows\Installer, porém está corrompido.

Propositalmente corrompi o pacote sql_engine_core_inst_msi na pasta C:\Windows\Installer, que no meu caso equivale ao arquivo 172c7.msi.

Quando tento instalar o Service Pack 4 do SQL Server 2012, um erro vai ocorrer. Verificando o log do setup posso confirmar o problema com o pacote que corrompi:

 

Slp: Setup was unable to open the file at 'C:\Windows\Installer\172c7.msi' due to error code '110'.

 

Resolvendo o problema com a ferramenta FixMissingMSI:

Para fazer a verificação com o utilitário, eu simplesmente o executo e aponto para a mídia de instalação do SQL Server 2012, que no meu caso está na unidade D, e clico em Scan Now:


Quando o scan é completado, seleciono Missing or Mismatched Only para ver apenas pacotes ausentes ou com problemas. Notem que a ferramenta indica que o pacote sql_engine_core_inst_msi tem algum problema (Mismatched):


Vou clicar em Fix It para que a ferramenta corrija o problema para mim, notem o aviso:


 Ou seja, a ferramenta vai copiar o pacote sql_engine_core_inst_msi da mídia de instalação do SQL Server 2012 para o diretório c:\windows\installer, trocando o seu nome para 172c7.msi, e substituindo o arquivo corrompido. Após concordar com a cópia o status na ferramenta muda para Fixed, ou seja resolvido:

 

Pronto, arrumamos o arquivo corrompido com a ferramenta FixMissingMSI.

 

Consertando o problema com o script FindSQLInstalls.vbs:

Primeiro, abro um prompt de comando elevado e navego até o diretório onde coloquei o script, no meu caso o diretório raiz do drive C:, em seguida executo o comando abaixo:

 

C:\>Cscript FindSQLInstalls.vbs %computername%_sql_install_details.txt > output.txt


 

Aqui temos uma diferença importante entre o utilitário FixMissingMSI  e o script FindSQLInstalls.vbs: na saída do script (no meu caso, arquivo output.txt), se procurarmos pelo pacote sql_engine_core_inst.msi, notem que e último caminho de origem (LastSourcePath) é identificado, ou seja, onde a mídia de instalação foi usada. De fato, no meu caso a mídia está inserida no drive D: e nenhuma ação precisa ser tomada:

 

sql_engine_core_inst.msi exists on the LastUsedSource path, no actions needed.

 

O script também informa qual é o pacote equivalente no cache, que ele existe e mais uma vez, que nenhuma ação precisa ser tomada:

 

Installer Cache File: C:\Windows\Installer\172c7.msi

Package exists in the Installer cache, no actions needed.

Any missing packages will update automatically if needed assuming that the LastUsedSource exists.

 

Porém sabemos que este pacote está corrompido, devido ao problema na instalação do Service Pack 4 do SQL Server 2012, registrado no log do setup. Portanto, continuando na saída do script FindSQLInstalls.vbs, existe a recomendação de copiar manualmente o pacote, da mídia de instalação do SQL Server para o cache do Windows Installer, trocando o seu nome para 172c7.msi:

 

 

Should you get errors about C:\Windows\Installer\172c7.msi or D:\x64\setup\sql_engine_core_inst_msi\sql_engine_core_inst.msi then you may need to manually copy the file, if file exists replace the problem file, copy and paste the following command line into an administrative command prompt:

 

O resultado do script termina mostrando como fazer o procedimento via prompt de comando:

 

Copy "D:\x64\setup\sql_engine_core_inst_msi\sql_engine_core_inst.msi" C:\Windows\Installer\172c7.msi

 

Ou seja, arquivos corrompidos não são apontados pelo script FindSQLInstalls.vbs, é preciso cruzar a informação da saída do script com o log do setup para tomar alguma ação.

 

Situação 2 – Arquivo não existe no C:\Windows\Installer.

O procedimento é o mesmo mostrado anteriormente, porém notem que agora o arquivo é classificado como inexistente (Missing):


Clicando em Fix It a ferramenta vai perguntar se desejamos copiar o pacote da mídia de instalação:


Aceitando o procedimento, o pacote é copiado e o status atualizado Fixed, ou seja resolvido:


Resolvendo o problema com o script FindSQLInstalls.vbs:

Após a execução do script FindSQLInstalls.vbs, para casos de arquivos inexistentes, temos que procurar na sua saída por do not ou !!!. Aqui um ponto importante: se executarmos o script com a mídia de instalação inserida no local de origem, os pacotes faltantes serão automaticamente copiados para o cache do Windows Installer. Porém, se a mídia de instalação não estiver no local original, teremos o seguinte resultado para o pacote sql_engine_core_inst.msi:

 

!!!! sql_engine_core_inst.msi DOES NOT exist on the path in the path D:\x64\setup\sql_engine_core_inst_msi\ !!!!

 

A saída do script também registra o pedido para que a mídia seja inserida no local original:

 

 

Action needed, re-establish the path to D:\x64\setup\sql_engine_core_inst_msi\

 

 

Na sequência, a saída do script mostra qual é o arquivo equivalente no cache do Windows Installer:

 

 

Installer Cache File: C:\Windows\Installer\172c7.msi

 

 

E mais importante, a saída do script mostra que o arquivo não está no cache do Windows Installer:

 

 

 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 !!!! C:\Windows\Installer\172c7.msi DOES NOT exist in the Installer cache. !!!!

 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

 

Para finalizar, a saída do script mostra as ações corretivas. Lembrando que se a mídia de instalação estivesse disponível, o script tomaria estas ações corretivas automaticamente:

 

 

Action needed, recreate or re-establish path to the directory:

D:\x64\setup\sql_engine_core_inst_msi\then rerun this script to update installer cache and results

    

The path on the line above must exist at the root location to resolve this problem with your msi/msp file not being found or corrupted, in some cases you may need to manually copy the missing file or manually replace the problem file overwriting it if it exists:

 

Copy "D:\x64\setup\sql_engine_core_inst_msi\sql_engine_core_inst.msi" C:\Windows\Installer\172c7.msi

 

Replace the existing file if prompted to do so.


Importante: Após realizar algum dos procedimentos acima, valide o Windows Installer cache através do Windows Installer Cache Verifier Package disponível neste link.

É importante ressaltar também que o esforço para recuperar arquivos de instalação corrompidos ou inexistentes no cache do Windows Installer pode ser bastante custoso. Nestes casos, pode ser mais vantajoso partir para uma nova instalação do SQL Server.

É isso pessoal, espero que tenha sido útil! Até a próxima!

Auto-Scale para Azure Database for MySQL usando Alertas e Runbooks

Olá pessoal tudo bem com vocês? Espero que sim.

O objetivo deste artigo é demonstrar através de Alertas e Runbooks como automatizar o auto-scale do tier de um servidor Azure Database for MySQL com base na métrica de consumo das CPUs, uma vez que este recurso não é nativo neste tipo de BD no Azure. Estou me baseando neste artigo do colega Nitin Kumar o qual me autorizou a fazer pequenas alterações e publicar uma versão em português do mesmo.

Abaixo vou descrever passo a passo como implementar a automação. 


Observações: 

1. Não reproduza esta demonstração em ambiente produtivo. Teste sempre em ambiente apropriado.

2. Não será discutido precificação de nenhum dos recursos neste artigo.


Passo-a-passo

Primeiro vamos criar um servidor Azure Database for MySQL na versão 5.7 no tier General Purpose, 2 vCore(s), 100 GB:



Depois precisamos criar uma nova Automation Account:



Dentro desta Automation Account precisamos importar os seguintes módulos:

·        Az.Accounts

·        Az.MySQL

Para importar os módulos vá em Procurar na galeria:






Aguarde a importação terminar:



Faça o mesmo para o outro módulo Az.MySQL.

Depois, ainda na Automation Account, crie um novo Runbook do tipo Powershell:



No runbook vamos usar um código de exemplo que recebe três paramêtros, nome do Resource Group, nome do servidor Azure Database for MySQL e SKU desejada. O código pode ser modificado de acordo com a necessidade de cada ambiente.

param(

 

    [Parameter(Mandatory=$True,Position=0)]

    [ValidateLength(1,100)]

    [string]$ResourceGroupName,

 

    [Parameter(Mandatory=$True,Position=1)]

    [ValidateLength(1,100)]

    [string]$ServerName,

 

    [Parameter(Mandatory=$False,Position=2)]

    [ValidateLength(1,100)]

    [string]$SkuTier

 

)



# Track the execution date & time

 

$StartDate=(GET-DATE)

 

Write-Verbose -Message 'Connecting to Azure'

 

# Name of the Azure Run As a connection

 

$ConnectionName = 'AzureRunAsConnection'

 

try

{

 

    # Get the connection properties to connect Azure resources

    $ServicePrincipalConnection = Get-AutomationConnection -Name $ConnectionName      

 

    'Log in to Azure...'

 

    $null = Connect-AzAccount -ServicePrincipal -TenantId $ServicePrincipalConnection.TenantId -ApplicationId $ServicePrincipalConnection.ApplicationId -CertificateThumbprint $ServicePrincipalConnection.CertificateThumbprint 

 

}

catch 

{

 

    if (!$ServicePrincipalConnection)

    {

 

        #Missed to 'Create Azure Run As account' 

        $ErrorMessage = "Connection $ConnectionName not found."

        throw $ErrorMessage

 

    }

    else

    {

        # additional execption

        Write-Error -Message $_.Exception.Message

        throw $_.Exception

    }

 

}



########################################################

 

# Setting SKU Tier for MySQLDatabase

 

########################################################

 

$CurrentSKU = (Get-AzMySqlServer -Name $ServerName -ResourceGroupName $ResourceGroupName).skuname

 

If($CurrentSKU -eq $SkuTier)

 

{

 

    # Validating the existing SKU value

    Write-Error "Cannot change pricing tier of $ServerName because the new SKU $SkuTier tier is equal to current SKU tier $CurrentSKU."

 

    return

 

}

 

else

 

{

 

    try

 

    {

 

        # updating the existing SKU value with the new one

        Update-AzMySqlServer -Name "$($ServerName)" -ResourceGroupName  "$($ResourceGroupName)" -sku "$($SkuTier)"

 

    }

 

    catch

 

    {

 

        Write-Error -Message $_.Exception.Message

 

        throw $_.Exception

 

    }    

 

}

 

Salve o Runbook e se for o caso ele pode ser testado clicando em Test Pane, informando o nome do Resource Group contendo o Azure Database for MySQL, nome do servidor Azure Database for MySQL e o novo SKU desejado para o mesmo.

Publique o Runbook:



Uma vez publicado, volte ao servidor Azure Database for MySQL e clique em Alertas.

Dentro de alertas clique em New Alert Rule.

Depois clique em Select Condition, selecione CPU percent, está será a métrica que irá disparar nosso alerta:



Para esta demonstração vamos usar um threshold baixo de 2% com um período de agregação de 5 minutos e uma frequência de verficação de 1 minuto:


Depois precisamos criar um Action Group, onde o tipo da ação será justamente executar um Automation Runbook, em Action clique em Add Action Groups:




Observação: Nesta demonstração não iremos usar mecanismos de notificação.

Em Actions, selecione Automation Runbook e então, selecione o Runbook criado anteriormente, clique em Configure Parameters e informe o nome do Resource Group onde está o servidor Azure Database for MySQL, informe o nome do servidor e finalmente selecione para qual tier este servidor deve mudar (escalar neste caso) caso a CPU ultrapasse os 2% de uso. Na demonstração estou deixando como General Purpose contendo 8 vCores:


 

Definido os parametros clique em Ok e defina um nome para a Ação:



Criado o Action Group, precisamos dar um nome a esta nova regra de alerta, uma descrição e um nível de severidade (no caso aqui irei usar Sev 3), isto definido, podemos clicar em Create alert rule.



Criado a nova regra de alerta, com o script abaixo podemos simular uma carga no Azure Database for MySQL, ele irá criar uma nova tabela no banco de dados e inserir 1 milhão de linhas:

CREATE TABLE customers

(

id INT,

customer_name VARCHAR(255)

);

 

INSERT INTO customers (id, customer_name)

SELECT n, CONCAT('Customer', n)

  FROM

(

select a.N + b.N * 10 + c.N * 100 + d.N * 1000 + e.N * 10000 + f.N * 100000 + 1 N

from (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) a

      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) b

      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) c

      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d

      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) e

      , (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) f

) t

 

Execute esta inserção de 1 milão de linhas algumas vezes, desta forma o consumo dos 2 vCores vai passar de 2% e disparar o alerta que por sua vez irá disparar o Runbook para escalar o tier:



Notem no gráfico que o consumo passou de 10%, ou seja, bem acima dos 2% que configuramos no alerta. Entrando nos alertas do servidor ja conseguimos ver que houve acionamento do que criamos:



Se olharmos na Automation Account também vemos que o Runbook executou:


Agora, basta conferir se o tier do servidor Azure Database for MySQL foi realmente alterado. Veja na imagem que de 2 vCores ele realmente mudou para 8vCores conforme configurado nos paramêtros do Runbook.


É isso pessoal! Espero que tenha sido útil e até apróxima!


Outros links de apoio:

https://azure.microsoft.com/en-us/services/mysql/

https://docs.microsoft.com/en-us/azure/automation/automation-runbook-types

https://docs.microsoft.com/en-us/azure/automation/start-runbooks

https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-overview