public void CalculateServiceNameSanitizeOutOfRangeChars()
        {
            RunnerSettings settings = new RunnerSettings();

            settings.AgentName = "name";
            settings.ServerUrl = "https://example.githubusercontent.com/12345678901234567890123456789012345678901234567890";
            settings.GitHubUrl = "https://github.com/org!@$*+[]()/repo!@$*+[]()";

            string serviceNamePattern        = "actions.runner.{0}.{1}";
            string serviceDisplayNamePattern = "GitHub Actions Runner ({0}.{1})";

            using (TestHostContext hc = CreateTestContext())
            {
                ServiceControlManager scm = new ServiceControlManager();

                scm.Initialize(hc);
                scm.CalculateServiceName(
                    settings,
                    serviceNamePattern,
                    serviceDisplayNamePattern,
                    out string serviceName,
                    out string serviceDisplayName);

                var serviceNameParts = serviceName.Split('.');

                // Verify service name parts are sanitized correctly
                Assert.Equal("actions", serviceNameParts[0]);
                Assert.Equal("runner", serviceNameParts[1]);
                Assert.Equal("org----------repo---------", serviceNameParts[2]); // Chars replaced with '-'
                Assert.Equal("name", serviceNameParts[3]);
            }
        }
        public void GenerateScripts(RunnerSettings settings)
        {
            try
            {
                string serviceName;
                string serviceDisplayName;
                CalculateServiceName(settings, _svcNamePattern, _svcDisplayPattern, out serviceName, out serviceDisplayName);

                string svcShPath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), _shName);

                string svcShContent    = File.ReadAllText(Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), _shTemplate));
                var    tokensToReplace = new Dictionary <string, string>
                {
                    { "{{SvcDescription}}", serviceDisplayName },
                    { "{{SvcNameVar}}", serviceName }
                };

                svcShContent = tokensToReplace.Aggregate(
                    svcShContent,
                    (current, item) => current.Replace(item.Key, item.Value));

                File.WriteAllText(svcShPath, svcShContent, new UTF8Encoding(false));

                var unixUtil = HostContext.CreateService <IUnixUtil>();
                unixUtil.ChmodAsync("755", svcShPath).GetAwaiter().GetResult();
            }
            catch (Exception ex)
            {
                Trace.Error(ex);
                throw;
            }
        }
        public void CalculateServiceNameLimitsServiceNameTo80Chars()
        {
            RunnerSettings settings = new RunnerSettings();

            settings.AgentName = "thisisareallyreallylongbutstillvalidagentname";
            settings.ServerUrl = "https://example.githubusercontent.com/12345678901234567890123456789012345678901234567890";
            settings.GitHubUrl = "https://github.com/myreallylongorganizationexample/myreallylongrepoexample";

            string serviceNamePattern        = "actions.runner.{0}.{1}";
            string serviceDisplayNamePattern = "GitHub Actions Runner ({0}.{1})";

            using (TestHostContext hc = CreateTestContext())
            {
                ServiceControlManager scm = new ServiceControlManager();

                scm.Initialize(hc);
                scm.CalculateServiceName(
                    settings,
                    serviceNamePattern,
                    serviceDisplayNamePattern,
                    out string serviceName,
                    out string serviceDisplayName);

                // Verify name has been shortened to 80 characters
                Assert.Equal(80, serviceName.Length);

                var serviceNameParts = serviceName.Split('.');

                // Verify that each component has been shortened to a sensible length
                Assert.Equal("actions", serviceNameParts[0]);                                       // Never shortened
                Assert.Equal("runner", serviceNameParts[1]);                                        // Never shortened
                Assert.Equal("myreallylongorganizationexample-myreallylongr", serviceNameParts[2]); // First 45 chars, '/' has been replaced with '-'
                Assert.Equal("thisisareallyreally", serviceNameParts[3]);                           // Remainder of unused chars
            }
        }
        public void CalculateServiceName80Chars()
        {
            RunnerSettings settings = new RunnerSettings();

            settings.AgentName = "thisiskindofalongrunnername12";
            settings.ServerUrl = "https://example.githubusercontent.com/12345678901234567890123456789012345678901234567890";
            settings.GitHubUrl = "https://github.com/myorganizationexample/myrepoexample";

            string serviceNamePattern        = "actions.runner.{0}.{1}";
            string serviceDisplayNamePattern = "GitHub Actions Runner ({0}.{1})";

            using (TestHostContext hc = CreateTestContext())
            {
                ServiceControlManager scm = new ServiceControlManager();

                scm.Initialize(hc);
                scm.CalculateServiceName(
                    settings,
                    serviceNamePattern,
                    serviceDisplayNamePattern,
                    out string serviceName,
                    out string serviceDisplayName);

                // Verify name is still equal to 80 characters
                Assert.Equal(80, serviceName.Length);

                var serviceNameParts = serviceName.Split('.');

                // Verify nothing has been shortened out
                Assert.Equal("actions", serviceNameParts[0]);
                Assert.Equal("runner", serviceNameParts[1]);
                Assert.Equal("myorganizationexample-myrepoexample", serviceNameParts[2]); // '/' has been replaced with '-'
                Assert.Equal("thisiskindofalongrunnername12", serviceNameParts[3]);
            }
        }
Пример #5
0
        public async Task CanEnsureConfigure()
        {
            using (TestHostContext tc = CreateTestContext())
            {
                Tracing trace = tc.GetTrace();

                trace.Info("Creating config manager");
                IConfigurationManager configManager = new ConfigurationManager();
                configManager.Initialize(tc);

                var userLabels = "userlabel1,userlabel2";

                trace.Info("Preparing command line arguments");
                var command = new CommandSettings(
                    tc,
                    new[]
                {
                    "configure",
                    "--url", _expectedServerUrl,
                    "--name", _expectedAgentName,
                    "--runnergroup", _secondRunnerGroupName,
                    "--work", _expectedWorkFolder,
                    "--auth", _expectedAuthType,
                    "--token", _expectedToken,
                    "--labels", userLabels,
                    "--ephemeral",
                });
                trace.Info("Constructed.");
                _store.Setup(x => x.IsConfigured()).Returns(false);
                _configMgrAgentSettings = null;

                trace.Info("Ensuring all the required parameters are available in the command line parameter");
                await configManager.ConfigureAsync(command);

                _store.Setup(x => x.IsConfigured()).Returns(true);

                trace.Info("Configured, verifying all the parameter value");
                var s = configManager.LoadSettings();
                Assert.NotNull(s);
                Assert.True(s.ServerUrl.Equals(_expectedServerUrl));
                Assert.True(s.AgentName.Equals(_expectedAgentName));
                Assert.True(s.PoolId.Equals(_secondRunnerGroupId));
                Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));
                Assert.True(s.Ephemeral.Equals(true));

                // validate GetAgentPoolsAsync gets called twice with automation pool type
                _runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny <string>(), It.Is <TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(2));

                var expectedLabels = new List <string>()
                {
                    "self-hosted", VarUtil.OS, VarUtil.OSArchitecture
                };
                expectedLabels.AddRange(userLabels.Split(",").ToList());

                _runnerServer.Verify(x => x.AddAgentAsync(It.IsAny <int>(), It.Is <TaskAgent>(a => a.Labels.Select(x => x.Name).ToHashSet().SetEquals(expectedLabels))), Times.Once);
            }
        }
