예제 #1
0
        public async Task TestVMScaleSetVMOperations_RunCommand()
        {
            EnsureClientsInitialized(DefaultLocation);
            InitializeCommon();
            instanceId = "0";
            bool passed = false;
            var  storageAccountOutput = await CreateStorageAccount(rgName, storageAccountName);

            var getTwoVirtualMachineScaleSet = await CreateVMScaleSet_NoAsyncTracking(
                rgName, vmssName, storageAccountOutput, imageRef,
                createWithManagedDisks : true);

            VirtualMachineScaleSet vmScaleSet = getTwoVirtualMachineScaleSet.Item1;

            inputVMScaleSet = getTwoVirtualMachineScaleSet.Item2;
            await WaitForCompletionAsync(await VirtualMachineScaleSetVMsOperations.StartStartAsync(rgName, vmScaleSet.Name, instanceId));

            RunCommandResult result = (await WaitForCompletionAsync(await VirtualMachineScaleSetVMsOperations.StartRunCommandAsync(rgName, vmScaleSet.Name, instanceId, new RunCommandInput("ipconfig")))).Value;

            Assert.NotNull(result);
            Assert.NotNull(result.Value);
            Assert.True(result.Value.Count > 0);
            passed = true;
            Assert.True(passed);
        }
예제 #2
0
        public static RunCommandResult RunCommandWithResult(string fileName, string args, int timeOut = 60000)
        {
            Process p = new Process();

            p.StartInfo = new ProcessStartInfo(fileName, args);
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError  = true;
            p.Start();

            RunCommandResult result = new RunCommandResult();

            if (p.WaitForExit(timeOut))
            {
                result.ExitCode = p.ExitCode;
                result.StdOut   = p.StandardOutput.ReadToEnd();
                result.StdErr   = p.StandardError.ReadToEnd();

                if (VerboseLogging)
                {
                    TestContext.Out.WriteLine($"Command run finished. {fileName} {args} {timeOut}. Output: {result.StdOut} Error: {result.StdErr}");
                }
            }
            else
            {
                throw new TimeoutException($"Command run timed out. {fileName} {args} {timeOut}");
            }

            return(result);
        }
        public void TestVMOperations_RunCommand()
        {
            using (MockContext context = MockContext.Start(this.GetType()))
            {
                EnsureClientsInitialized(context);

                ImageReference imageRef = GetPlatformVMImage(useWindowsImage: true);

                // Create resource group
                string         rg1Name            = ComputeManagementTestUtilities.GenerateName(TestPrefix) + 1;
                string         as1Name            = ComputeManagementTestUtilities.GenerateName("as");
                string         storageAccountName = ComputeManagementTestUtilities.GenerateName(TestPrefix);
                VirtualMachine inputVM1;

                try
                {
                    // Create Storage Account, so that both the VMs can share it
                    var storageAccountOutput = CreateStorageAccount(rg1Name, storageAccountName);

                    VirtualMachine vm1 = CreateVM(rg1Name, as1Name, storageAccountOutput, imageRef, out inputVM1);

                    var runCommandImput = new RunCommandInput()
                    {
                        CommandId = "RunPowerShellScript",
                        Script    = new List <string>()
                        {
                            "param(",
                            "    [string]$arg1,",
                            "    [string]$arg2",
                            ")",
                            "echo This is a sample script with parameters $arg1 $arg2"
                        },
                        Parameters = new List <RunCommandInputParameter>()
                        {
                            new RunCommandInputParameter("arg1", "value1"),
                            new RunCommandInputParameter("arg2", "value2"),
                        }
                    };
                    RunCommandResult result = m_CrpClient.VirtualMachines.RunCommand(rg1Name, vm1.Name, runCommandImput);
                    Assert.NotNull(result);
                    Assert.NotNull(result.Value);
                    Assert.True(result.Value.Count > 0);
                }
                finally
                {
                    // Cleanup the created resources. But don't wait since it takes too long, and it's not the purpose
                    // of the test to cover deletion. CSM does persistent retrying over all RG resources.
                    m_ResourcesClient.ResourceGroups.Delete(rg1Name);
                }
            }
        }
