protected void DeleteVCloudEnvironmentAsync(TestEnvironment environment) { environment.SetEnvironmentStatus(EnvironmentStatus.Disposing); System.Threading.Tasks.Task.Factory.StartNew ( () => { try { ATFEnvironment.Log.logger.Debug(string.Format("Disposing Envrionment Id = {0}, Name= {1}", environment.EnvironmentId, environment.Name)); Vapp vApp = VCloud.GetVappByName(Organization, VDC, environment.Name); if (vApp != null) { var status = VCloud.GetVAppStatus(vApp); if (!(status == vAppStatus.Undeploy || status == vAppStatus.Error)) { ATFEnvironment.Log.logger.Debug("start undeploy vApp: " + environment.Name); VCloud.UndeployVapp(vApp); ATFEnvironment.Log.logger.Debug("finish undeploy vApp: " + environment.Name); } ATFEnvironment.Log.logger.Debug("start delete vApp: " + environment.Name); VCloud.DeleteVapp(vApp); ATFEnvironment.Log.logger.Debug("finish delete vApp: " + environment.Name); } } catch (Exception ex) { ATFEnvironment.Log.logger.Error(string.Format("Failed to dispose envrionment: {0}. Exception: {1}", environment.Name, ex.Message), ex); environment.SetEnvironmentStatus(EnvironmentStatus.Discard);//here we set the environment to be discard. Because this is a async operation, it's not reasonable to throw an exception. } } ); }
protected void DeployVCloudEnvironmentAsync(TestEnvironment environment, int timeout) { System.Threading.Tasks.Task.Factory.StartNew ( () => { try { var vApp = VCloud.GetVappByName(Organization, VDC, environment.Name); ATFEnvironment.Log.logger.Debug("start deploy vApp: " + environment.Name); VCloud.DeployVapp(vApp, true, timeout, false); ATFEnvironment.Log.logger.Debug("finish deploy vApp: " + environment.Name); } catch (Exception ex) { string errorMsg = string.Format("Failed to Deploy vApp by template: {0}", environment.Description); ATFEnvironment.Log.logger.Error(errorMsg, ex); environment.SetEnvironmentStatus(EnvironmentStatus.Error);//here we set the environment to be error. Because this is a async operation, it's not reasonable to throw an exception. } } ); }
public virtual void UpdateEnvironmentConfig(TestEnvironment environment) { IList<VM> vms = null; try { vms = VCloud.GetVMsByVapp(Organization, VDC, environment.Name); } catch (Exception ex) { ATFEnvironment.Log.logger.Error(string.Format("Failed to get the VMs of the vAPP {0}", environment.Name), ex); } if (vms == null) { ATFEnvironment.Log.logger.Error(string.Format("No vm is found in environment {0}", environment.Name)); return; } string xmlConfig = environment.Config; EnvironmentType type = EnvironmentConfigHelper.GetResidenceType(xmlConfig); foreach (var vm in vms) { string ip = string.Empty; try { ip = vm.GetIpAddressesById().Count > 0 ? vm.GetIpAddressesById().First().Value : string.Empty; } catch(Exception ex) { ATFEnvironment.Log.logger.Error("Could not get the IP address of the VM.", ex); environment.SetEnvironmentStatus(EnvironmentStatus.Error); return; } if (ip != string.Empty) { string externalIP = string.Empty; xmlConfig = EnvironmentConfigHelper.SetMachineIP(xmlConfig, type, vm.Resource.name, ip); try { externalIP = vm.GetNetworkConnections().Count > 0 ? vm.GetNetworkConnections()[0].ExternalIpAddress : string.Empty; } catch (Exception ex) { ATFEnvironment.Log.logger.Error(string.Format("Failed to get the external IP of the VM {0}.", vm.Resource.name), ex); environment.SetEnvironmentStatus(EnvironmentStatus.Error); return; } xmlConfig = EnvironmentConfigHelper.SetMachineExternalIP(xmlConfig, type, vm.Resource.name, externalIP); } else { string message = string.Format("Could not get the IP address for the machine {0}", vm.Resource.name); ATFEnvironment.Log.logger.Error(message); environment.SetEnvironmentStatus(EnvironmentStatus.Error); return; } } environment.SetEnvironmentConfig(xmlConfig); }
protected void CreateVCloudEnvironmentAsync(TestEnvironment environment, int timeout) { environment.SetEnvironmentStatus(EnvironmentStatus.Setup); System.Threading.Tasks.Task.Factory.StartNew ( () => { try { ATFEnvironment.Log.logger.Debug(string.Format("Creating Envrionment Id = {0}, Name= {1}", environment.EnvironmentId, environment.Name)); ATFEnvironment.Log.logger.Info("Try to find vApp Template: " + environment.Description); VappTemplate vAppTemplate = null; vAppTemplate = VCloud.GetVappTemplateByName(Organization, VDC, environment.Description); if (vAppTemplate == null) { string errorMsg = string.Format("vApp template: {0} not find", environment.Description); environment.SetEnvironmentStatus(EnvironmentStatus.Error); ATFEnvironment.Log.logger.Error(errorMsg); throw new EnvironmentException(ModuleName, errorMsg); } ATFEnvironment.Log.logger.Debug("start create vApp: " + environment.Name); var vApp = VCloud.CreateVappFromTemplate(Organization, VDC, environment.Description, environment.Name, timeout); ATFEnvironment.Log.logger.Debug("finish create vApp: " + environment.Name); ATFEnvironment.Log.logger.Debug("start deploy vApp: " + environment.Name); VCloud.DeployVapp(vApp, true, timeout, false); ATFEnvironment.Log.logger.Debug("start deploy vApp: " + environment.Name); } catch (Exception ex) { string errorMsg = string.Format("Failed to create vApp by template: {0}", environment.Description); ATFEnvironment.Log.logger.Error(errorMsg, ex); environment.SetEnvironmentStatus(EnvironmentStatus.Error);//here we set the environment to be error. Because this is a async operation, it's not reasonable to throw an exception. } } ); }
/// <summary> /// Refresh environment status /// </summary> /// <param name="environment"></param> public virtual void RefreshEnvironmentStatus(TestEnvironment environment) { TestEnvironmentConfigHelper config = new TestEnvironmentConfigHelper(environment.Config); EnvironmentType type = config.Type; EnvironmentDeploymentType deployType = EnvironmentDeploymentType.Undefined; vAppStatus status = vAppStatus.Unknow; switch (type) { case EnvironmentType.Residence_Together: deployType = config.SUTConfiguration.DeploymentType; break; case EnvironmentType.SUTAlone: deployType = config.SUTConfiguration.DeploymentType; break; case EnvironmentType.TestAgentAlone: deployType = config.TestAgentConfiguration.DeploymentType; break; } switch (environment.EnvironmentStatus) { case EnvironmentStatus.New: if (deployType == EnvironmentDeploymentType.ToBeCreated) { try { if (IsAllowNewVappDeploy()) { RequestEnvironment(environment); } } catch (Exception ex) { ATFEnvironment.Log.logger.Error(ex); } } else { environment.SetEnvironmentStatus(EnvironmentStatus.AgentServiceInstalledAndReady); } break; case EnvironmentStatus.Setup: status = vAppStatus.Unknow; try { status = VCloud.GetVAppStatus(Organization, VDC, environment.Name); } catch (Exception ex) { ATFEnvironment.Log.logger.Error("Failed to get the status of vAPP.", ex); } switch (status) { case vAppStatus.Error: environment.SetEnvironmentStatus(EnvironmentStatus.Error); break; case vAppStatus.Ready: UpdateEnvironmentConfig(environment); environment.SetEnvironmentStatus(EnvironmentStatus.MachinesReady); break; case vAppStatus.NotExist://Neil, sometimes the vAPP is not created yet, and request another environment with the same name will cause exception. //if (IsAllowNewVappDeploy()) //{ // RequestEnvironment(environment); //} break; // redeploy case vAppStatus.Unknow: case vAppStatus.Undeploy://Neil, The deployment will be done when request the environment, here we did nothing. //if (IsAllowNewVappDeploy()) //{ // DeployVCloudEnvironmentAsync(environment, 1000 * 60 * 30); //} break; } break; case EnvironmentStatus.MachinesReady: break; case EnvironmentStatus.AgentServiceInstalledAndReady: break; case EnvironmentStatus.BuildInstalled: break; case EnvironmentStatus.Ready: break; case EnvironmentStatus.Error: break; case EnvironmentStatus.Discard: DisposeEnvironment(environment); break; case EnvironmentStatus.Disposing: status = vAppStatus.Unknow; try { status = VCloud.GetVAppStatus(Organization, VDC, environment.Name); } catch (Exception ex) { ATFEnvironment.Log.logger.Error("Failed to get the status of vAPP.", ex); } switch (status) { case vAppStatus.NotExist: environment.SetEnvironmentStatus(EnvironmentStatus.Disposed); break; case vAppStatus.Ready: DisposeEnvironment(environment); break; case vAppStatus.Undeploy: DisposeEnvironment(environment); break; case vAppStatus.Error: DisposeEnvironment(environment); break; } break; } }
/// <summary> /// Install the test agent windows service on the test agent /// </summary> private static void InstallTestAgentWindowsServiceOnEnvironmentAsynchronous(TestEnvironment testEnvironment) { System.Threading.Tasks.Task.Factory.StartNew ( () => { AutomationJob job = GetAutomationJobOfTestEnvironment(testEnvironment); try { job.AddJobProgressInformation(string.Format("Start to install the Saber Agent Service on environment [{0}] for Job [{1}]", testEnvironment.Name, job.Name)); //RemoteInstallTestAgentWindowsServiceConcurrentlyAndWaitToFinish(testEnvironment); if (RemoteInstallTestAgentWindowsFormAppConcurrentlyAndWaitToFinsh(testEnvironment)) { job.AddJobProgressInformation(string.Format("The Saber Agent service has been installed on environment [{0}] for Job [{1}]", testEnvironment.Name, job.Name)); testEnvironment.SetEnvironmentStatus(EnvironmentStatus.AgentServiceInstalledAndReady); } else { job.AddJobProgressInformation(string.Format("The Saber Agent service failed to be installed on environment [{0}] for Job [{1}]", testEnvironment.Name, job.Name)); job.SetJobsStatus(JobStatus.Failed); } } catch (Exception ex) { //TODO, exception handling, we may need to revert the record in DB -> reinstall the windows services. ATFEnvironment.Log.logger.Error(string.Format("Error happened when install the Saber Agent service on machine [{0}]", testEnvironment.Name), ex); job.SetJobsStatus(JobStatus.Failed); } } ); }
/// <summary> /// Request the test agent environment for the job /// </summary> /// <param name="job">job</param> /// <param name="provider">environment provider</param> public void RequestTestAgentEnvironmentForJob(AutomationJob job, IEnvironmentProvider provider) { SupportedEnvironment supportEnvironment = job.GetSupportedEnv(); AutomationTask task = JobManagement.GetAutomationTaskOfJob(job); string templateName = new TestEnvironmentConfigHelper(supportEnvironment.Config).TestAgentConfiguration.Name; string environmentName = string.Format("{0}_{1}_{2}_{3}", task.Name, job.JobId, "TestAgent", Guid.NewGuid()); TestEnvironmentConfigHelper sutConfig = new TestEnvironmentConfigHelper(supportEnvironment.Config); // Get the avaliable permenent agent, typically we maintain a pool of machines act as the test agent, no need to deploy new vApps // If no available agents in the pool now, we'll create a new vApp from the template with name of templateName TestEnvironment availableReadyStaticAgent = TestEnvironment.GetAvalibleStaticTestAgent4SupportedEnvironment(supportEnvironment); EnvironmentDeploymentType deployType = new TestEnvironmentConfigHelper(supportEnvironment.Config).TestAgentConfiguration.DeploymentType; if (deployType == EnvironmentDeploymentType.Existing ) { if (availableReadyStaticAgent != null) { string info = string.Format("Find one avaliable permanent test agent [{0}:{1}] for job [{2}]", availableReadyStaticAgent.EnvironmentId, availableReadyStaticAgent.Name, job.Name); availableReadyStaticAgent.SetEnvironmentStatus(EnvironmentStatus.MachinesReady); ATFEnvironment.Log.logger.Info(info); job.AddJobProgressInformation(info); // set SUT information to test agent's config // set test agent type to TestAgentAlone /* TestEnvironmentConfigHelper testAgentConfig = new TestEnvironmentConfigHelper(availableReadyStaticAgent.Config); testAgentConfig.SUTConfiguration = sutConfig.SUTConfiguration; testAgentConfig.Type = EnvironmentType.TestAgentAlone; availableReadyStaticAgent.Config = testAgentConfig.ToXML(); info = string.Format("Change the permanent agent's status, AgentServiceInstalledAndReady -> Ocuppied"); ATFEnvironment.Log.logger.Info(info); job.AddJobProgressInformation(info); // Set this permanent agent to occuppied //availableReadyStaticAgent.Status = (int)EnvironmentStatus.Ocuppied; //availableReadyStaticAgent.Update(); TestEnvironmentConfigHelper config = new TestEnvironmentConfigHelper(availableReadyStaticAgent.Config); //clear the finished job information config.TestAgentConfiguration.Categories.Clear(); //add the jobId into the configuration file to let the Test Agent know which job the test agent is for. config.TestAgentConfiguration.Categories.Add("JobId=" + job.JobId.ToString()); availableReadyStaticAgent.Config = config.ToXML(); availableReadyStaticAgent.Update(); //copy the config file to the test agent List<Machine> testAgents = GetMachinesNeedTestAgentInstalledOn(config); string ip = testAgents.Count() > 0 ? testAgents[0].ExternalIP : string.Empty; string domain = config.TestAgentConfiguration.TestAgentDomainConfig.Name; string administrator = config.TestAgentConfiguration.TestAgentDomainConfig.Adminstrator; string password = config.TestAgentConfiguration.TestAgentDomainConfig.Password; string targetPath = @"\\" + ip + @"\C$\SaberAgent"; string targetEnvironmentConfigFolder = targetPath + @"\Config"; string targetEnvironmentConfigFile = targetEnvironmentConfigFolder + @"\Environment.xml"; if (!NetUseHelper.NetUserMachine(ip, domain + @"\" + administrator, password)) { ATFEnvironment.Log.logger.Error(string.Format("Net use the machine [{0}] failed.", ip)); } Common.ScriptCommon.CMDScript.FlushDNSRemotely(ip, domain + @"\" + administrator, password); if (!FileHelper.IsExistsFolder(targetEnvironmentConfigFolder)) { FileHelper.CreateFolder(targetEnvironmentConfigFolder); } TXTHelper.ClearTXTContent(targetEnvironmentConfigFile); TXTHelper.WriteNewLine(targetEnvironmentConfigFile, config.ToXML(), System.Text.Encoding.Default); info = string.Format("Copy the file[{0}] to permanent agent", targetEnvironmentConfigFile); ATFEnvironment.Log.logger.Info(info); job.AddJobProgressInformation(info); */ job.SetTestAgentEnvironment(availableReadyStaticAgent.EnvironmentId); } else { string info = string.Format("There's no available test agents right now, please wait other tasks to free some environments."); ATFEnvironment.Log.logger.Info(info); job.AddJobProgressInformation(info); } } else { //create a new record in DB for Test Agent, and Galaxy will handle the environment later(install, config and so on) sutConfig.TestAgentConfiguration.DeploymentType = EnvironmentDeploymentType.ToBeCreated; sutConfig.Type = EnvironmentType.TestAgentAlone; string config = sutConfig.ToXML(); try { var testEnvironment = new TestEnvironment { ProviderId = provider.Provider.ProviderId, Name = environmentName, Type = provider.Provider.Name, Status = (int)EnvironmentStatus.New, CreateDate = DateTime.UtcNow, ModifyDate = DateTime.UtcNow, //Config = EnvironmentConfigHelper.SetResidenceType(supportEnvironment.Config, EnvironmentType.TestAgentAlone), Config = config, Description = templateName, }; if (job.JobStatus == JobStatus.Cancelled || job.JobStatus == JobStatus.End) { testEnvironment.SetEnvironmentStatus(EnvironmentStatus.Discard); } TestEnvironment.Add(testEnvironment); job.SetTestAgentEnvironment(testEnvironment.EnvironmentId); } catch (Exception ex) { job.SetJobsStatus(JobStatus.Failed); string info = string.Format("Failed to request Test Agent environment {0}, Exception: {1}", environmentName, ex.Message); job.AddJobProgressInformation(info); ATFEnvironment.Log.logger.Error(info, ex); } } }
/// <summary> /// Request the sut environment for job /// </summary> /// <param name="job">job</param> /// <param name="provider">environment provider</param> public void RequestSUTEnvironmentForJob(AutomationJob job, IEnvironmentProvider provider) { SupportedEnvironment supportEnvironment = job.GetSupportedEnv(); TestEnvironmentConfigHelper config = new TestEnvironmentConfigHelper(supportEnvironment.Config); string templateName = config.SUTConfiguration.Name; string sutConfig = string.Empty; if (config.Type == EnvironmentType.Residence_Seperate) { sutConfig = EnvironmentConfigHelper.SetResidenceType(supportEnvironment.Config, EnvironmentType.SUTAlone); } else if (config.Type == EnvironmentType.Residence_Together) { sutConfig = EnvironmentConfigHelper.SetResidenceType(supportEnvironment.Config, EnvironmentType.Residence_Together); } AutomationTask task = JobManagement.GetAutomationTaskOfJob(job); if (config.SUTConfiguration.DeploymentType == EnvironmentDeploymentType.Existing) { //Note: the existing SUT environments are distinguished by it's name, two environments with same name are considered as the same one var sutEnvironment = TestEnvironment.GetAvalibleStaticSUT4SupportedEnvironment(supportEnvironment); if (sutEnvironment == null)//wait untill another environment is freed { string info = string.Format("There's no SUT environment in the pool available now, please wait for other tasks to free any environment."); ATFEnvironment.Log.logger.Info(info); job.AddJobProgressInformation(info); } else//reuse the record { string message = string.Format("Get an available SUT environment [{0}] for the job [{1}:{2}]", sutEnvironment.Name, job.JobId, job.Name); job.AddJobProgressInformation(message); message = string.Format("Change environment [{0}:{1}] status from {2} to {3}", sutEnvironment.EnvironmentId, sutEnvironment.Name, sutEnvironment.Status, "MachinesReady"); job.AddJobProgressInformation(message); sutEnvironment.SetEnvironmentStatus(EnvironmentStatus.MachinesReady); job.SetSUTEnvironment(sutEnvironment.EnvironmentId); } } else { string environmentName = string.Format("{0}_{1}_{2}_{3}", task.Name, job.JobId, "SUT", Guid.NewGuid()); try { var testEnvironment = new TestEnvironment { ProviderId = provider.Provider.ProviderId, Name = environmentName, Type = provider.Provider.Name, CreateDate = DateTime.UtcNow, ModifyDate = DateTime.UtcNow, Config = sutConfig, Description = templateName, }; if (job.JobStatus == JobStatus.Cancelled || job.JobStatus == JobStatus.End) testEnvironment.SetEnvironmentStatus(EnvironmentStatus.Discard); TestEnvironment.Add(testEnvironment); string message = string.Format("Environment [{0}:{1} is created for job [{2}:{3}]]", testEnvironment.EnvironmentId, testEnvironment.Name, job.JobId, job.Name); job.AddJobProgressInformation(message); job.SetSUTEnvironment(testEnvironment.EnvironmentId); } catch (Exception ex) { string info = string.Format("Failed to assign {0}, Exception: {1}", environmentName, ex.Message); job.SetJobsStatus(JobStatus.Failed); job.AddJobProgressInformation(info); ATFEnvironment.Log.logger.Error(info, ex); } } }
/// <summary> /// Handle the test environment with machines ready, work include: /// 1. Install the Saber Agent services on the machines and start the services on remote machine /// 2. Update the environment information for the TestAgent and SUT, then the TestAgent and SUT know the details of each other(mainly IPs here) /// 3. Specify what kinds of works the Saber Agent services will take after it restarted. such as /// 1). to tell services hosted on test agent to install the S1 build /// 2). to tell the services hosted on test agent to run the test case for which job /// 4. After that, the test environment status is AgentServiceInstalling or AgentServiceInstalledAndReady /// Below actions are taken by other components /// 5. The saber agent service on the test agent will install the S1 build, before that it'll wait the SUT to be AgentServiceInstalledAndReady /// 6. The saber agent service will set the environment status to be BuildInstalled /// 7. Then the environment manager will restart all the machines in SUT /// 8. After restarted, the saber agent in test agent will check all the machines in SUT are started and start to run the test cases. /// </summary> /// <param name="environment"></param> public void HandleTestEnvironmentWithStatusMachinesReady(TestEnvironment environment) { EnvironmentType type = EnvironmentConfigHelper.GetResidenceType(environment.Config); if (type == EnvironmentType.Residence_Together) { //add the jobId into the configuration file to let the Test Agent know which job the test agent is for. TestEnvironmentConfigHelper config = new TestEnvironmentConfigHelper(environment.Config); config.TestAgentConfiguration.Categories.Add(string.Format("JobId={0}", EnvironmentManager.GetAutomationJobOfTestEnvironment(environment).JobId.ToString())); //config.TestAgentConfiguration.Categories.Add(string.Format("mode={0}", SaberAgentMode.InstallS1Build)); environment.SetEnvironmentConfig(config.ToXML()); environment.SetEnvironmentStatus(EnvironmentStatus.AgentServiceInstalling); try { InstallTestAgentWindowsServiceOnEnvironmentAsynchronous(environment); } catch (Exception ex) { ATFEnvironment.Log.logger.Error(string.Format("Execption captured when install test agent windows service on environment asynchronously for environment {0}",environment.EnvironmentId), ex); } ATFEnvironment.Log.logger.Info(string.Format("Test Agents started to be installed on environment {0}", environment.Name)); ATFEnvironment.Log.logger.Info(string.Format("Environment status changes from MachinesReady -> AgentServiceInstalling")); } else if (type == EnvironmentType.TestAgentAlone) { //to make sure in the test agent, we have the information about the SUT, //we'll first check whether the SUT is MachinesReady, //if yes, we'll copy the SUT config to the TestAgent config, then setup the Saber Agent //else, do nothing and wait another loop TestEnvironment sutEnvironment = EnvironmentManager.GetSUTEnvironmentOfTestAgentEnvironment(environment); if (null != sutEnvironment) { //if the sut is machine ready or other status after machine ready if (sutEnvironment.EnvironmentStatus == EnvironmentStatus.MachinesReady || sutEnvironment.EnvironmentStatus == EnvironmentStatus.AgentServiceInstalling || sutEnvironment.EnvironmentStatus == EnvironmentStatus.AgentServiceInstalledAndReady || sutEnvironment.EnvironmentStatus == EnvironmentStatus.BuildInstalled || sutEnvironment.EnvironmentStatus == EnvironmentStatus.Ready ) { //update the SUT part of the configuration of the test agent configuration. //then the test agent know the detail of the SUT. TestEnvironmentConfigHelper sutConfig = new TestEnvironmentConfigHelper(sutEnvironment.Config); TestEnvironmentConfigHelper testAgentConfig = new TestEnvironmentConfigHelper(environment.Config); testAgentConfig.SUTConfiguration = sutConfig.SUTConfiguration; environment.SetEnvironmentConfig(testAgentConfig.ToXML()); //add the jobId into the configuration file to let the Test Agent know which job the test agent is for. TestEnvironmentConfigHelper config = new TestEnvironmentConfigHelper(environment.Config); config.TestAgentConfiguration.Categories.Add("JobId=" + EnvironmentManager.GetAutomationJobOfTestEnvironment(environment).JobId.ToString()); environment.SetEnvironmentConfig(config.ToXML()); //Install the Saber Agent service into the environment environment.SetEnvironmentStatus(EnvironmentStatus.AgentServiceInstalling); InstallTestAgentWindowsServiceOnEnvironmentAsynchronous(environment); ATFEnvironment.Log.logger.Info(string.Format("Start to install Saber Agent on environment {0}", environment.Name)); ATFEnvironment.Log.logger.Info(string.Format("Environment status changes from MachinesReady -> AgentServiceInstalling")); } } } else if (type == EnvironmentType.SUTAlone)//TODO, do we need to install the build on the SUT? currently we do nothing and assume that the environment is ready { TestEnvironmentConfigHelper config = new TestEnvironmentConfigHelper(environment.Config); config.TestAgentConfiguration.Categories.Add(string.Format("JobId={0}", EnvironmentManager.GetAutomationJobOfTestEnvironment(environment).JobId.ToString())); environment.SetEnvironmentConfig(config.ToXML()); ATFEnvironment.Log.logger.Info(string.Format("Test Agents started to be installed on environment {0}", environment.Name)); //ATFEnvironment.Log.logger.Info(string.Format("Environment status changes from {0} -> AgentServiceInstalling", environment.EnvironmentStatus)); environment.SetEnvironmentStatus(EnvironmentStatus.AgentServiceInstalling); InstallTestAgentWindowsServiceOnEnvironmentAsynchronous(environment); ATFEnvironment.Log.logger.Info(string.Format("Test Agents have been installed on environment {0}", environment.Name)); } }