Пример #6
0
        public async void RenewJobRequestNewAgentNameUpdatesSettings()
        {
            //Arrange
            using (var hc = new TestHostContext(this))
            {
                var count       = 0;
                var oldName     = "OldName";
                var newName     = "NewName";
                var oldSettings = new RunnerSettings {
                    AgentName = oldName
                };
                var reservedAgent = new TaskAgentReference {
                    Name = newName
                };

                var trace = hc.GetTrace(nameof(DispatcherRenewJobRequestStopOnJobTokenExpiredExceptions));
                TaskCompletionSource <int> firstJobRequestRenewed  = new TaskCompletionSource <int>();
                CancellationTokenSource    cancellationTokenSource = new CancellationTokenSource();

                var request = new Mock <TaskAgentJobRequest>();
                request.Object.ReservedAgent = reservedAgent;
                PropertyInfo lockUntilProperty = request.Object.GetType().GetProperty("LockedUntil", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                Assert.NotNull(lockUntilProperty);
                lockUntilProperty.SetValue(request.Object, DateTime.UtcNow.AddMinutes(5));
                hc.SetSingleton <IRunnerServer>(_runnerServer.Object);
                hc.SetSingleton <IConfigurationStore>(_configurationStore.Object);
                _configurationStore.Setup(x => x.GetSettings()).Returns(oldSettings);
                _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny <int>(), It.IsAny <long>(), It.IsAny <Guid>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
                .Returns(() =>
                {
                    count++;
                    if (count < 5)
                    {
                        return(Task.FromResult <TaskAgentJobRequest>(request.Object));
                    }
                    else if (count == 5 || count == 6 || count == 7)
                    {
                        throw new TimeoutException("");
                    }
                    else
                    {
                        cancellationTokenSource.Cancel();
                        return(Task.FromResult <TaskAgentJobRequest>(request.Object));
                    }
                });

                var jobDispatcher = new JobDispatcher();
                jobDispatcher.Initialize(hc);

                // Act
                await jobDispatcher.RenewJobRequestAsync(0, 0, Guid.Empty, Guid.NewGuid().ToString(), firstJobRequestRenewed, cancellationTokenSource.Token);

                // Assert
                _configurationStore.Verify(x => x.SaveSettings(It.Is <RunnerSettings>(settings => settings.AgentName == newName)), Times.Once);
            }
        }
Пример #7
0
 public MessageListenerL0()
 {
     _settings = new RunnerSettings {
         AgentId = 1, AgentName = "myagent", PoolId = 123, PoolName = "default", ServerUrl = "http://myserver", WorkFolder = "_work"
     };
     _config = new Mock <IConfigurationManager>();
     _config.Setup(x => x.LoadSettings()).Returns(_settings);
     _runnerServer = new Mock <IRunnerServer>();
     _credMgr      = new Mock <ICredentialManager>();
 }
Пример #8
0
        public override void Help()
        {
            CpuSettings    cpuSettings = SettingsManager.GetSettings <CpuSettings>();
            RunnerSettings settings    = new RunnerSettings();

            HlCompilerSettings hls = SettingsManager.GetSettings <HlCompilerSettings>();
            MemorySettings     ms  = SettingsManager.GetSettings <MemorySettings>();
            MemoryBusSettings  mbs = SettingsManager.GetSettings <MemoryBusSettings>();

            HelpSubSystem.WriteSubsystem("vis run", settings, hls, ms, mbs, cpuSettings);
        }
Пример #9
0
 public void ConfigureRun(
     string assemblyLocation,
     IEnumerable <string> categories,
     IEnumerable <string> otherTestFixtures,
     IEnumerable <string> categoriesToRun,
     RunnerSettings runnerSettings)
 {
     _assemblyLocation = assemblyLocation;
     _runnerSettings   = runnerSettings;
     //TODO does this design make any sense... not all runners need the same thing
     throw new NotImplementedException("This runner needs to be completely re-worked...");
 }
Пример #10
0
        public RunnerSettings LoadSettings()
        {
            Trace.Info(nameof(LoadSettings));
            if (!IsConfigured())
            {
                throw new InvalidOperationException("Not configured");
            }

            RunnerSettings settings = _store.GetSettings();

            Trace.Info("Settings Loaded");

            return(settings);
        }
Пример #11
0
        private static string RunPreRunSteps(RunnerSettings settings, string file)
        {
            string ret = file;

            foreach (KeyValuePair <string, Func <string, string> > keyValuePair in settings.PreRunMap)
            {
                if (Path.GetExtension(ret) == keyValuePair.Key)
                {
                    ret = RunPreRunSteps(settings, keyValuePair.Value(ret));
                }
            }

            return(ret);
        }
 public ReflectionDiscovery(IBenchmarkOutput output, IBenchmarkAssertionRunner benchmarkAssertions, RunnerSettings settings)
 {
     Output = output;
     BenchmarkAssertions = benchmarkAssertions;
     RunnerSettings      = settings;
     if (RunnerSettings.TracingEnabled)
     {
         Trace = new BenchmarkOutputTrace(Output);
     }
     else
     {
         Trace = NoOpBenchmarkTrace.Instance;
     }
 }
Пример #13
0
        public async Task CanEnsureConfigure()
        {
            using (TestHostContext tc = CreateTestContext())
            {
                Tracing trace = tc.GetTrace();

                trace.Info("Creating config manager");
                IConfigurationManager configManager = new ConfigurationManager();
                configManager.Initialize(tc);

                trace.Info("Preparing command line arguments");
                var command = new CommandSettings(
                    tc,
                    new[]
                {
                    "configure",
                    "--url", _expectedServerUrl,
                    "--name", _expectedAgentName,
                    "--pool", _expectedPoolName,
                    "--work", _expectedWorkFolder,
                    "--auth", _expectedAuthType,
                    "--token", _expectedToken
                });
                trace.Info("Constructed.");
                _store.Setup(x => x.IsConfigured()).Returns(false);
                _configMgrAgentSettings = null;

                trace.Info("Ensuring all the required parameters are available in the command line parameter");
                await configManager.ConfigureAsync(command);

                _store.Setup(x => x.IsConfigured()).Returns(true);

                trace.Info("Configured, verifying all the parameter value");
                var s = configManager.LoadSettings();
                Assert.NotNull(s);
                Assert.True(s.ServerUrl.Equals(_expectedServerUrl));
                Assert.True(s.AgentName.Equals(_expectedAgentName));
                Assert.True(s.PoolId.Equals(_expectedPoolId));
                Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));

                // validate GetAgentPoolsAsync gets called once with automation pool type
                _runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny <string>(), It.Is <TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Once);

                _runnerServer.Verify(x => x.AddAgentAsync(It.IsAny <int>(), It.Is <TaskAgent>(a => a.Labels.Contains("self-hosted") && a.Labels.Contains(VarUtil.OS) && a.Labels.Contains(VarUtil.OSArchitecture))), Times.Once);
            }
        }
Пример #14
0
        public async Task ConfigureErrorOnMissingRunnerGroup()
        {
            using (TestHostContext tc = CreateTestContext())
            {
                var expectedPools = new List <TaskAgentPool>()
                {
                    new TaskAgentPool(_defaultRunnerGroupName)
                    {
                        Id = _defaultRunnerGroupId, IsInternal = true
                    }
                };
                _runnerServer.Setup(x => x.GetAgentPoolsAsync(It.IsAny <string>(), It.IsAny <TaskAgentPoolType>())).Returns(Task.FromResult(expectedPools));

                Tracing trace = tc.GetTrace();

                trace.Info("Creating config manager");
                IConfigurationManager configManager = new ConfigurationManager();
                configManager.Initialize(tc);


                trace.Info("Preparing command line arguments");
                var command = new CommandSettings(
                    tc,
                    new[]
                {
                    "configure",
                    "--url", _expectedServerUrl,
                    "--name", _expectedAgentName,
                    "--runnergroup", "notexists",
                    "--work", _expectedWorkFolder,
                    "--auth", _expectedAuthType,
                    "--token", _expectedToken,
                });
                trace.Info("Constructed.");
                _store.Setup(x => x.IsConfigured()).Returns(false);
                _configMgrAgentSettings = null;

                trace.Info("Ensuring all the required parameters are available in the command line parameter");
                var ex = await Assert.ThrowsAsync <TaskAgentPoolNotFoundException>(() => configManager.ConfigureAsync(command));

                Assert.Contains("notexists", ex.Message);

                _runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny <string>(), It.Is <TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(1));
            }
        }
Пример #15
0
        static int Main(string[] args)
        {
            var runnerSettings = new RunnerSettings();
            var showHelp       = false;
            var displayDetails = false;

            var options = new OptionSet
            {
                { "r|recursive", "Recursive", v => runnerSettings.Recursive = v != null },
                { "h|help", "Show help", v => showHelp = true },
                { "d|details", "Display Details", v => displayDetails = true }
            };

            try
            {
                runnerSettings.StartPaths = options.Parse(args).ToArray();
            }
            catch (OptionException e)
            {
                Console.Write("invalid options: {0}", e.Message);
                Console.WriteLine("Try `DotNetAssemblyInformer --help' for more information.");
                return(-1);
            }

            if (showHelp)
            {
                ShowHelp(options);
                return(0);
            }

            var runner       = new Runner(runnerSettings);
            var runnerResult = runner.Run();

            var reporter = !displayDetails ? new BasicConsoleReporter() : new JsonConsoleReporter();

            reporter.Generate(runnerResult);

            if (Debugger.IsAttached)
            {
                Console.ReadKey();
            }

            return(runnerResult.OverralSuccess ? 0 : 1);
        }
Пример #16
0
        public static Cpu Create(
            IEnumerable <string> args,
            CpuSettings cpuSettings = null,
            RunnerSettings settings = null,
            HlCompilerSettings hls  = null,
            MemorySettings ms       = null,
            MemoryBusSettings mbs   = null)
        {
            Logger.LogMessage(LoggerSystems.Console, "Creating CPU...");
            cpuSettings = cpuSettings ?? SettingsManager.GetSettings <CpuSettings>();
            settings    = settings ?? new RunnerSettings();
            hls         = hls ?? SettingsManager.GetSettings <HlCompilerSettings>();
            ms          = ms ?? SettingsManager.GetSettings <MemorySettings>();
            mbs         = mbs ?? SettingsManager.GetSettings <MemoryBusSettings>();

            ArgumentSyntaxParser.Parse(
                args.ToArray(),
                settings,
                hls,
                ms,
                mbs,
                cpuSettings
                );

            SettingsManager.SaveSettings(hls);
            SettingsManager.SaveSettings(ms);
            SettingsManager.SaveSettings(mbs);
            SettingsManager.SaveSettings(cpuSettings);

            if (settings.InputFiles == null)
            {
                Logger.LogMessage(LoggerSystems.Console, "No Files Specified");

                return(null);
            }

            MemoryBus bus = CreateBus(mbs);

            Cpu cpu = new Cpu(bus, cpuSettings.CpuResetAddr, cpuSettings.CpuIntAddr);

            return(cpu);
        }