예제 #4
0
        public static bool RunCommand(string fileName, string args = "", int timeOut = 60000)
        {
            RunCommandResult result = RunCommandWithResult(fileName, args, timeOut);

            if (result.ExitCode != 0)
            {
                TestContext.Out.WriteLine($"Command failed with: {result.ExitCode}");
                return(false);
            }
            else
            {
                return(true);
            }
        }
예제 #5
0
        // This method is used when the test is run in an OS that does not support AppExecutionAlias. E,g, our build machine.
        // There is not any existing API that'll activate a packaged app and wait for result, and not possible to capture the stdIn and stdOut.
        // This method tries to call Invoke-CommandInDesktopPackage PS command to make test executable run in packaged context.
        // Since Invoke-CommandInDesktopPackage just launches the executable and return, we use cmd pipe to get execution results.
        // The final constructed command will look like:
        //   Invoke-CommandInDesktopPackage ...... -Command cmd.exe -Args '-c <cmd command>'
        //   where <cmd command> will look like: "echo stdIn | appinst.exe args > stdout.txt 2> stderr.txt & echo %ERRORLEVEL% > exitcode.txt"
        // Then this method will read the piped result and return as RunCommandResult.
        public static RunCommandResult RunAICLICommandViaInvokeCommandInDesktopPackage(string command, string parameters, string stdIn = null, int timeOut = 60000)
        {
            string cmdCommandPiped = "";

            if (!string.IsNullOrEmpty(stdIn))
            {
                cmdCommandPiped += $"echo {stdIn} | ";
            }

            string workDirectory = GetRandomTestDir();
            string exitCodeFile  = Path.Combine(workDirectory, "ExitCode.txt");
            string stdOutFile    = Path.Combine(workDirectory, "StdOut.txt");
            string stdErrFile    = Path.Combine(workDirectory, "StdErr.txt");

            cmdCommandPiped += $"{AICLIPath} {command} {parameters} > {stdOutFile} 2> {stdErrFile} & call echo %^ERRORLEVEL% > {exitCodeFile}";

            string psCommand = $"Invoke-CommandInDesktopPackage -PackageFamilyName {Constants.AICLIPackageFamilyName} -AppId {Constants.AICLIAppId} -PreventBreakaway -Command cmd.exe -Args '/c \"{cmdCommandPiped}\"'";

            var psInvokeResult = RunCommandWithResult("powershell", psCommand);

            if (psInvokeResult.ExitCode != 0)
            {
                // PS invocation failed, return result and no need to check piped output.
                return(psInvokeResult);
            }

            // The PS command just launches the app and immediately returns, we'll have to wait for up to the timeOut specified here
            int waitedTime = 0;

            while (!File.Exists(exitCodeFile) && waitedTime <= timeOut)
            {
                Thread.Sleep(1000);
                waitedTime += 1000;
            }

            if (waitedTime >= timeOut)
            {
                throw new TimeoutException("Command run timed out.");
            }

            RunCommandResult result = new RunCommandResult();

            result.ExitCode = File.Exists(exitCodeFile) ? int.Parse(File.ReadAllText(exitCodeFile).Trim()) : unchecked ((int)0x80004005);
            result.StdOut   = File.Exists(stdOutFile) ? File.ReadAllText(stdOutFile) : "";
            result.StdErr   = File.Exists(stdErrFile) ? File.ReadAllText(stdErrFile) : "";

            return(result);
        }
