예제 #1
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);
                }
            }
        }
예제 #2
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 (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))
                    {
                        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);
                }
            }
        }