Пример #17
0
        public void ConfigureRun(
            string assemblyLocation,
            IEnumerable <string> categories,
            IEnumerable <string> otherTestFixtures,
            IEnumerable <string> categoriesToRun,
            RunnerSettings runnerSettings)
        {
            if (_configured)
            {
                throw new InvalidOperationException("Need to at least wait until this run is complete..." + "\n"
                                                    + "Then we can talk, but for now, just create a new one");
            }

            _assemblyLocation  = assemblyLocation;
            _otherTestFixtures = otherTestFixtures;
            _categories        = categories.ToList();
            _categoriesToRun   = categoriesToRun.ToList();
            _runnerSettings    = runnerSettings;
            _configured        = true;
        }
        public void CalculateServiceName(RunnerSettings settings, string serviceNamePattern, string serviceDisplayNamePattern, out string serviceName, out string serviceDisplayName)
        {
            Trace.Entering();
            serviceName        = string.Empty;
            serviceDisplayName = string.Empty;

            if (string.IsNullOrEmpty(settings.RepoOrOrgName))
            {
                throw new InvalidOperationException($"Cannot find GitHub repository/organization name from server url: '{settings.ServerUrl}'");
            }

            // For the service name, replace any characters outside of the alpha-numeric set and ".", "_", "-" with "-"
            Regex  regex         = new Regex(@"[^0-9a-zA-Z._\-]");
            string repoOrOrgName = regex.Replace(settings.RepoOrOrgName, "-");

            serviceName = StringUtil.Format(serviceNamePattern, repoOrOrgName, settings.AgentName);

            if (serviceName.Length > 80)
            {
                Trace.Verbose($"Calculated service name is too long (> 80 chars). Trying again by calculating a shorter name.");

                int    exceededCharLength     = serviceName.Length - 80;
                string repoOrOrgNameSubstring = StringUtil.SubstringPrefix(repoOrOrgName, 45);

                exceededCharLength -= repoOrOrgName.Length - repoOrOrgNameSubstring.Length;

                string runnerNameSubstring = settings.AgentName;

                // Only trim runner name if it's really necessary
                if (exceededCharLength > 0)
                {
                    runnerNameSubstring = StringUtil.SubstringPrefix(settings.AgentName, settings.AgentName.Length - exceededCharLength);
                }

                serviceName = StringUtil.Format(serviceNamePattern, repoOrOrgNameSubstring, runnerNameSubstring);
            }

            serviceDisplayName = StringUtil.Format(serviceDisplayNamePattern, repoOrOrgName, settings.AgentName);

            Trace.Info($"Service name '{serviceName}' display name '{serviceDisplayName}' will be used for service configuration.");
        }