예제 #6
0
        public static RunCommandResult RunAICLICommandViaDirectProcess(string command, string parameters, string stdIn = null, int timeOut = 60000)
        {
            RunCommandResult result = new RunCommandResult();
            Process          p      = new Process();

            p.StartInfo = new ProcessStartInfo(AICLIPath, command + ' ' + parameters);
            p.StartInfo.UseShellExecute        = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError  = true;

            if (!string.IsNullOrEmpty(stdIn))
            {
                p.StartInfo.RedirectStandardInput = true;
            }

            p.Start();

            if (!string.IsNullOrEmpty(stdIn))
            {
                p.StandardInput.Write(stdIn);
            }

            if (p.WaitForExit(timeOut))
            {
                result.ExitCode = p.ExitCode;
                result.StdOut   = p.StandardOutput.ReadToEnd();
                result.StdErr   = p.StandardError.ReadToEnd();

                TestContext.Out.WriteLine("Command run completed with exit code: " + result.ExitCode);

                if (!string.IsNullOrEmpty(result.StdErr))
                {
                    TestContext.Error.WriteLine("Command run error. Error: " + result.StdErr);
                }

                if (VerboseLogging && !string.IsNullOrEmpty(result.StdOut))
                {
                    TestContext.Out.WriteLine("Command run output. Output: " + result.StdOut);
                }
            }
            else
            {
                throw new TimeoutException("Command run timed out.");
            }

            return(result);
        }
        public override void ExecuteCmdlet()
        {
            base.ExecuteCmdlet();

            switch (ParameterSetName)
            {
            case IdParameterSet:
            {
                var resource = new ResourceIdentifier(Id);
                ResourceGroupName = resource.ResourceGroupName;
                Name = resource.ResourceName;
                break;
            }

            case InputObjectParameterSet:
            {
                var resource = new ResourceIdentifier(InputObject.Id);
                ResourceGroupName = resource.ResourceGroupName;
                Name = resource.ResourceName;
                break;
            }
            }

            var msg = $"{Name} in {ResourceGroupName}";

            ConfirmAction(Force.IsPresent,
                          string.Format(Resources.DoYouWantToExecuteCommandOnCluster, Name),
                          string.Format(Resources.ExecutingCommandOnCluster, Name),
                          msg,
                          () =>
            {
                ManagedCluster cluster    = Client.ManagedClusters.Get(ResourceGroupName, Name);
                RunCommandRequest request = new RunCommandRequest
                {
                    Command = Command,
                    Context = GetCommandContext()
                };
                if (cluster.AadProfile != null && cluster.AadProfile.Managed != null)
                {
                    request.ClusterToken = GetClusterToken();
                }
                RunCommandResult response = Client.ManagedClusters.RunCommand(ResourceGroupName, Name, request);
                WriteObject(PSMapper.Instance.Map <PSRunCommandResult>(response));
            });
        }
예제 #8
0
        private void WriteInvalidOptionOrArgument(RunCommandResult runCommandResult)
        {
            var message = new StringBuilder();

            message.AppendLine($"The Command could not be run. The following errors occured: ");


            foreach (var option in runCommandResult.InvalidOptions)
            {
                message.AppendLine($"- Invalid value for Option: {option.Key}");
            }

            foreach (var argument in runCommandResult.InvalidArguments)
            {
                message.AppendLine($"- Invalid value for Argument: {argument.Key}");
            }

            Console.WriteLine(message.ToString());
        }
예제 #9
0
        private void AnalyseRunCommandResult(RunCommandResult runCommandResult)
        {
            // Two cases:
            // 1. There are non optional parameters which are not marked as either Option or Argument.
            //    This is an exception-case because that is a wrong declaration of a Command-method.
            // 2. There are invalid Options or Arguments.
            //    This is NOT an exception-case because that is an error by the user which provided wrong input.

            // Case 1:
            if (runCommandResult.NonOptionalUnknownParameters.Any())
            {
                WriteNonOptionalUnknownParametersError(runCommandResult.NonOptionalUnknownParameters);
            }

            // Case 2:
            if (runCommandResult.InvalidOptions.Any() || runCommandResult.InvalidArguments.Any())
            {
                WriteInvalidOptionOrArgument(runCommandResult);
            }
        }
