0

我正在尝试使用自定义脚本扩展取消预配 Azure Linux 实例。

我的脚本存储在匿名访问 Blob 中:

sudo waagent -deprovision+user -verbose -force
exit

我的命令应用扩展:

az vm extension set --resource-group rg01--vm-name vm01--name CustomScript --publisher Microsoft.Azure.Extensions --version 2.0  --settings "{'fileUris': [ 'https://mystorageaccount.blob.core.windows.net/scripts/Deprovision.sh' ], 'commandToExecute': 'sh Deprovision.sh'}" 

当我运行 az 命令时,所有/var/log/azure子目录和日志都消失了!我可以从堡垒窗口中看出,有些东西试图删除我的用户帐户,所以我相信扩展程序正在被配置和运行。

不幸的是,扩展程序将所有状态信息显示为不可用,而我的 az 命令就在那里。一旦取消配置开始,VM 活动日志中的“创建或更新虚拟机扩展”项也不会显示任何活动。Azure 活动日志表明发生了重新启动,并且我的帐户不再有效。

希望 Linux/Azure 的人对此有一个秘诀……

-

我在 Windows 中看到了类似的行为,并最终将此脚本用于 Sysprep (-Wait 很关键,因为它强制 Powershell 进程等待完成,防止代理在进程完成之前返回成功/失败。),这可以防止重新启动。然后,我可以在扩展完成时执行脚本解除分配。 我怀疑这里正在发生类似的事情。

Start-Process -FilePath C:\Windows\System32\Sysprep\Sysprep.exe -ArgumentList '/generalize /oobe /quiet /quit'  -Wait 
4

1 回答 1

1

虽然命令:

sudo waagent -deprovision+user -verbose -force

通过 SSH 工作,当通过CustomScript扩展运行时,此命令基本上会杀死机器上的所有内容。CustomScript扩展无法确认完成。

使用此脚本:

sudo shutdown +3
sudo waagent -deprovision+user -verbose -force -start
  • 第 1 行,在 3 分钟内关闭 VM(deprovision 命令似乎非常快)
  • 第 2 行,添加“-start”,将 waagent 作为后台进程运行。这允许CustomScript扩展确认完成。

现在此命令完成(而不是挂起):

        var cmd = "sh Deprovision.sh";

        var result = vm.Update()
                    .DefineNewExtension("deprovision")
                    .WithPublisher("Microsoft.Azure.Extensions")
                    .WithType("CustomScript")
                    .WithVersion("2.1")
                    .WithMinorVersionAutoUpgrade()
                    .WithPublicSetting("fileUris", new string[] { blobUri })
                    .WithPublicSetting("commandToExecute", cmd)
                    .Attach()
                    .Apply();

完成后,我们必须轮询 Azure 以了解 VM 何时停止。

WaitForVMToStop(vm);


private void WaitForVMToStop(IVirtualMachine newVM)
{
    Context.Logger.LogInformation($"WaitForVMToStop...");

    bool stopped = false;
    int cnt = 0;
    do
    {
        var stoppedVM = Context.AzureInstance.VirtualMachines.GetById(newVM.Id);
        stopped = (stoppedVM.PowerState == PowerState.Stopped);
        if (!stopped)
        {
            cnt++;
            Context.Logger.LogInformation($"\tPolling 60 seconds for 'PowerState = Stopped on [{newVM.Name}]...");
            System.Threading.Thread.Sleep(60000);

            if (cnt > 20)
            {
                Context.Logger.LogInformation($"\tSysPrep Extension exceeded 20 minutes. Aborting...");
                throw new Exception($"SysPrep Extension exceeded 20 minutes on [{newVM.Name}]");
            }
        }

    } while (!stopped);

    Context.Logger.LogInformation($"\tWaited {cnt} minutes for 'PowerState = Stopped...");

}

这对我来说似乎太复杂了,但它确实有效。我特别不喜欢假设取消配置将在 3 分钟或更短的时间内发生。如果有人有更好的方法,请分享。

于 2020-02-27T16:03:48.153 回答