Пример #19
0
        public override void Initialize(IHostContext hostContext)
        {
            base.Initialize(hostContext);

            // get pool id from config
            var configurationStore = hostContext.GetService <IConfigurationStore>();

            _runnerSetting = configurationStore.GetSettings();
            _poolId        = _runnerSetting.PoolId;

            int channelTimeoutSeconds;

            if (!int.TryParse(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_CHANNEL_TIMEOUT") ?? string.Empty, out channelTimeoutSeconds))
            {
                channelTimeoutSeconds = 30;
            }

            // _channelTimeout should in range [30,  300] seconds
            _channelTimeout = TimeSpan.FromSeconds(Math.Min(Math.Max(channelTimeoutSeconds, 30), 300));
            Trace.Info($"Set runner/worker IPC timeout to {_channelTimeout.TotalSeconds} seconds.");
        }
Пример #20
0
        public IRunner Create(RunnerSettings runnerSettings, Assembly assembly, string categoriesList = null)
        {
            Func <Type, bool> filterTestFixtures = null;

            if (runnerSettings.Namespace != null)
            {
                filterTestFixtures = type => type.Namespace
                                     .IfNotNull(x =>
                                                x.StartsWith(runnerSettings.Namespace));
            }

            var categories = _categoryFinderService.FindCategories(assembly, filterTestFixtures);

            var other         = categories.Concat(new[] { "Long" });
            var otherFixtures = _categoryFinderService.FindTestFixturesExcludingCategories(assembly, other, filterTestFixtures).ToList();

            if (!categories.Any() && !otherFixtures.Any())
            {
                throw new InvalidOperationException("Cannot run if there are no tests.");
            }

            var categoriesToRun = categoriesList != null
                                      ? categoriesList.Split(',', ';', '\n', '\r')
                                  .Select(x => x.Trim())
                                  .Where(x => x.Length > 0)
                                      : new string[0];

            if (runnerSettings.RerunFailedCategories)
            {
                var erroredCategories = _resultsParser.GetErrorsCategories(runnerSettings.ResultsStatsFilepath);
                categoriesToRun = categoriesToRun.Concat(erroredCategories);
            }

            //return new ThreadRunner(_assembly.Location, _featureTypes, ObjectFactory.GetInstance<ILogger>(), _outputPath);
            //return new ProcessRunner(assembly.Location, categories, otherFixtures, categoriesToRun, ObjectFactory.GetInstance<ILogger>(), runnerSettings);
            //TODO: With this, this is no longer a factory...
            _runner.ConfigureRun(assembly.Location, categories, otherFixtures, categoriesToRun, runnerSettings);
            return(_runner);
        }
Пример #21
0
        public async Task <int> ExecuteCommand(CommandSettings command)
        {
            try
            {
                VssUtil.InitializeVssClientSettings(HostContext.UserAgent, HostContext.WebProxy);

                _inConfigStage = true;
                _completedCommand.Reset();
                _term.CancelKeyPress += CtrlCHandler;

                //register a SIGTERM handler
                HostContext.Unloading += Runner_Unloading;

                // TODO Unit test to cover this logic
                Trace.Info(nameof(ExecuteCommand));
                var configManager = HostContext.GetService <IConfigurationManager>();

                // command is not required, if no command it just starts if configured

                // TODO: Invalid config prints usage

                if (command.Help)
                {
                    PrintUsage(command);
                    return(Constants.Runner.ReturnCode.Success);
                }

                if (command.Version)
                {
                    _term.WriteLine(BuildConstants.RunnerPackage.Version);
                    return(Constants.Runner.ReturnCode.Success);
                }

                if (command.Commit)
                {
                    _term.WriteLine(BuildConstants.Source.CommitHash);
                    return(Constants.Runner.ReturnCode.Success);
                }

                // Configure runner prompt for args if not supplied
                // Unattended configure mode will not prompt for args if not supplied and error on any missing or invalid value.
                if (command.Configure)
                {
                    try
                    {
                        await configManager.ConfigureAsync(command);

                        return(Constants.Runner.ReturnCode.Success);
                    }
                    catch (Exception ex)
                    {
                        Trace.Error(ex);
                        _term.WriteError(ex.Message);
                        return(Constants.Runner.ReturnCode.TerminatedError);
                    }
                }

                // remove config files, remove service, and exit
                if (command.Remove)
                {
                    try
                    {
                        await configManager.UnconfigureAsync(command);

                        return(Constants.Runner.ReturnCode.Success);
                    }
                    catch (Exception ex)
                    {
                        Trace.Error(ex);
                        _term.WriteError(ex.Message);
                        return(Constants.Runner.ReturnCode.TerminatedError);
                    }
                }

                _inConfigStage = false;

                // warmup runner process (JIT/CLR)
                // In scenarios where the runner is single use (used and then thrown away), the system provisioning the runner can call `Runner.Listener --warmup` before the machine is made available to the pool for use.
                // this will optimizes the runner process startup time.
                if (command.Warmup)
                {
                    var binDir = HostContext.GetDirectory(WellKnownDirectory.Bin);
                    foreach (var assemblyFile in Directory.EnumerateFiles(binDir, "*.dll"))
                    {
                        try
                        {
                            Trace.Info($"Load assembly: {assemblyFile}.");
                            var assembly = Assembly.LoadFrom(assemblyFile);
                            var types    = assembly.GetTypes();
                            foreach (Type loadedType in types)
                            {
                                try
                                {
                                    Trace.Info($"Load methods: {loadedType.FullName}.");
                                    var methods = loadedType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
                                    foreach (var method in methods)
                                    {
                                        if (!method.IsAbstract && !method.ContainsGenericParameters)
                                        {
                                            Trace.Verbose($"Prepare method: {method.Name}.");
                                            RuntimeHelpers.PrepareMethod(method.MethodHandle);
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Trace.Error(ex);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Trace.Error(ex);
                        }
                    }

                    return(Constants.Runner.ReturnCode.Success);
                }

                RunnerSettings settings = configManager.LoadSettings();

                var  store = HostContext.GetService <IConfigurationStore>();
                bool configuredAsService = store.IsServiceConfigured();

                // Run runner
                if (command.Run) // this line is current break machine provisioner.
                {
                    // Error if runner not configured.
                    if (!configManager.IsConfigured())
                    {
                        _term.WriteError("Runner is not configured.");
                        PrintUsage(command);
                        return(Constants.Runner.ReturnCode.TerminatedError);
                    }

                    Trace.Verbose($"Configured as service: '{configuredAsService}'");

                    //Get the startup type of the runner i.e., autostartup, service, manual
                    StartupType startType;
                    var         startupTypeAsString = command.GetStartupType();
                    if (string.IsNullOrEmpty(startupTypeAsString) && configuredAsService)
                    {
                        // We need try our best to make the startup type accurate
                        // The problem is coming from runner autoupgrade, which result an old version service host binary but a newer version runner binary
                        // At that time the servicehost won't pass --startuptype to Runner.Listener while the runner is actually running as service.
                        // We will guess the startup type only when the runner is configured as service and the guess will based on whether STDOUT/STDERR/STDIN been redirect or not
                        Trace.Info($"Try determine runner startup type base on console redirects.");
                        startType = (Console.IsErrorRedirected && Console.IsInputRedirected && Console.IsOutputRedirected) ? StartupType.Service : StartupType.Manual;
                    }
                    else
                    {
                        if (!Enum.TryParse(startupTypeAsString, true, out startType))
                        {
                            Trace.Info($"Could not parse the argument value '{startupTypeAsString}' for StartupType. Defaulting to {StartupType.Manual}");
                            startType = StartupType.Manual;
                        }
                    }

                    Trace.Info($"Set runner startup type - {startType}");
                    HostContext.StartupType = startType;

                    // Run the runner interactively or as service
                    return(await RunAsync(settings, command.RunOnce));
                }
                else
                {
                    PrintUsage(command);
                    return(Constants.Runner.ReturnCode.Success);
                }
            }
            finally
            {
                _term.CancelKeyPress  -= CtrlCHandler;
                HostContext.Unloading -= Runner_Unloading;
                _completedCommand.Set();
            }
        }
Пример #22
0
        public async Task ConfigureAsync(CommandSettings command)
        {
            _term.WriteLine();
            _term.WriteLine("--------------------------------------------------------------------------------", ConsoleColor.White);
            _term.WriteLine("|        ____ _ _   _   _       _          _        _   _                      |", ConsoleColor.White);
            _term.WriteLine("|       / ___(_) |_| | | |_   _| |__      / \\   ___| |_(_) ___  _ __  ___      |", ConsoleColor.White);
            _term.WriteLine("|      | |  _| | __| |_| | | | | '_ \\    / _ \\ / __| __| |/ _ \\| '_ \\/ __|     |", ConsoleColor.White);
            _term.WriteLine("|      | |_| | | |_|  _  | |_| | |_) |  / ___ \\ (__| |_| | (_) | | | \\__ \\     |", ConsoleColor.White);
            _term.WriteLine("|       \\____|_|\\__|_| |_|\\__,_|_.__/  /_/   \\_\\___|\\__|_|\\___/|_| |_|___/     |", ConsoleColor.White);
            _term.WriteLine("|                                                                              |", ConsoleColor.White);
            _term.Write("|                       ", ConsoleColor.White);
            _term.Write("Self-hosted runner registration", ConsoleColor.Cyan);
            _term.WriteLine("                        |", ConsoleColor.White);
            _term.WriteLine("|                                                                              |", ConsoleColor.White);
            _term.WriteLine("--------------------------------------------------------------------------------", ConsoleColor.White);

            Trace.Info(nameof(ConfigureAsync));
            if (IsConfigured())
            {
                throw new InvalidOperationException("Cannot configure the runner because it is already configured. To reconfigure the runner, run 'config.cmd remove' or './config.sh remove' first.");
            }

            RunnerSettings runnerSettings = new RunnerSettings();

            bool isHostedServer = false;
            // Loop getting url and creds until you can connect
            ICredentialProvider credProvider = null;
            VssCredentials      creds        = null;

            _term.WriteSection("Authentication");
            while (true)
            {
                // Get the URL
                var inputUrl = command.GetUrl();
                if (!inputUrl.Contains("github.com", StringComparison.OrdinalIgnoreCase) &&
                    !inputUrl.Contains("github.localhost", StringComparison.OrdinalIgnoreCase))
                {
                    runnerSettings.ServerUrl = inputUrl;
                    // Get the credentials
                    credProvider = GetCredentialProvider(command, runnerSettings.ServerUrl);
                    creds        = credProvider.GetVssCredentials(HostContext);
                    Trace.Info("legacy vss cred retrieved");
                }
                else
                {
                    runnerSettings.GitHubUrl = inputUrl;
                    var githubToken             = command.GetRunnerRegisterToken();
                    GitHubAuthResult authResult = await GetTenantCredential(inputUrl, githubToken, Constants.RunnerEvent.Register);

                    runnerSettings.ServerUrl = authResult.TenantUrl;
                    creds = authResult.ToVssCredentials();
                    Trace.Info("cred retrieved via GitHub auth");
                }

                try
                {
                    // Determine the service deployment type based on connection data. (Hosted/OnPremises)
                    isHostedServer = await IsHostedServer(runnerSettings.ServerUrl, creds);

                    // Validate can connect.
                    await _runnerServer.ConnectAsync(new Uri(runnerSettings.ServerUrl), creds);

                    _term.WriteLine();
                    _term.WriteSuccessMessage("Connected to GitHub");

                    Trace.Info("Test Connection complete.");
                    break;
                }
                catch (Exception e) when(!command.Unattended)
                {
                    _term.WriteError(e);
                    _term.WriteError("Failed to connect.  Try again or ctrl-c to quit");
                    _term.WriteLine();
                }
            }

            // We want to use the native CSP of the platform for storage, so we use the RSACSP directly
            RSAParameters publicKey;
            var           keyManager = HostContext.GetService <IRSAKeyManager>();

            using (var rsa = keyManager.CreateKey())
            {
                publicKey = rsa.ExportParameters(false);
            }

            _term.WriteSection("Runner Registration");

            //Get all the agent pools, and select the first private pool
            List <TaskAgentPool> agentPools = await _runnerServer.GetAgentPoolsAsync();

            TaskAgentPool agentPool = agentPools?.Where(x => x.IsHosted == false).FirstOrDefault();

            if (agentPool == null)
            {
                throw new TaskAgentPoolNotFoundException($"Could not find any private pool. Contact support.");
            }
            else
            {
                Trace.Info("Found a private pool with id {1} and name {2}", agentPool.Id, agentPool.Name);
                runnerSettings.PoolId   = agentPool.Id;
                runnerSettings.PoolName = agentPool.Name;
            }

            TaskAgent agent;

            while (true)
            {
                runnerSettings.AgentName = command.GetRunnerName();

                _term.WriteLine();

                var agents = await _runnerServer.GetAgentsAsync(runnerSettings.PoolId, runnerSettings.AgentName);

                Trace.Verbose("Returns {0} agents", agents.Count);
                agent = agents.FirstOrDefault();
                if (agent != null)
                {
                    _term.WriteLine("A runner exists with the same name", ConsoleColor.Yellow);
                    if (command.GetReplace())
                    {
                        // Update existing agent with new PublicKey, agent version.
                        agent = UpdateExistingAgent(agent, publicKey);

                        try
                        {
                            agent = await _runnerServer.ReplaceAgentAsync(runnerSettings.PoolId, agent);

                            _term.WriteSuccessMessage("Successfully replaced the runner");
                            break;
                        }
                        catch (Exception e) when(!command.Unattended)
                        {
                            _term.WriteError(e);
                            _term.WriteError("Failed to replace the runner.  Try again or ctrl-c to quit");
                        }
                    }
                    else if (command.Unattended)
                    {
                        // if not replace and it is unattended config.
                        throw new TaskAgentExistsException($"Pool {runnerSettings.PoolId} already contains a runner with name {runnerSettings.AgentName}.");
                    }
                }
                else
                {
                    // Create a new agent.
                    agent = CreateNewAgent(runnerSettings.AgentName, publicKey);

                    try
                    {
                        agent = await _runnerServer.AddAgentAsync(runnerSettings.PoolId, agent);

                        _term.WriteSuccessMessage("Runner successfully added");
                        break;
                    }
                    catch (Exception e) when(!command.Unattended)
                    {
                        _term.WriteError(e);
                        _term.WriteError("Failed to add the runner. Try again or ctrl-c to quit");
                    }
                }
            }
            // Add Agent Id to settings
            runnerSettings.AgentId = agent.Id;

            // respect the serverUrl resolve by server.
            // in case of agent configured using collection url instead of account url.
            string agentServerUrl;

            if (agent.Properties.TryGetValidatedValue <string>("ServerUrl", out agentServerUrl) &&
                !string.IsNullOrEmpty(agentServerUrl))
            {
                Trace.Info($"Agent server url resolve by server: '{agentServerUrl}'.");

                // we need make sure the Schema/Host/Port component of the url remain the same.
                UriBuilder inputServerUrl          = new UriBuilder(runnerSettings.ServerUrl);
                UriBuilder serverReturnedServerUrl = new UriBuilder(agentServerUrl);
                if (Uri.Compare(inputServerUrl.Uri, serverReturnedServerUrl.Uri, UriComponents.SchemeAndServer, UriFormat.Unescaped, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    inputServerUrl.Path = serverReturnedServerUrl.Path;
                    Trace.Info($"Replace server returned url's scheme://host:port component with user input server url's scheme://host:port: '{inputServerUrl.Uri.AbsoluteUri}'.");
                    runnerSettings.ServerUrl = inputServerUrl.Uri.AbsoluteUri;
                }
                else
                {
                    runnerSettings.ServerUrl = agentServerUrl;
                }
            }

            // See if the server supports our OAuth key exchange for credentials
            if (agent.Authorization != null &&
                agent.Authorization.ClientId != Guid.Empty &&
                agent.Authorization.AuthorizationUrl != null)
            {
                UriBuilder configServerUrl         = new UriBuilder(runnerSettings.ServerUrl);
                UriBuilder oauthEndpointUrlBuilder = new UriBuilder(agent.Authorization.AuthorizationUrl);
                if (!isHostedServer && Uri.Compare(configServerUrl.Uri, oauthEndpointUrlBuilder.Uri, UriComponents.SchemeAndServer, UriFormat.Unescaped, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    oauthEndpointUrlBuilder.Scheme = configServerUrl.Scheme;
                    oauthEndpointUrlBuilder.Host   = configServerUrl.Host;
                    oauthEndpointUrlBuilder.Port   = configServerUrl.Port;
                    Trace.Info($"Set oauth endpoint url's scheme://host:port component to match runner configure url's scheme://host:port: '{oauthEndpointUrlBuilder.Uri.AbsoluteUri}'.");
                }

                var credentialData = new CredentialData
                {
                    Scheme = Constants.Configuration.OAuth,
                    Data   =
                    {
                        { "clientId",         agent.Authorization.ClientId.ToString("D")       },
                        { "authorizationUrl", agent.Authorization.AuthorizationUrl.AbsoluteUri },
                        { "oauthEndpointUrl", oauthEndpointUrlBuilder.Uri.AbsoluteUri          },
                    },
                };

                // Save the negotiated OAuth credential data
                _store.SaveCredential(credentialData);
            }
            else
            {
                throw new NotSupportedException("Message queue listen OAuth token.");
            }

            // Testing agent connection, detect any potential connection issue, like local clock skew that cause OAuth token expired.
            var            credMgr    = HostContext.GetService <ICredentialManager>();
            VssCredentials credential = credMgr.LoadCredentials();

            try
            {
                await _runnerServer.ConnectAsync(new Uri(runnerSettings.ServerUrl), credential);

                // ConnectAsync() hits _apis/connectionData which is an anonymous endpoint
                // Need to hit an authenticate endpoint to trigger OAuth token exchange.
                await _runnerServer.GetAgentPoolsAsync();

                _term.WriteSuccessMessage("Runner connection is good");
            }
            catch (VssOAuthTokenRequestException ex) when(ex.Message.Contains("Current server time is"))
            {
                // there are two exception messages server send that indicate clock skew.
                // 1. The bearer token expired on {jwt.ValidTo}. Current server time is {DateTime.UtcNow}.
                // 2. The bearer token is not valid until {jwt.ValidFrom}. Current server time is {DateTime.UtcNow}.
                Trace.Error("Catch exception during test agent connection.");
                Trace.Error(ex);
                throw new Exception("The local machine's clock may be out of sync with the server time by more than five minutes. Please sync your clock with your domain or internet time and try again.");
            }

            _term.WriteSection("Runner settings");

            // We will Combine() what's stored with root.  Defaults to string a relative path
            runnerSettings.WorkFolder = command.GetWork();

            runnerSettings.MonitorSocketAddress = command.GetMonitorSocketAddress();

            _store.SaveSettings(runnerSettings);

            _term.WriteLine();
            _term.WriteSuccessMessage("Settings Saved.");
            _term.WriteLine();

#if OS_WINDOWS
            // config windows service
            bool runAsService = command.GetRunAsService();
            if (runAsService)
            {
                Trace.Info("Configuring to run the agent as service");
                var serviceControlManager = HostContext.GetService <IWindowsServiceControlManager>();
                serviceControlManager.ConfigureService(runnerSettings, command);
            }
#elif OS_LINUX || OS_OSX
            // generate service config script for OSX and Linux, GenerateScripts() will no-opt on windows.
            var serviceControlManager = HostContext.GetService <ILinuxServiceControlManager>();
            serviceControlManager.GenerateScripts(runnerSettings);
#endif
        }
Пример #23
0
        public async Task UnconfigureAsync(CommandSettings command)
        {
            string currentAction = string.Empty;

            _term.WriteSection("Runner removal");

            try
            {
                //stop, uninstall service and remove service config file
                if (_store.IsServiceConfigured())
                {
                    currentAction = "Removing service";
                    _term.WriteLine(currentAction);
#if OS_WINDOWS
                    var serviceControlManager = HostContext.GetService <IWindowsServiceControlManager>();
                    serviceControlManager.UnconfigureService();

                    _term.WriteLine();
                    _term.WriteSuccessMessage("Runner service removed");
#elif OS_LINUX
                    // unconfig system D service first
                    throw new Exception("Unconfigure service first");
#elif OS_OSX
                    // unconfig osx service first
                    throw new Exception("Unconfigure service first");
#endif
                }

                //delete agent from the server
                currentAction = "Removing runner from the server";
                bool isConfigured   = _store.IsConfigured();
                bool hasCredentials = _store.HasCredentials();
                if (isConfigured && hasCredentials)
                {
                    RunnerSettings settings          = _store.GetSettings();
                    var            credentialManager = HostContext.GetService <ICredentialManager>();

                    // Get the credentials
                    VssCredentials creds = null;
                    if (string.IsNullOrEmpty(settings.GitHubUrl))
                    {
                        var credProvider = GetCredentialProvider(command, settings.ServerUrl);
                        creds = credProvider.GetVssCredentials(HostContext);
                        Trace.Info("legacy vss cred retrieved");
                    }
                    else
                    {
                        var githubToken             = command.GetRunnerDeletionToken();
                        GitHubAuthResult authResult = await GetTenantCredential(settings.GitHubUrl, githubToken, Constants.RunnerEvent.Remove);

                        creds = authResult.ToVssCredentials();
                        Trace.Info("cred retrieved via GitHub auth");
                    }

                    // Determine the service deployment type based on connection data. (Hosted/OnPremises)
                    bool isHostedServer = await IsHostedServer(settings.ServerUrl, creds);

                    await _runnerServer.ConnectAsync(new Uri(settings.ServerUrl), creds);

                    var agents = await _runnerServer.GetAgentsAsync(settings.PoolId, settings.AgentName);

                    Trace.Verbose("Returns {0} agents", agents.Count);
                    TaskAgent agent = agents.FirstOrDefault();
                    if (agent == null)
                    {
                        _term.WriteLine("Does not exist. Skipping " + currentAction);
                    }
                    else
                    {
                        await _runnerServer.DeleteAgentAsync(settings.PoolId, settings.AgentId);

                        _term.WriteLine();
                        _term.WriteSuccessMessage("Runner removed successfully");
                    }
                }
                else
                {
                    _term.WriteLine("Cannot connect to server, because config files are missing. Skipping removing runner from the server.");
                }

                //delete credential config files
                currentAction = "Removing .credentials";
                if (hasCredentials)
                {
                    _store.DeleteCredential();
                    var keyManager = HostContext.GetService <IRSAKeyManager>();
                    keyManager.DeleteKey();
                    _term.WriteSuccessMessage("Removed .credentials");
                }
                else
                {
                    _term.WriteLine("Does not exist. Skipping " + currentAction);
                }

                //delete settings config file
                currentAction = "Removing .runner";
                if (isConfigured)
                {
                    _store.DeleteSettings();
                    _term.WriteSuccessMessage("Removed .runner");
                }
                else
                {
                    _term.WriteLine("Does not exist. Skipping " + currentAction);
                }
            }
            catch (Exception)
            {
                _term.WriteError("Failed: " + currentAction);
                throw;
            }

            _term.WriteLine();
        }
Пример #24
0
        public async Task <Boolean> CreateSessionAsync(CancellationToken token)
        {
            Trace.Entering();

            // Settings
            var configManager = HostContext.GetService <IConfigurationManager>();

            _settings = configManager.LoadSettings();
            var serverUrl = _settings.ServerUrl;

            Trace.Info(_settings);

            // Create connection.
            Trace.Info("Loading Credentials");
            var            credMgr = HostContext.GetService <ICredentialManager>();
            VssCredentials creds   = credMgr.LoadCredentials();

            var agent = new TaskAgentReference
            {
                Id            = _settings.AgentId,
                Name          = _settings.AgentName,
                Version       = BuildConstants.RunnerPackage.Version,
                OSDescription = RuntimeInformation.OSDescription,
            };
            string sessionName      = $"{Environment.MachineName ?? "RUNNER"}";
            var    taskAgentSession = new TaskAgentSession(sessionName, agent);

            string errorMessage      = string.Empty;
            bool   encounteringError = false;

            while (true)
            {
                token.ThrowIfCancellationRequested();
                Trace.Info($"Attempt to create session.");
                try
                {
                    Trace.Info("Connecting to the Runner Server...");
                    await _runnerServer.ConnectAsync(new Uri(serverUrl), creds);

                    Trace.Info("VssConnection created");

                    _term.WriteLine();
                    _term.WriteSuccessMessage("Connected to GitHub");
                    _term.WriteLine();

                    _session = await _runnerServer.CreateAgentSessionAsync(
                        _settings.PoolId,
                        taskAgentSession,
                        token);

                    Trace.Info($"Session created.");
                    if (encounteringError)
                    {
                        _term.WriteLine($"{DateTime.UtcNow:u}: Runner reconnected.");
                        _sessionCreationExceptionTracker.Clear();
                        encounteringError = false;
                    }

                    return(true);
                }
                catch (OperationCanceledException) when(token.IsCancellationRequested)
                {
                    Trace.Info("Session creation has been cancelled.");
                    throw;
                }
                catch (TaskAgentAccessTokenExpiredException)
                {
                    Trace.Info("Runner OAuth token has been revoked. Session creation failed.");
                    throw;
                }
                catch (Exception ex)
                {
                    Trace.Error("Catch exception during create session.");
                    Trace.Error(ex);

                    if (ex is VssOAuthTokenRequestException && creds.Federated is VssOAuthCredential vssOAuthCred)
                    {
                        // Check whether we get 401 because the runner registration already removed by the service.
                        // If the runner registration get deleted, we can't exchange oauth token.
                        Trace.Error("Test oauth app registration.");
                        var oauthTokenProvider = new VssOAuthTokenProvider(vssOAuthCred, new Uri(serverUrl));
                        var authError          = await oauthTokenProvider.ValidateCredentialAsync(token);

                        if (string.Equals(authError, "invalid_client", StringComparison.OrdinalIgnoreCase))
                        {
                            _term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure.");
                            return(false);
                        }
                    }

                    if (!IsSessionCreationExceptionRetriable(ex))
                    {
                        _term.WriteError($"Failed to create session. {ex.Message}");
                        return(false);
                    }

                    if (!encounteringError) //print the message only on the first error
                    {
                        _term.WriteError($"{DateTime.UtcNow:u}: Runner connect error: {ex.Message}. Retrying until reconnected.");
                        encounteringError = true;
                    }

                    Trace.Info("Sleeping for {0} seconds before retrying.", _sessionCreationRetryInterval.TotalSeconds);
                    await HostContext.Delay(_sessionCreationRetryInterval, token);
                }
            }
        }
Пример #25
0
        private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
        {
            var hc = new TestHostContext(this, testName);

            _jobEc                = new Runner.Worker.ExecutionContext();
            _actionManager        = new Mock <IActionManager>();
            _jobServerQueue       = new Mock <IJobServerQueue>();
            _config               = new Mock <IConfigurationStore>();
            _logger               = new Mock <IPagingLogger>();
            _containerProvider    = new Mock <IContainerOperationProvider>();
            _diagnosticLogManager = new Mock <IDiagnosticLogManager>();
            _directoryManager     = new Mock <IPipelineDirectoryManager>();
            _directoryManager.Setup(x => x.PrepareDirectory(It.IsAny <IExecutionContext>(), It.IsAny <Pipelines.WorkspaceOptions>()))
            .Returns(new TrackingConfig()
            {
                PipelineDirectory = "runner", WorkspaceDirectory = "runner/runner"
            });

            IActionRunner step1 = new ActionRunner();
            IActionRunner step2 = new ActionRunner();
            IActionRunner step3 = new ActionRunner();
            IActionRunner step4 = new ActionRunner();
            IActionRunner step5 = new ActionRunner();

            _logger.Setup(x => x.Setup(It.IsAny <Guid>(), It.IsAny <Guid>()));
            var settings = new RunnerSettings
            {
                AgentId    = 1,
                AgentName  = "runner",
                ServerUrl  = "https://pipelines.actions.githubusercontent.com/abcd",
                WorkFolder = "_work",
            };

            _config.Setup(x => x.GetSettings())
            .Returns(settings);

            if (_tokenSource != null)
            {
                _tokenSource.Dispose();
                _tokenSource = null;
            }

            _tokenSource = new CancellationTokenSource();
            TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
            TimelineReference timeline          = new Timeline(Guid.NewGuid());

            List <Pipelines.ActionStep> steps = new List <Pipelines.ActionStep>()
            {
                new Pipelines.ActionStep()
                {
                    Id          = Guid.NewGuid(),
                    DisplayName = "action1",
                },
                new Pipelines.ActionStep()
                {
                    Id          = Guid.NewGuid(),
                    DisplayName = "action2",
                },
                new Pipelines.ActionStep()
                {
                    Id          = Guid.NewGuid(),
                    DisplayName = "action3",
                },
                new Pipelines.ActionStep()
                {
                    Id          = Guid.NewGuid(),
                    DisplayName = "action4",
                },
                new Pipelines.ActionStep()
                {
                    Id          = Guid.NewGuid(),
                    DisplayName = "action5",
                }
            };

            Guid jobId = Guid.NewGuid();

            _message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary <string, VariableValue>(), new List <MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null, null);
            GitHubContext github = new GitHubContext();

            github["repository"]    = new Pipelines.ContextData.StringContextData("actions/runner");
            github["secret_source"] = new Pipelines.ContextData.StringContextData("Actions");
            _message.ContextData.Add("github", github);

            hc.SetSingleton(_actionManager.Object);
            hc.SetSingleton(_config.Object);
            hc.SetSingleton(_jobServerQueue.Object);
            hc.SetSingleton(_containerProvider.Object);
            hc.SetSingleton(_directoryManager.Object);
            hc.SetSingleton(_diagnosticLogManager.Object);
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // JobExecutionContext
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // Initial Job
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // step1
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // step2
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // step3
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // step4
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // step5
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // prepare1
            hc.EnqueueInstance <IPagingLogger>(_logger.Object); // prepare2

            hc.EnqueueInstance <IActionRunner>(step1);
            hc.EnqueueInstance <IActionRunner>(step2);
            hc.EnqueueInstance <IActionRunner>(step3);
            hc.EnqueueInstance <IActionRunner>(step4);
            hc.EnqueueInstance <IActionRunner>(step5);

            _jobEc.Initialize(hc);
            _jobEc.InitializeJob(_message, _tokenSource.Token);
            return(hc);
        }
Пример #26
0
 public ReflectionDiscovery(IBenchmarkOutput output, IBenchmarkAssertionRunner benchmarkAssertions, RunnerSettings settings)
 {
     Output = _reflectionOutput = output;
     BenchmarkAssertions = benchmarkAssertions;
     RunnerSettings = settings;
     if(RunnerSettings.TracingEnabled)
         Trace = new BenchmarkOutputTrace(Output);
     else
         Trace = NoOpBenchmarkTrace.Instance;
 }
Пример #27
0
        private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
        {
            var hc = new TestHostContext(this, testName);

            _jobEc                = new Runner.Worker.ExecutionContext();
            _config               = new Mock <IConfigurationStore>();
            _extensions           = new Mock <IExtensionManager>();
            _jobExtension         = new Mock <IJobExtension>();
            _jobServer            = new Mock <IJobServer>();
            _jobServerQueue       = new Mock <IJobServerQueue>();
            _stepRunner           = new Mock <IStepsRunner>();
            _logger               = new Mock <IPagingLogger>();
            _temp                 = new Mock <ITempDirectoryManager>();
            _diagnosticLogManager = new Mock <IDiagnosticLogManager>();

            if (_tokenSource != null)
            {
                _tokenSource.Dispose();
                _tokenSource = null;
            }

            _tokenSource = new CancellationTokenSource();
            var expressionManager = new ExpressionManager();

            expressionManager.Initialize(hc);
            hc.SetSingleton <IExpressionManager>(expressionManager);

            _jobRunner = new JobRunner();
            _jobRunner.Initialize(hc);

            TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
            TimelineReference timeline          = new Timeline(Guid.NewGuid());
            Guid jobId = Guid.NewGuid();

            _message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, testName, testName, null, null, null, new Dictionary <string, VariableValue>(), new List <MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List <Pipelines.ActionStep>(), null, null);
            _message.Variables[Constants.Variables.System.Culture] = "en-US";
            _message.Resources.Endpoints.Add(new ServiceEndpoint()
            {
                Name          = WellKnownServiceEndpointNames.SystemVssConnection,
                Url           = new Uri("https://pipelines.actions.githubusercontent.com"),
                Authorization = new EndpointAuthorization()
                {
                    Scheme     = "Test",
                    Parameters =
                    {
                        { "AccessToken", "token" }
                    }
                },
            });

            _message.Resources.Repositories.Add(new Pipelines.RepositoryResource()
            {
                Alias   = Pipelines.PipelineConstants.SelfAlias,
                Id      = "github",
                Version = "sha1"
            });
            _message.ContextData.Add("github", new Pipelines.ContextData.DictionaryContextData());

            _initResult.Clear();

            _jobExtension.Setup(x => x.InitializeJob(It.IsAny <IExecutionContext>(), It.IsAny <Pipelines.AgentJobRequestMessage>())).
            Returns(Task.FromResult(_initResult));

            var settings = new RunnerSettings
            {
                AgentId    = 1,
                AgentName  = "agent1",
                ServerUrl  = "https://pipelines.actions.githubusercontent.com",
                WorkFolder = "_work",
            };

            _config.Setup(x => x.GetSettings())
            .Returns(settings);

            _logger.Setup(x => x.Setup(It.IsAny <Guid>(), It.IsAny <Guid>()));

            hc.SetSingleton(_config.Object);
            hc.SetSingleton(_jobServer.Object);
            hc.SetSingleton(_jobServerQueue.Object);
            hc.SetSingleton(_stepRunner.Object);
            hc.SetSingleton(_extensions.Object);
            hc.SetSingleton(_temp.Object);
            hc.SetSingleton(_diagnosticLogManager.Object);
            hc.EnqueueInstance <IExecutionContext>(_jobEc);
            hc.EnqueueInstance <IPagingLogger>(_logger.Object);
            hc.EnqueueInstance <IJobExtension>(_jobExtension.Object);
            return(hc);
        }
Пример #28
0
        //create worker manager, create message listener and start listening to the queue
        private async Task <int> RunAsync(RunnerSettings settings, bool runOnce = false)
        {
            try
            {
                Trace.Info(nameof(RunAsync));
                _listener = HostContext.GetService <IMessageListener>();
                if (!await _listener.CreateSessionAsync(HostContext.RunnerShutdownToken))
                {
                    return(Constants.Runner.ReturnCode.TerminatedError);
                }

                HostContext.WritePerfCounter("SessionCreated");
                _term.WriteLine($"{DateTime.UtcNow:u}: Listening for Jobs");

                IJobDispatcher          jobDispatcher = null;
                CancellationTokenSource messageQueueLoopTokenSource = CancellationTokenSource.CreateLinkedTokenSource(HostContext.RunnerShutdownToken);
                try
                {
                    var notification = HostContext.GetService <IJobNotification>();

                    notification.StartClient(settings.MonitorSocketAddress);

                    bool        autoUpdateInProgress = false;
                    Task <bool> selfUpdateTask       = null;
                    bool        runOnceJobReceived   = false;
                    jobDispatcher = HostContext.CreateService <IJobDispatcher>();

                    while (!HostContext.RunnerShutdownToken.IsCancellationRequested)
                    {
                        TaskAgentMessage message             = null;
                        bool             skipMessageDeletion = false;
                        try
                        {
                            Task <TaskAgentMessage> getNextMessage = _listener.GetNextMessageAsync(messageQueueLoopTokenSource.Token);
                            if (autoUpdateInProgress)
                            {
                                Trace.Verbose("Auto update task running at backend, waiting for getNextMessage or selfUpdateTask to finish.");
                                Task completeTask = await Task.WhenAny(getNextMessage, selfUpdateTask);

                                if (completeTask == selfUpdateTask)
                                {
                                    autoUpdateInProgress = false;
                                    if (await selfUpdateTask)
                                    {
                                        Trace.Info("Auto update task finished at backend, an runner update is ready to apply exit the current runner instance.");
                                        Trace.Info("Stop message queue looping.");
                                        messageQueueLoopTokenSource.Cancel();
                                        try
                                        {
                                            await getNextMessage;
                                        }
                                        catch (Exception ex)
                                        {
                                            Trace.Info($"Ignore any exception after cancel message loop. {ex}");
                                        }

                                        if (runOnce)
                                        {
                                            return(Constants.Runner.ReturnCode.RunOnceRunnerUpdating);
                                        }
                                        else
                                        {
                                            return(Constants.Runner.ReturnCode.RunnerUpdating);
                                        }
                                    }
                                    else
                                    {
                                        Trace.Info("Auto update task finished at backend, there is no available runner update needs to apply, continue message queue looping.");
                                    }
                                }
                            }

                            if (runOnceJobReceived)
                            {
                                Trace.Verbose("One time used runner has start running its job, waiting for getNextMessage or the job to finish.");
                                Task completeTask = await Task.WhenAny(getNextMessage, jobDispatcher.RunOnceJobCompleted.Task);

                                if (completeTask == jobDispatcher.RunOnceJobCompleted.Task)
                                {
                                    Trace.Info("Job has finished at backend, the runner will exit since it is running under onetime use mode.");
                                    Trace.Info("Stop message queue looping.");
                                    messageQueueLoopTokenSource.Cancel();
                                    try
                                    {
                                        await getNextMessage;
                                    }
                                    catch (Exception ex)
                                    {
                                        Trace.Info($"Ignore any exception after cancel message loop. {ex}");
                                    }

                                    return(Constants.Runner.ReturnCode.Success);
                                }
                            }

                            message = await getNextMessage; //get next message
                            HostContext.WritePerfCounter($"MessageReceived_{message.MessageType}");
                            if (string.Equals(message.MessageType, AgentRefreshMessage.MessageType, StringComparison.OrdinalIgnoreCase))
                            {
                                if (autoUpdateInProgress == false)
                                {
                                    autoUpdateInProgress = true;
                                    var runnerUpdateMessage = JsonUtility.FromString <AgentRefreshMessage>(message.Body);
                                    var selfUpdater         = HostContext.GetService <ISelfUpdater>();
                                    selfUpdateTask = selfUpdater.SelfUpdate(runnerUpdateMessage, jobDispatcher, !runOnce && HostContext.StartupType != StartupType.Service, HostContext.RunnerShutdownToken);
                                    Trace.Info("Refresh message received, kick-off selfupdate background process.");
                                }
                                else
                                {
                                    Trace.Info("Refresh message received, skip autoupdate since a previous autoupdate is already running.");
                                }
                            }
                            else if (string.Equals(message.MessageType, JobRequestMessageTypes.PipelineAgentJobRequest, StringComparison.OrdinalIgnoreCase))
                            {
                                if (autoUpdateInProgress || runOnceJobReceived)
                                {
                                    skipMessageDeletion = true;
                                    Trace.Info($"Skip message deletion for job request message '{message.MessageId}'.");
                                }
                                else
                                {
                                    var jobMessage = StringUtil.ConvertFromJson <Pipelines.AgentJobRequestMessage>(message.Body);
                                    jobDispatcher.Run(jobMessage, runOnce);
                                    if (runOnce)
                                    {
                                        Trace.Info("One time used runner received job message.");
                                        runOnceJobReceived = true;
                                    }
                                }
                            }
                            else if (string.Equals(message.MessageType, JobCancelMessage.MessageType, StringComparison.OrdinalIgnoreCase))
                            {
                                var  cancelJobMessage = JsonUtility.FromString <JobCancelMessage>(message.Body);
                                bool jobCancelled     = jobDispatcher.Cancel(cancelJobMessage);
                                skipMessageDeletion = (autoUpdateInProgress || runOnceJobReceived) && !jobCancelled;

                                if (skipMessageDeletion)
                                {
                                    Trace.Info($"Skip message deletion for cancellation message '{message.MessageId}'.");
                                }
                            }
                            else
                            {
                                Trace.Error($"Received message {message.MessageId} with unsupported message type {message.MessageType}.");
                            }
                        }
                        finally
                        {
                            if (!skipMessageDeletion && message != null)
                            {
                                try
                                {
                                    await _listener.DeleteMessageAsync(message);
                                }
                                catch (Exception ex)
                                {
                                    Trace.Error($"Catch exception during delete message from message queue. message id: {message.MessageId}");
                                    Trace.Error(ex);
                                }
                                finally
                                {
                                    message = null;
                                }
                            }
                        }
                    }
                }
                finally
                {
                    if (jobDispatcher != null)
                    {
                        await jobDispatcher.ShutdownAsync();
                    }

                    //TODO: make sure we don't mask more important exception
                    await _listener.DeleteSessionAsync();

                    messageQueueLoopTokenSource.Dispose();
                }
            }
            catch (TaskAgentAccessTokenExpiredException)
            {
                Trace.Info("Runner OAuth token has been revoked. Shutting down.");
            }

            return(Constants.Runner.ReturnCode.Success);
        }
Пример #29
0
        public async Task <Boolean> CreateSessionAsync(CancellationToken token)
        {
            Trace.Entering();

            // Settings
            var configManager = HostContext.GetService <IConfigurationManager>();

            _settings = configManager.LoadSettings();
            var serverUrl = _settings.ServerUrl;

            Trace.Info(_settings);

            // Create connection.
            Trace.Info("Loading Credentials");
            var            credMgr = HostContext.GetService <ICredentialManager>();
            VssCredentials creds   = credMgr.LoadCredentials();

            var agent = new TaskAgentReference
            {
                Id            = _settings.AgentId,
                Name          = _settings.AgentName,
                Version       = BuildConstants.RunnerPackage.Version,
                OSDescription = RuntimeInformation.OSDescription,
            };
            string sessionName      = $"{Environment.MachineName ?? "RUNNER"}";
            var    taskAgentSession = new TaskAgentSession(sessionName, agent);

            string errorMessage      = string.Empty;
            bool   encounteringError = false;

            while (true)
            {
                token.ThrowIfCancellationRequested();
                Trace.Info($"Attempt to create session.");
                try
                {
                    Trace.Info("Connecting to the Runner Server...");
                    await _runnerServer.ConnectAsync(new Uri(serverUrl), creds);

                    Trace.Info("VssConnection created");

                    _term.WriteLine();
                    _term.WriteSuccessMessage("Connected to GitHub");
                    _term.WriteLine();

                    _session = await _runnerServer.CreateAgentSessionAsync(
                        _settings.PoolId,
                        taskAgentSession,
                        token);

                    Trace.Info($"Session created.");
                    if (encounteringError)
                    {
                        _term.WriteLine($"{DateTime.UtcNow:u}: Runner reconnected.");
                        _sessionCreationExceptionTracker.Clear();
                        encounteringError = false;
                    }

                    return(true);
                }
                catch (OperationCanceledException) when(token.IsCancellationRequested)
                {
                    Trace.Info("Session creation has been cancelled.");
                    throw;
                }
                catch (TaskAgentAccessTokenExpiredException)
                {
                    Trace.Info("Runner OAuth token has been revoked. Session creation failed.");
                    throw;
                }
                catch (Exception ex)
                {
                    Trace.Error("Catch exception during create session.");
                    Trace.Error(ex);

                    if (!IsSessionCreationExceptionRetriable(ex))
                    {
                        _term.WriteError($"Failed to create session. {ex.Message}");
                        return(false);
                    }

                    if (!encounteringError) //print the message only on the first error
                    {
                        _term.WriteError($"{DateTime.UtcNow:u}: Runner connect error: {ex.Message}. Retrying until reconnected.");
                        encounteringError = true;
                    }

                    Trace.Info("Sleeping for {0} seconds before retrying.", _sessionCreationRetryInterval.TotalSeconds);
                    await HostContext.Delay(_sessionCreationRetryInterval, token);
                }
            }
        }
Пример #30
0
        public ConfigurationManagerL0()
        {
            _runnerServer   = new Mock <IRunnerServer>();
            _locationServer = new Mock <ILocationServer>();
            _credMgr        = new Mock <ICredentialManager>();
            _promptManager  = new Mock <IPromptManager>();
            _store          = new Mock <IConfigurationStore>();
            _extnMgr        = new Mock <IExtensionManager>();
            _rsaKeyManager  = new Mock <IRSAKeyManager>();

#if OS_WINDOWS
            _serviceControlManager = new Mock <IWindowsServiceControlManager>();
#endif

#if !OS_WINDOWS
            _serviceControlManager = new Mock <ILinuxServiceControlManager>();
#endif

            var expectedAgent = new TaskAgent(_expectedAgentName)
            {
                Id = 1
            };
            expectedAgent.Authorization = new TaskAgentAuthorization
            {
                ClientId         = Guid.NewGuid(),
                AuthorizationUrl = new Uri("http://localhost:8080/pipelines"),
            };

            var connectionData = new ConnectionData()
            {
                InstanceId     = Guid.NewGuid(),
                DeploymentType = DeploymentFlags.Hosted,
                DeploymentId   = Guid.NewGuid()
            };
            _runnerServer.Setup(x => x.ConnectAsync(It.IsAny <Uri>(), It.IsAny <VssCredentials>())).Returns(Task.FromResult <object>(null));
            _locationServer.Setup(x => x.ConnectAsync(It.IsAny <VssConnection>())).Returns(Task.FromResult <object>(null));
            _locationServer.Setup(x => x.GetConnectionDataAsync()).Returns(Task.FromResult <ConnectionData>(connectionData));

            _store.Setup(x => x.IsConfigured()).Returns(false);
            _store.Setup(x => x.HasCredentials()).Returns(false);
            _store.Setup(x => x.GetSettings()).Returns(() => _configMgrAgentSettings);

            _store.Setup(x => x.SaveSettings(It.IsAny <RunnerSettings>()))
            .Callback((RunnerSettings settings) =>
            {
                _configMgrAgentSettings = settings;
            });

            _credMgr.Setup(x => x.GetCredentialProvider(It.IsAny <string>())).Returns(new TestRunnerCredential());

#if !OS_WINDOWS
            _serviceControlManager.Setup(x => x.GenerateScripts(It.IsAny <RunnerSettings>()));
#endif

            var expectedPools = new List <TaskAgentPool>()
            {
                new TaskAgentPool(_expectedPoolName)
                {
                    Id = _expectedPoolId
                }
            };
            _runnerServer.Setup(x => x.GetAgentPoolsAsync(It.IsAny <string>(), It.IsAny <TaskAgentPoolType>())).Returns(Task.FromResult(expectedPools));

            var expectedAgents = new List <TaskAgent>();
            _runnerServer.Setup(x => x.GetAgentsAsync(It.IsAny <int>(), It.IsAny <string>())).Returns(Task.FromResult(expectedAgents));

            _runnerServer.Setup(x => x.AddAgentAsync(It.IsAny <int>(), It.IsAny <TaskAgent>())).Returns(Task.FromResult(expectedAgent));
            _runnerServer.Setup(x => x.ReplaceAgentAsync(It.IsAny <int>(), It.IsAny <TaskAgent>())).Returns(Task.FromResult(expectedAgent));

            rsa = new RSACryptoServiceProvider(2048);

            _rsaKeyManager.Setup(x => x.CreateKey()).Returns(rsa);
        }
Пример #31
0
        public async Task <Boolean> CreateSessionAsync(CancellationToken token)
        {
            Trace.Entering();

            // Settings
            var configManager = HostContext.GetService <IConfigurationManager>();

            _settings = configManager.LoadSettings();
            var serverUrl = _settings.ServerUrl;

            Trace.Info(_settings);

            // Create connection.
            Trace.Info("Loading Credentials");
            _useMigratedCredentials = !StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_SPSAUTHURL"));
            VssCredentials creds = _credMgr.LoadCredentials(_useMigratedCredentials);

            var agent = new TaskAgentReference
            {
                Id            = _settings.AgentId,
                Name          = _settings.AgentName,
                Version       = BuildConstants.RunnerPackage.Version,
                OSDescription = RuntimeInformation.OSDescription,
            };
            string sessionName      = $"{Environment.MachineName ?? "RUNNER"}";
            var    taskAgentSession = new TaskAgentSession(sessionName, agent);

            string errorMessage      = string.Empty;
            bool   encounteringError = false;

            var originalCreds = _configStore.GetCredentials();
            var migratedCreds = _configStore.GetMigratedCredentials();

            if (migratedCreds == null)
            {
                _useMigratedCredentials = false;
                if (originalCreds.Scheme == Constants.Configuration.OAuth)
                {
                    _needToCheckAuthorizationUrlUpdate = true;
                }
            }

            while (true)
            {
                token.ThrowIfCancellationRequested();
                Trace.Info($"Attempt to create session.");
                try
                {
                    Trace.Info("Connecting to the Runner Server...");
                    await _runnerServer.ConnectAsync(new Uri(serverUrl), creds);

                    Trace.Info("VssConnection created");

                    _term.WriteLine();
                    _term.WriteSuccessMessage("Connected to GitHub");
                    _term.WriteLine();

                    _session = await _runnerServer.CreateAgentSessionAsync(
                        _settings.PoolId,
                        taskAgentSession,
                        token);

                    Trace.Info($"Session created.");
                    if (encounteringError)
                    {
                        _term.WriteLine($"{DateTime.UtcNow:u}: Runner reconnected.");
                        _sessionCreationExceptionTracker.Clear();
                        encounteringError = false;
                    }

                    if (_needToCheckAuthorizationUrlUpdate)
                    {
                        // start background task try to get new authorization url
                        _authorizationUrlMigrationBackgroundTask = GetNewOAuthAuthorizationSetting(token);
                    }

                    return(true);
                }
                catch (OperationCanceledException) when(token.IsCancellationRequested)
                {
                    Trace.Info("Session creation has been cancelled.");
                    throw;
                }
                catch (TaskAgentAccessTokenExpiredException)
                {
                    Trace.Info("Runner OAuth token has been revoked. Session creation failed.");
                    throw;
                }
                catch (Exception ex)
                {
                    Trace.Error("Catch exception during create session.");
                    Trace.Error(ex);

                    if (!IsSessionCreationExceptionRetriable(ex))
                    {
                        if (_useMigratedCredentials)
                        {
                            // migrated credentials might cause lose permission during permission check,
                            // we will force to use original credential and try again
                            _useMigratedCredentials = false;
                            var reattemptBackoff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromHours(24), TimeSpan.FromHours(36));
                            _authorizationUrlRollbackReattemptDelayBackgroundTask = HostContext.Delay(reattemptBackoff, token); // retry migrated creds in 24-36 hours.
                            creds = _credMgr.LoadCredentials(false);
                            Trace.Error("Fallback to original credentials and try again.");
                        }
                        else
                        {
                            _term.WriteError($"Failed to create session. {ex.Message}");
                            return(false);
                        }
                    }

                    if (!encounteringError) //print the message only on the first error
                    {
                        _term.WriteError($"{DateTime.UtcNow:u}: Runner connect error: {ex.Message}. Retrying until reconnected.");
                        encounteringError = true;
                    }

                    Trace.Info("Sleeping for {0} seconds before retrying.", _sessionCreationRetryInterval.TotalSeconds);
                    await HostContext.Delay(_sessionCreationRetryInterval, token);
                }
            }
        }