예제 #10
0
        public void TestVMScaleSetVMOperations_RunCommand()
        {
            using (MockContext context = MockContext.Start(this.GetType()))
            {
                InitializeCommon(context);
                instanceId = "0";
                bool passed = false;
                try
                {
                    var storageAccountOutput = CreateStorageAccount(rgName, storageAccountName);

                    VirtualMachineScaleSet vmScaleSet = CreateVMScaleSet_NoAsyncTracking(
                        rgName, vmssName, storageAccountOutput, imageRef, out inputVMScaleSet,
                        createWithManagedDisks: true);

                    m_CrpClient.VirtualMachineScaleSetVMs.Start(rgName, vmScaleSet.Name, instanceId);

                    RunCommandResult result = m_CrpClient.VirtualMachineScaleSetVMs.RunCommand(rgName, vmScaleSet.Name, instanceId, new RunCommandInput()
                    {
                        CommandId = "ipconfig"
                    });
                    Assert.NotNull(result);
                    Assert.NotNull(result.Value);
                    Assert.True(result.Value.Count > 0);

                    passed = true;
                }
                finally
                {
                    // Cleanup the created resources. But don't wait since it takes too long, and it's not the purpose
                    // of the test to cover deletion. CSM does persistent retrying over all RG resources.
                    m_ResourcesClient.ResourceGroups.Delete(rgName);
                }

                Assert.True(passed);
            }
        }
예제 #11
0
        public void TestVMOperations()
        {
            using (MockContext context = MockContext.Start(this.GetType().FullName))
            {
                EnsureClientsInitialized(context);

                ImageReference imageRef = GetPlatformVMImage(useWindowsImage: true);

                // Create resource group
                string         rg1Name            = ComputeManagementTestUtilities.GenerateName(TestPrefix) + 1;
                string         as1Name            = ComputeManagementTestUtilities.GenerateName("as");
                string         storageAccountName = ComputeManagementTestUtilities.GenerateName(TestPrefix);
                VirtualMachine inputVM1;

                try
                {
                    // Create Storage Account, so that both the VMs can share it
                    var storageAccountOutput = CreateStorageAccount(rg1Name, storageAccountName);

                    VirtualMachine vm1 = CreateVM(rg1Name, as1Name, storageAccountOutput, imageRef, out inputVM1);
                    m_CrpClient.VirtualMachines.Start(rg1Name, vm1.Name);
                    m_CrpClient.VirtualMachines.Redeploy(rg1Name, vm1.Name);
                    m_CrpClient.VirtualMachines.Restart(rg1Name, vm1.Name);

                    var runCommandImput = new RunCommandInput()
                    {
                        CommandId = "RunPowerShellScript",
                        Script    = new List <string>()
                        {
                            "param(",
                            "    [string]$arg1,",
                            "    [string]$arg2",
                            ")",
                            "echo This is a sample script with parameters $arg1 $arg2"
                        },
                        Parameters = new List <RunCommandInputParameter>()
                        {
                            new RunCommandInputParameter("arg1", "value1"),
                            new RunCommandInputParameter("arg2", "value2"),
                        }
                    };
                    RunCommandResult result = m_CrpClient.VirtualMachines.RunCommand(rg1Name, vm1.Name, runCommandImput);
                    Assert.NotNull(result);
                    Assert.NotNull(result.Value);
                    Assert.True(result.Value.Count > 0);

                    m_CrpClient.VirtualMachines.PowerOff(rg1Name, vm1.Name);
                    m_CrpClient.VirtualMachines.Deallocate(rg1Name, vm1.Name);
                    m_CrpClient.VirtualMachines.Generalize(rg1Name, vm1.Name);

                    VirtualMachine ephemeralVM;
                    string         as2Name = as1Name + "_ephemeral";
                    CreateVM(rg1Name, as2Name, storageAccountName, imageRef, out ephemeralVM, hasManagedDisks: true, hasDiffDisks: true, vmSize: VirtualMachineSizeTypes.StandardDS1V2,
                             osDiskStorageAccountType: StorageAccountTypes.StandardLRS, dataDiskStorageAccountType: StorageAccountTypes.StandardLRS);
                    m_CrpClient.VirtualMachines.Reimage(rg1Name, ephemeralVM.Name, tempDisk: true);
                    var captureParams = new VirtualMachineCaptureParameters
                    {
                        DestinationContainerName = ComputeManagementTestUtilities.GenerateName(TestPrefix),
                        VhdPrefix     = ComputeManagementTestUtilities.GenerateName(TestPrefix),
                        OverwriteVhds = true
                    };

                    var captureResponse = m_CrpClient.VirtualMachines.Capture(rg1Name, vm1.Name, captureParams);

                    Assert.NotNull(captureResponse);
                    Assert.True(captureResponse.Resources.Count > 0);
                    string resource = captureResponse.Resources[0].ToString();
                    Assert.Contains(captureParams.DestinationContainerName.ToLowerInvariant(), resource.ToLowerInvariant());
                    Assert.Contains(captureParams.VhdPrefix.ToLowerInvariant(), resource.ToLowerInvariant());

                    Resource template = JsonConvert.DeserializeObject <Resource>(resource);
                    string   imageUri = template.Properties.StorageProfile.OSDisk.Image.Uri;
                    Assert.False(string.IsNullOrEmpty(imageUri));

                    // Create 3rd VM from the captured image
                    // TODO : Provisioning Time-out Issues
                    VirtualMachine inputVM2;
                    string         as3Name = as1Name + "b";
                    VirtualMachine vm3     = CreateVM(rg1Name, as3Name, storageAccountOutput, imageRef, out inputVM2,
                                                      vm =>
                    {
                        vm.StorageProfile.ImageReference = null;
                        vm.StorageProfile.OsDisk.Image   = new VirtualHardDisk {
                            Uri = imageUri
                        };
                        vm.StorageProfile.OsDisk.Vhd.Uri = vm.StorageProfile.OsDisk.Vhd.Uri.Replace(".vhd", "copy.vhd");
                        vm.StorageProfile.OsDisk.OsType  = OperatingSystemTypes.Windows;
                    }, false, false);
                    Assert.True(vm3.StorageProfile.OsDisk.Image.Uri == imageUri);
                }
                finally
                {
                    // Cleanup the created resources. But don't wait since it takes too long, and it's not the purpose
                    // of the test to cover deletion. CSM does persistent retrying over all RG resources.
                    m_ResourcesClient.ResourceGroups.Delete(rg1Name);
                }
            }
        }
예제 #12
0
        // This method is used when the test is run in an OS that does not support AppExecutionAlias. E,g, our build machine.
        // There is not any existing API that'll activate a packaged app and wait for result, and not possible to capture the stdIn and stdOut.
        // This method tries to call Invoke-CommandInDesktopPackage PS command to make test executable run in packaged context.
        // Since Invoke-CommandInDesktopPackage just launches the executable and return, we use cmd pipe to get execution results.
        // The final constructed command will look like:
        //   Invoke-CommandInDesktopPackage ...... -Command cmd.exe -Args '-c <cmd command>'
        //   where <cmd command> will look like: "echo stdIn | appinst.exe args > stdout.txt 2> stderr.txt & echo %ERRORLEVEL% > exitcode.txt"
        // Then this method will read the piped result and return as RunCommandResult.
        public static RunCommandResult RunAICLICommandViaInvokeCommandInDesktopPackage(string command, string parameters, string stdIn = null, int timeOut = 60000)
        {
            string cmdCommandPiped = "";

            if (!string.IsNullOrEmpty(stdIn))
            {
                cmdCommandPiped += $"echo {stdIn} | ";
            }

            string workDirectory = GetRandomTestDir();
            string tempBatchFile = Path.Combine(workDirectory, "Batch.cmd");
            string exitCodeFile  = Path.Combine(workDirectory, "ExitCode.txt");
            string stdOutFile    = Path.Combine(workDirectory, "StdOut.txt");
            string stdErrFile    = Path.Combine(workDirectory, "StdErr.txt");

            // First change the codepage so that the rest of the batch file works
            cmdCommandPiped += $"chcp 65001\n{AICLIPath} {command} {parameters} > {stdOutFile} 2> {stdErrFile}\necho %ERRORLEVEL% > {exitCodeFile}";
            File.WriteAllText(tempBatchFile, cmdCommandPiped, new System.Text.UTF8Encoding(false));

            string psCommand = $"Invoke-CommandInDesktopPackage -PackageFamilyName {Constants.AICLIPackageFamilyName} -AppId {Constants.AICLIAppId} -PreventBreakaway -Command cmd.exe -Args '/c \"{tempBatchFile}\"'";

            var psInvokeResult = RunCommandWithResult("powershell", psCommand);

            if (psInvokeResult.ExitCode != 0)
            {
                // PS invocation failed, return result and no need to check piped output.
                return(psInvokeResult);
            }

            // The PS command just launches the app and immediately returns, we'll have to wait for up to the timeOut specified here
            int waitedTime = 0;

            while (!File.Exists(exitCodeFile) && waitedTime <= timeOut)
            {
                Thread.Sleep(1000);
                waitedTime += 1000;
            }

            if (waitedTime >= timeOut)
            {
                throw new TimeoutException($"Packaged winget command run timed out: {command} {parameters}");
            }

            RunCommandResult result = new RunCommandResult();

            // Sometimes the files are still in use; allow for this with a wait and retry loop.
            for (int retryCount = 0; retryCount < 4; ++retryCount)
            {
                bool success = false;

                try
                {
                    result.ExitCode = File.Exists(exitCodeFile) ? int.Parse(File.ReadAllText(exitCodeFile).Trim()) : unchecked ((int)0x80004005);
                    result.StdOut   = File.Exists(stdOutFile) ? File.ReadAllText(stdOutFile) : "";
                    result.StdErr   = File.Exists(stdErrFile) ? File.ReadAllText(stdErrFile) : "";
                    success         = true;
                }
                catch (Exception e)
                {
                    TestContext.Out.WriteLine("Failed to access files: " + e.Message);
                }

                if (success)
                {
                    break;
                }
                else
                {
                    Thread.Sleep(250);
                }
            }

            return(result);
        }
예제 #13
0
        public async Task TestVMOperations()
        {
            EnsureClientsInitialized(DefaultLocation);

            ImageReference imageRef = await GetPlatformVMImage(useWindowsImage : true);

            // Create resource group
            string         rg1Name            = Recording.GenerateAssetName(TestPrefix) + 1;
            string         as1Name            = Recording.GenerateAssetName("as");
            string         storageAccountName = Recording.GenerateAssetName(TestPrefix);
            VirtualMachine inputVM1;
            // Create Storage Account, so that both the VMs can share it
            var storageAccountOutput = await CreateStorageAccount(rg1Name, storageAccountName);

            var returnTwovm = await CreateVM(rg1Name, as1Name, storageAccountOutput, imageRef);

            var vm1 = returnTwovm.Item1;

            inputVM1 = returnTwovm.Item2;
            await WaitForCompletionAsync(await VirtualMachinesOperations.StartStartAsync(rg1Name, vm1.Name));
            await WaitForCompletionAsync(await VirtualMachinesOperations.StartRedeployAsync(rg1Name, vm1.Name));
            await WaitForCompletionAsync(await VirtualMachinesOperations.StartRestartAsync(rg1Name, vm1.Name));

            var runCommandImput = new RunCommandInput("RunPowerShellScript")
            {
                Script =
                {
                    "param(",
                    "    [string]$arg1,",
                    "    [string]$arg2",
                    ")",
                    "echo This is a sample script with parameters $arg1 $arg2"
                },
                Parameters =
                {
                    new RunCommandInputParameter("arg1", "value1"),
                    new RunCommandInputParameter("arg2", "value2"),
                }
            };
            RunCommandResult result = (await WaitForCompletionAsync(await VirtualMachinesOperations.StartRunCommandAsync(rg1Name, vm1.Name, runCommandImput))).Value;

            Assert.NotNull(result);
            Assert.NotNull(result.Value);
            Assert.True(result.Value.Count > 0);

            await WaitForCompletionAsync(await VirtualMachinesOperations.StartPowerOffAsync(rg1Name, vm1.Name));
            await WaitForCompletionAsync(await VirtualMachinesOperations.StartDeallocateAsync(rg1Name, vm1.Name));

            await VirtualMachinesOperations.GeneralizeAsync(rg1Name, vm1.Name);

            VirtualMachine ephemeralVM;
            string         as2Name     = as1Name + "_ephemeral";
            var            returnTwoVM = await CreateVM(rg1Name, as2Name, storageAccountName, imageRef, hasManagedDisks : true, hasDiffDisks : true, vmSize : VirtualMachineSizeTypes.StandardDS5V2.ToString(),
                                                        osDiskStorageAccountType : StorageAccountTypes.StandardLRS.ToString(), dataDiskStorageAccountType : StorageAccountTypes.StandardLRS.ToString());

            ephemeralVM = returnTwoVM.Item2;
            await WaitForCompletionAsync(await VirtualMachinesOperations.StartReimageAsync(rg1Name, ephemeralVM.Name));

            var captureParams = new VirtualMachineCaptureParameters(Recording.GenerateAssetName(TestPrefix), Recording.GenerateAssetName(TestPrefix), true);

            var captureResponse = await WaitForCompletionAsync(await VirtualMachinesOperations.StartCaptureAsync(rg1Name, vm1.Name, captureParams));

            Assert.NotNull(captureResponse);
            Assert.True(captureResponse.Value.Resources.Count > 0);
            string resource = captureResponse.Value.Resources[0].ToString();

            Assert.IsTrue(resource.ToLowerInvariant().Contains(captureParams.DestinationContainerName.ToLowerInvariant()));
            Assert.IsTrue(resource.ToLowerInvariant().Contains(captureParams.VhdPrefix.ToLowerInvariant()));
            Resource template = JsonSerializer.Deserialize <Resource>(resource);
            string   imageUri = template.Properties.StorageProfile.OSDisk.Image.Uri;

            Assert.False(string.IsNullOrEmpty(imageUri));

            // Create 3rd VM from the captured image
            // TODO : Provisioning Time-out Issues
            VirtualMachine inputVM2;
            string         as3Name = as1Name + "b";

            returnTwovm = await CreateVM(rg1Name, as3Name, storageAccountOutput, imageRef,
                                         vm =>
            {
                vm.StorageProfile.ImageReference = null;
                vm.StorageProfile.OsDisk.Image   = new VirtualHardDisk {
                    Uri = imageUri
                };
                vm.StorageProfile.OsDisk.Vhd.Uri = vm.StorageProfile.OsDisk.Vhd.Uri.Replace(".vhd", "copy.vhd");
                vm.StorageProfile.OsDisk.OsType  = OperatingSystemTypes.Windows;
            }, false, false);

            var vm3 = returnTwovm.Item1;

            inputVM2 = returnTwovm.Item2;
            Assert.True(vm3.StorageProfile.OsDisk.Image.Uri == imageUri);
        }
        }                                                                                                //从左到右,第一位:代表大版本迭代 ,第二位:代表大版本下的大更新 第三位:代表bug修复次数

        /// <summary>
        /// 命令执行方法约定
        /// </summary>
        public void TryExecute()
        {
            try
            {
                ShowCommandLog("----------------------" + DateTime.Now + ":开始执行命令-----------------------------------------");
                DateTime         startTime = DateTime.Now;
                Stopwatch        sw        = new Stopwatch();
                RunCommandResult r;
                sw.Start();
                try
                {
                    r = Execute();
                    int retryCount = 0;
                    while (r.ExecuteStatus == ExecuteStatus.ExecuteException && retryCount < this.CommandDetail.maxexeceptionretrycount)
                    {
                        int ct = retryCount + 1;
                        ShowCommandLog("**********第" + ct + "次重试 Start**********");
                        r           = Execute();
                        retryCount += 1;
                        ShowCommandLog("**********第" + ct + "次重试 End**********");
                    }
                    r.RetryCount += retryCount;
                }
                catch (Exception ex)
                {
                    r = new RunCommandResult()
                    {
                        ExecuteStatus = ExecuteStatus.ExecuteException, Message = ex.Message, Ex = ex
                    };
                    ShowCommandLog("执行命令异常,异常信息:" + JsonConvert.SerializeObject(ex));
                }
                sw.Stop();
                ShowCommandLog("----------------------" + DateTime.Now + ":执行命令完成-----------------------------------------");
                DateTime endTime = DateTime.Now;
                TimeSpan ts      = sw.Elapsed;
                long     times   = sw.ElapsedMilliseconds / 1000;//秒
                AddCommandExecuteLogRequest addLogReq = new AddCommandExecuteLogRequest()
                {
                    NodeId            = GlobalNodeConfig.NodeID,
                    Source            = Source.Node,
                    CommandEndTime    = endTime.ToString("yyyy-MM-dd HH:mm:ss"),
                    CommandExecuteLog = strLog.ToString(),
                    CommandParams     = JsonConvert.SerializeObject(this.AppConfig),
                    CommandQueueId    = CommandQueue.id,
                    CommandResult     = JsonConvert.SerializeObject(r),
                    ExecuteStatus     = (int)r.ExecuteStatus,
                    CommandStartTime  = startTime.ToString("yyyy-MM-dd HH:mm:ss"),
                    TotalTime         = times.ToString(),
                    CommandDetailId   = CommandDetail.id,
                };
                //上报命令执行日志和执行结果
                var r2 = NodeProxy.PostToServer <EmptyResponse, AddCommandExecuteLogRequest>(ProxyUrl.AddCommandExecuteLog_Url, addLogReq);
                if (r2.Status != ResponesStatus.Success)
                {
                    ShowCommandLog("上报命令(" + CommandDetail.commandmainclassname + ")的执行日志失败,请求地址:" + ProxyUrl.AddCommandExecuteLog_Url + ",请求参数:" + JsonConvert.SerializeObject(addLogReq) + ",服务器返回参数:" + JsonConvert.SerializeObject(r2));
                }
                if (r.ExecuteStatus == ExecuteStatus.ExecuteException)//命令执行异常,报警
                {
                    string        title      = "当前命令队列(" + CommandQueue.id + ")执行失败,请及时处理";
                    StringBuilder strContent = new StringBuilder();
                    strContent.AppendLine("节点编号:" + GlobalNodeConfig.NodeID);
                    strContent.AppendLine("命令队列编号/命令编号:" + CommandQueue.id + "/" + CommandDetail.id.ToString());
                    strContent.AppendLine("命令执行参数:" + JsonConvert.SerializeObject(this.AppConfig));
                    strContent.AppendLine("命令执行起/止时间:" + startTime.ToString("yyyy-MM-dd HH:mm:ss") + "/" + endTime.ToString("yyyy-MM-dd HH:mm:ss"));
                    strContent.AppendLine("命令执行耗时(s):" + times.ToString());
                    strContent.AppendLine("命令执行结果,状态:" + r.ExecuteStatus.description() + ",执行结果:" + JsonConvert.SerializeObject(r));
                    AlarmHelper.AlarmAsync(GlobalNodeConfig.NodeInfo.isenablealarm, (AlarmType)GlobalNodeConfig.NodeInfo.alarmtype, GlobalNodeConfig.Alarm, title, strContent.ToString());
                }
            }
            catch (Exception ex)
            {
                ShowCommandLog("执行命令异常,异常信息:" + JsonConvert.SerializeObject(ex));
                ShowCommandLog("----------------------" + DateTime.Now + ":执行命令完成-----------------------------------------");
                log.Error(strLog.ToString());
            }
            finally
            {
                strLog.Clear();//正常执行完情况strLog日志
            }
        }