Beispiel #1
0
 public RunController(IXxlJobServicesProvider <IXxlJobExecutorHandler> handlerProvider,
                      ILogger <RunController> logger,
                      IJobDispatcher dispatcher)
 {
     _logger     = logger;
     _dispatcher = dispatcher;
 }
Beispiel #2
0
        public async Task <bool> SelfUpdate(AgentRefreshMessage updateMessage, IJobDispatcher jobDispatcher, bool restartInteractiveRunner, CancellationToken token)
        {
            Busy = true;
            try
            {
                if (!await UpdateNeeded(updateMessage.TargetVersion, token))
                {
                    Trace.Info($"Can't find available update package.");
                    return(false);
                }

                Trace.Info($"An update is available.");

                // Print console line that warn user not shutdown runner.
                await UpdateRunnerUpdateStateAsync("Runner update in progress, do not shutdown runner.");
                await UpdateRunnerUpdateStateAsync($"Downloading {_targetPackage.Version} runner");

                await DownloadLatestRunner(token);

                Trace.Info($"Download latest runner and unzip into runner root.");

                // wait till all running job finish
                await UpdateRunnerUpdateStateAsync("Waiting for current job finish running.");

                await jobDispatcher.WaitAsync(token);

                Trace.Info($"All running job has exited.");

                // delete runner backup
                DeletePreviousVersionRunnerBackup(token);
                Trace.Info($"Delete old version runner backup.");

                // generate update script from template
                await UpdateRunnerUpdateStateAsync("Generate and execute update script.");

                string updateScript = GenerateUpdateScript(restartInteractiveRunner);
                Trace.Info($"Generate update script into: {updateScript}");

                // kick off update script
                Process invokeScript = new Process();
#if OS_WINDOWS
                invokeScript.StartInfo.FileName  = WhichUtil.Which("cmd.exe", trace: Trace);
                invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\"";
#elif (OS_OSX || OS_LINUX)
                invokeScript.StartInfo.FileName  = WhichUtil.Which("bash", trace: Trace);
                invokeScript.StartInfo.Arguments = $"\"{updateScript}\"";
#endif
                invokeScript.Start();
                Trace.Info($"Update script start running");

                await UpdateRunnerUpdateStateAsync("Runner will exit shortly for update, should back online within 10 seconds.");

                return(true);
            }
            finally
            {
                Busy = false;
            }
        }
Beispiel #3
0
        public async Task <bool> SelfUpdate(AgentRefreshMessage updateMessage, IJobDispatcher jobDispatcher, bool restartInteractiveAgent, CancellationToken token)
        {
            ArgUtil.NotNull(updateMessage, nameof(updateMessage));
            ArgUtil.NotNull(jobDispatcher, nameof(jobDispatcher));
            if (!await UpdateNeeded(updateMessage.TargetVersion, token))
            {
                Trace.Info($"Can't find available update package.");
                return(false);
            }

            Trace.Info($"An update is available.");

            // Print console line that warn user not shutdown agent.
            await UpdateAgentUpdateStateAsync(StringUtil.Loc("UpdateInProgress"));
            await UpdateAgentUpdateStateAsync(StringUtil.Loc("DownloadAgent", _targetPackage.Version));

            await DownloadLatestAgent(token);

            Trace.Info($"Download latest agent and unzip into agent root.");

            // wait till all running job finish
            await UpdateAgentUpdateStateAsync(StringUtil.Loc("EnsureJobFinished"));

            await jobDispatcher.WaitAsync(token);

            Trace.Info($"All running jobs have exited.");

            // delete agent backup
            DeletePreviousVersionAgentBackup(token);
            Trace.Info($"Delete old version agent backup.");

            // generate update script from template
            await UpdateAgentUpdateStateAsync(StringUtil.Loc("GenerateAndRunUpdateScript"));

            string updateScript = GenerateUpdateScript(restartInteractiveAgent);

            Trace.Info($"Generate update script into: {updateScript}");

            // kick off update script
            Process invokeScript = new Process();

            if (PlatformUtil.RunningOnWindows)
            {
                invokeScript.StartInfo.FileName  = WhichUtil.Which("cmd.exe", trace: Trace);
                invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\"";
            }
            else
            {
                invokeScript.StartInfo.FileName  = WhichUtil.Which("bash", trace: Trace);
                invokeScript.StartInfo.Arguments = $"\"{updateScript}\"";
            }
            invokeScript.Start();
            Trace.Info($"Update script start running");

            await UpdateAgentUpdateStateAsync(StringUtil.Loc("AgentExit"));

            return(true);
        }
Beispiel #4
0
 public RabbitConnector(
     ILogger <RabbitConnector> logger,
     IJobDispatcher jobDispatcher,
     IEventFactory eventFactory)
 {
     _logger        = logger;
     _jobDispatcher = jobDispatcher;
     _eventFactory  = eventFactory;
 }
Beispiel #5
0
        public async Task <bool> SelfUpdate(AgentRefreshMessage updateMessage, IJobDispatcher jobDispatcher, bool restartInteractiveAgent, CancellationToken token)
        {
            if (!await UpdateNeeded(updateMessage.TargetVersion, token))
            {
                Trace.Info($"Can't find available update package.");
                return(false);
            }

            Trace.Info($"An update is available.");

            // Print console line that warn user not shutdown agent.
            await UpdateAgentUpdateStateAsync(StringUtil.Loc("UpdateInProgress"));
            await UpdateAgentUpdateStateAsync(StringUtil.Loc("DownloadAgent", _targetPackage.Version));

            await DownloadLatestAgent(token);

            Trace.Info($"Download latest agent and unzip into agent root.");

            // wait till all running job finish
            await UpdateAgentUpdateStateAsync(StringUtil.Loc("EnsureJobFinished"));

            await jobDispatcher.WaitAsync(token);

            Trace.Info($"All running job has exited.");

            // delete agent backup
            DeletePreviousVersionAgentBackup(token);
            Trace.Info($"Delete old version agent backup.");

            // generate update script from template
            await UpdateAgentUpdateStateAsync(StringUtil.Loc("GenerateAndRunUpdateScript"));

            string updateScript = GenerateUpdateScript(restartInteractiveAgent);

            Trace.Info($"Generate update script into: {updateScript}");

            // kick off update script
            Process invokeScript = new Process();
            var     whichUtil    = HostContext.GetService <IWhichUtil>();

#if OS_WINDOWS
            invokeScript.StartInfo.FileName  = whichUtil.Which("cmd.exe");
            invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\"";
#elif (OS_OSX || OS_LINUX)
            invokeScript.StartInfo.FileName  = whichUtil.Which("bash");
            invokeScript.StartInfo.Arguments = $"\"{updateScript}\"";
#endif
            invokeScript.Start();
            Trace.Info($"Update script start running");

            await UpdateAgentUpdateStateAsync(StringUtil.Loc("AgentExit"));

            return(true);
        }
Beispiel #6
0
 public Plan(IContainerService containerService, Fr8Account dockyardAccount, IActivity activity,
             ICrateManager crate, ISecurityServices security, IJobDispatcher dispatcher, IPusherNotifier pusher)
 {
     _containerService = containerService;
     _dockyardAccount  = dockyardAccount;
     _activity         = activity;
     _crate            = crate;
     _security         = security;
     _dispatcher       = dispatcher;
     _pusherNotifier   = pusher;
 }
Beispiel #7
0
        public async Task <bool> SelfUpdate(IJobDispatcher jobDispatcher, bool restartInteractiveAgent, CancellationToken token)
        {
            if (!await UpdateNeeded(token))
            {
                Trace.Info($"Can't find availiable update package.");
                return(false);
            }

            Trace.Info($"An update is availiable.");

            string latestAgent = await DownloadLatestAgent(token);

            Trace.Info($"Download latest agent into: {latestAgent}");

            // wait till all running job finish
            await jobDispatcher.WaitAsync(token);

            Trace.Info($"All running job has exited.");

            // delete previous backup agent
            // bin.bak.2.99.0
            // externals.bak.2.99.0
            foreach (string existBackUp in Directory.GetDirectories(IOUtil.GetRootPath(), "*.bak.*"))
            {
                Trace.Info($"Delete existing agent backup at {existBackUp}.");
                IOUtil.DeleteDirectory(existBackUp, token);
            }

            // generate update script
#if OS_WINDOWS
            string updateScript = GenerateBatchScript(latestAgent, restartInteractiveAgent);
#elif (OS_OSX || OS_LINUX)
            string updateScript = GenerateShellScript(latestAgent, restartInteractiveAgent);
#endif
            Trace.Info($"Generate update script into: {updateScript}");

            // kick off update script
            Process invokeScript = new Process();
            var     whichUtil    = HostContext.GetService <IWhichUtil>();
#if OS_WINDOWS
            invokeScript.StartInfo.FileName  = whichUtil.Which("cmd.exe");
            invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\"";
#elif (OS_OSX || OS_LINUX)
            invokeScript.StartInfo.FileName  = whichUtil.Which("bash");
            invokeScript.StartInfo.Arguments = $"-c \"{updateScript}\"";
#endif
            invokeScript.Start();
            Trace.Info($"Update script start running");

            return(true);
        }
Beispiel #8
0
        public async Task<bool> SelfUpdate(IJobDispatcher jobDispatcher, bool restartInteractiveAgent, CancellationToken token)
        {
            if (!await UpdateNeeded(token))
            {
                Trace.Info($"Can't find availiable update package.");
                return false;
            }

            Trace.Info($"An update is availiable.");

            string latestAgent = await DownloadLatestAgent(token);
            Trace.Info($"Download latest agent into: {latestAgent}");

            // wait till all running job finish
            await jobDispatcher.WaitAsync(token);
            Trace.Info($"All running job has exited.");

            // delete previous backup agent
            // bin.bak.2.99.0
            // externals.bak.2.99.0
            foreach (string existBackUp in Directory.GetDirectories(IOUtil.GetRootPath(), "*.bak.*"))
            {
                Trace.Info($"Delete existing agent backup at {existBackUp}.");
                IOUtil.DeleteDirectory(existBackUp, token);
            }

            // generate update script
#if OS_WINDOWS
            string updateScript = GenerateBatchScript(latestAgent, restartInteractiveAgent);
#elif (OS_OSX || OS_LINUX)
            string updateScript = GenerateShellScript(latestAgent, restartInteractiveAgent);
#endif
            Trace.Info($"Generate update script into: {updateScript}");

            // kick off update script
            Process invokeScript = new Process();
            var whichUtil = HostContext.GetService<IWhichUtil>();
#if OS_WINDOWS
            invokeScript.StartInfo.FileName = whichUtil.Which("cmd.exe");
            invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\"";
#elif (OS_OSX || OS_LINUX)
            invokeScript.StartInfo.FileName = whichUtil.Which("bash");
            invokeScript.StartInfo.Arguments = $"-c \"{updateScript}\"";
#endif
            invokeScript.Start();
            Trace.Info($"Update script start running");

            return true;
        }
 public RunController(ILogger <RunController> logger,
                      IJobDispatcher dispatcher)
 {
     _logger     = logger;
     _dispatcher = dispatcher;
 }
Beispiel #10
0
 public KillController(IJobDispatcher dispatcher)
 {
     _dispatcher = dispatcher;
 }
Beispiel #11
0
        //create worker manager, create message listener and start listening to the queue
        private async Task <int> RunAsync(CancellationToken token, AgentSettings settings, bool runAsService)
        {
            Trace.Info(nameof(RunAsync));

            // Load the settings.
            _poolId = settings.PoolId;

            var listener = HostContext.GetService <IMessageListener>();

            if (!await listener.CreateSessionAsync(token))
            {
                return(Constants.Agent.ReturnCode.TerminatedError);
            }

            _term.WriteLine(StringUtil.Loc("ListenForJobs", DateTime.UtcNow));

            _sessionId = listener.Session.SessionId;
            IJobDispatcher jobDispatcher = null;

            try
            {
                bool        disableAutoUpdate    = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("agent.disableupdate"));
                bool        autoUpdateInProgress = false;
                Task <bool> selfUpdateTask       = null;
                jobDispatcher = HostContext.CreateService <IJobDispatcher>();
                while (!token.IsCancellationRequested)
                {
                    TaskAgentMessage message             = null;
                    bool             skipMessageDeletion = false;
                    try
                    {
                        Task <TaskAgentMessage> getNextMessage = listener.GetNextMessageAsync(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 agent update is ready to apply exit the current agent instance.");
                                    return(Constants.Agent.ReturnCode.AgentUpdating);
                                }
                                else
                                {
                                    Trace.Info("Auto update task finished at backend, there is no available agent update needs to apply, continue message queue looping.");
                                }
                            }
                        }

                        message = await getNextMessage; //get next message
                        if (string.Equals(message.MessageType, AgentRefreshMessage.MessageType, StringComparison.OrdinalIgnoreCase))
                        {
                            if (disableAutoUpdate)
                            {
                                Trace.Info("Refresh message received, skip autoupdate since environment variable agent.disableupdate is set.");
                            }
                            else
                            {
                                if (autoUpdateInProgress == false)
                                {
                                    autoUpdateInProgress = true;
                                    var selfUpdater = HostContext.GetService <ISelfUpdater>();
                                    selfUpdateTask = selfUpdater.SelfUpdate(jobDispatcher, !runAsService, token);
                                    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, JobRequestMessage.MessageType, StringComparison.OrdinalIgnoreCase))
                        {
                            if (autoUpdateInProgress)
                            {
                                skipMessageDeletion = true;
                            }
                            else
                            {
                                var newJobMessage = JsonUtility.FromString <JobRequestMessage>(message.Body);
                                jobDispatcher.Run(newJobMessage);
                            }
                        }
                        else if (string.Equals(message.MessageType, JobCancelMessage.MessageType, StringComparison.OrdinalIgnoreCase))
                        {
                            var  cancelJobMessage = JsonUtility.FromString <JobCancelMessage>(message.Body);
                            bool jobCancelled     = jobDispatcher.Cancel(cancelJobMessage);
                            skipMessageDeletion = autoUpdateInProgress && !jobCancelled;
                        }
                    }
                    finally
                    {
                        if (!skipMessageDeletion && message != null)
                        {
                            try
                            {
                                await 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();
            }

            return(Constants.Agent.ReturnCode.Success);
        }
 public EventsController()
 {
     _crate         = ObjectFactory.GetInstance <ICrateManager>();
     _jobDispatcher = ObjectFactory.GetInstance <IJobDispatcher>();
 }
Beispiel #13
0
        public async Task <bool> SelfUpdate(AgentRefreshMessage updateMessage, IJobDispatcher jobDispatcher, bool restartInteractiveRunner, CancellationToken token)
        {
            Busy = true;
            try
            {
                var totalUpdateTime = Stopwatch.StartNew();

                if (!await UpdateNeeded(updateMessage.TargetVersion, token))
                {
                    Trace.Info($"Can't find available update package.");
                    return(false);
                }

                Trace.Info($"An update is available.");
                _updateTrace.Add($"RunnerPlatform: {_targetPackage.Platform}");

                // RUST: disable self-updates
                var rustAvoidUnreachableCodeError = true;
                if (rustAvoidUnreachableCodeError)
                {
                    Console.WriteLine("RUST: prevented self-update");
                    return(false);
                }

                // Print console line that warn user not shutdown runner.
                await UpdateRunnerUpdateStateAsync("Runner update in progress, do not shutdown runner.");
                await UpdateRunnerUpdateStateAsync($"Downloading {_targetPackage.Version} runner");

                await DownloadLatestRunner(token);

                Trace.Info($"Download latest runner and unzip into runner root.");

                // wait till all running job finish
                await UpdateRunnerUpdateStateAsync("Waiting for current job finish running.");

                await jobDispatcher.WaitAsync(token);

                Trace.Info($"All running job has exited.");

                // We need to keep runner backup around for macOS until we fixed https://github.com/actions/runner/issues/743
                // delete runner backup
                var stopWatch = Stopwatch.StartNew();
                DeletePreviousVersionRunnerBackup(token);
                Trace.Info($"Delete old version runner backup.");
                stopWatch.Stop();
                // generate update script from template
                _updateTrace.Add($"DeleteRunnerBackupTime: {stopWatch.ElapsedMilliseconds}ms");
                await UpdateRunnerUpdateStateAsync("Generate and execute update script.");

                string updateScript = GenerateUpdateScript(restartInteractiveRunner);
                Trace.Info($"Generate update script into: {updateScript}");

                // kick off update script
                Process invokeScript = new Process();
#if OS_WINDOWS
                invokeScript.StartInfo.FileName  = WhichUtil.Which("cmd.exe", trace: Trace);
                invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\"";
#elif (OS_OSX || OS_LINUX)
                invokeScript.StartInfo.FileName  = WhichUtil.Which("bash", trace: Trace);
                invokeScript.StartInfo.Arguments = $"\"{updateScript}\"";
#endif
                invokeScript.Start();
                Trace.Info($"Update script start running");

                totalUpdateTime.Stop();

                _updateTrace.Add($"TotalUpdateTime: {totalUpdateTime.ElapsedMilliseconds}ms");
                await UpdateRunnerUpdateStateAsync("Runner will exit shortly for update, should be back online within 10 seconds.");

                return(true);
            }
            catch (Exception ex)
            {
                _updateTrace.Add(ex.ToString());
                throw;
            }
            finally
            {
                await UpdateRunnerUpdateStateAsync("Runner update process finished.");

                Busy = false;
            }
        }
Beispiel #14
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);
        }
Beispiel #15
0
        public async Task <bool> SelfUpdate(AgentRefreshMessage updateMessage, IJobDispatcher jobDispatcher, bool restartInteractiveRunner, CancellationToken token)
        {
            Busy = true;
            try
            {
                if (!await UpdateNeeded(updateMessage.TargetVersion, token))
                {
                    Trace.Info($"Can't find available update package.");
                    return(false);
                }

                Trace.Info($"An update is available.");

                var runnerUpdateNotification = Environment.GetEnvironmentVariable("_INTERNAL_RUNNER_LIFECYCLE_NOTIFICATION");
                if (!string.IsNullOrEmpty(runnerUpdateNotification))
                {
                    HostContext.GetService <ITerminal>().WriteLine($"{DateTime.UtcNow:u}: Publish RunnerUpdate to {runnerUpdateNotification}");
                    using (var runnerUpdateInvoker = HostContext.CreateService <IProcessInvoker>())
                    {
                        runnerUpdateInvoker.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stdout)
                        {
                            if (!string.IsNullOrEmpty(stdout.Data))
                            {
                                Trace.Info($"RunnerUpdateNotification: {stdout.Data}");
                            }
                        };

                        runnerUpdateInvoker.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stderr)
                        {
                            if (!string.IsNullOrEmpty(stderr.Data))
                            {
                                if (!string.IsNullOrEmpty(stderr.Data))
                                {
                                    Trace.Error($"RunnerUpdateNotification: {stderr.Data}");
                                }
                            }
                        };

                        try
                        {
                            await runnerUpdateInvoker.ExecuteAsync(
                                workingDirectory : HostContext.GetDirectory(WellKnownDirectory.Root),
                                fileName : WhichUtil.Which("bash"),
                                arguments : $"-c \"{runnerUpdateNotification} RUNNERUPDATE {DateTime.UtcNow.ToString("O")}\"",
                                environment : null,
                                requireExitCodeZero : true,
                                outputEncoding : null,
                                killProcessOnCancel : true,
                                redirectStandardIn : null,
                                inheritConsoleHandler : false,
                                keepStandardInOpen : false,
                                highPriorityProcess : true,
                                cancellationToken : new CancellationTokenSource(10000).Token);
                        }
                        catch (Exception ex)
                        {
                            Trace.Error($"Fail to publish RunnerUpdate notification: {ex}");
                        }
                    }
                }
                // Print console line that warn user not shutdown runner.
                await UpdateRunnerUpdateStateAsync("Runner update in progress, do not shutdown runner.");
                await UpdateRunnerUpdateStateAsync($"Downloading {_targetPackage.Version} runner");

                await DownloadLatestRunner(token);

                Trace.Info($"Download latest runner and unzip into runner root.");

                // wait till all running job finish
                await UpdateRunnerUpdateStateAsync("Waiting for current job finish running.");

                await jobDispatcher.WaitAsync(token);

                Trace.Info($"All running job has exited.");

                // delete runner backup
                DeletePreviousVersionRunnerBackup(token);
                Trace.Info($"Delete old version runner backup.");

                // generate update script from template
                await UpdateRunnerUpdateStateAsync("Generate and execute update script.");

                string updateScript = GenerateUpdateScript(restartInteractiveRunner);
                Trace.Info($"Generate update script into: {updateScript}");

                // kick off update script
                Process invokeScript = new Process();
#if OS_WINDOWS
                invokeScript.StartInfo.FileName  = WhichUtil.Which("cmd.exe", trace: Trace);
                invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\"";
#elif (OS_OSX || OS_LINUX)
                invokeScript.StartInfo.FileName  = WhichUtil.Which("bash", trace: Trace);
                invokeScript.StartInfo.Arguments = $"\"{updateScript}\"";
#endif
                invokeScript.Start();
                Trace.Info($"Update script start running");

                await UpdateRunnerUpdateStateAsync("Runner will exit shortly for update, should back online within 10 seconds.");

                return(true);
            }
            finally
            {
                Busy = false;
            }
        }
Beispiel #16
0
        public async Task <int> LocalRunAsync(CommandSettings command, CancellationToken token)
        {
            Trace.Info(nameof(LocalRunAsync));

            // Warn preview.
            _term.WriteLine("This command is currently in preview. The interface and behavior will change in a future version.");
            if (!command.Unattended)
            {
                _term.WriteLine("Press Enter to continue.");
                _term.ReadLine();
            }

            HostContext.RunMode = RunMode.Local;

            // Resolve the YAML file path.
            string ymlFile = command.GetYml();

            if (string.IsNullOrEmpty(ymlFile))
            {
                string[] ymlFiles =
                    Directory.GetFiles(Directory.GetCurrentDirectory())
                    .Where((string filePath) =>
                {
                    return(filePath.EndsWith(".yml", IOUtil.FilePathStringComparison));
                })
                    .ToArray();
                if (ymlFiles.Length > 1)
                {
                    throw new Exception($"More than one .yml file exists in the current directory. Specify which file to use via the '{Constants.Agent.CommandLine.Args.Yml}' command line argument.");
                }

                ymlFile = ymlFiles.FirstOrDefault();
            }

            if (string.IsNullOrEmpty(ymlFile))
            {
                throw new Exception($"Unable to find a .yml file in the current directory. Specify which file to use via the '{Constants.Agent.CommandLine.Args.Yml}' command line argument.");
            }

            // Load the YAML file.
            var parseOptions = new ParseOptions
            {
                MaxFiles = 10,
                MustacheEvaluationMaxResultLength = 512 * 1024, // 512k string length
                MustacheEvaluationTimeout         = TimeSpan.FromSeconds(10),
                MustacheMaxDepth = 5,
            };
            var pipelineParser = new PipelineParser(new PipelineTraceWriter(), new PipelineFileProvider(), parseOptions);

            Pipelines.Process process = pipelineParser.Load(
                defaultRoot: Directory.GetCurrentDirectory(),
                path: ymlFile,
                mustacheContext: null,
                cancellationToken: HostContext.AgentShutdownToken);
            ArgUtil.NotNull(process, nameof(process));
            if (command.WhatIf)
            {
                return(Constants.Agent.ReturnCode.Success);
            }

            // Verify the current directory is the root of a git repo.
            string repoDirectory = Directory.GetCurrentDirectory();

            if (!Directory.Exists(Path.Combine(repoDirectory, ".git")))
            {
                throw new Exception("Unable to run the build locally. The command must be executed from the root directory of a local git repository.");
            }

            // Get the URL - required if missing tasks.
            string url = command.GetUrl(suppressPromptIfEmpty: true);

            if (string.IsNullOrEmpty(url))
            {
                if (!TestAllTasksCached(process, token))
                {
                    url = command.GetUrl(suppressPromptIfEmpty: false);
                }
            }

            if (!string.IsNullOrEmpty(url))
            {
                // Initialize and store the HTTP client.
                var credentialManager = HostContext.GetService <ICredentialManager>();

                // Get the auth type. On premise defaults to negotiate (Kerberos with fallback to NTLM).
                // Hosted defaults to PAT authentication.
                string defaultAuthType = UrlUtil.IsHosted(url) ? Constants.Configuration.PAT :
                                         (Constants.Agent.Platform == Constants.OSPlatform.Windows ? Constants.Configuration.Integrated : Constants.Configuration.Negotiate);
                string authType = command.GetAuth(defaultValue: defaultAuthType);
                ICredentialProvider provider = credentialManager.GetCredentialProvider(authType);
                provider.EnsureCredential(HostContext, command, url);
                _taskStore.HttpClient = new TaskAgentHttpClient(new Uri(url), provider.GetVssCredentials(HostContext));
            }

            var           configStore = HostContext.GetService <IConfigurationStore>();
            AgentSettings settings    = configStore.GetSettings();

            // Create job message.
            IJobDispatcher jobDispatcher = null;

            try
            {
                jobDispatcher = HostContext.CreateService <IJobDispatcher>();
                foreach (JobInfo job in await ConvertToJobMessagesAsync(process, repoDirectory, token))
                {
                    job.RequestMessage.Environment.Variables[Constants.Variables.Agent.RunMode] = RunMode.Local.ToString();
                    jobDispatcher.Run(job.RequestMessage);
                    Task jobDispatch = jobDispatcher.WaitAsync(token);
                    if (!Task.WaitAll(new[] { jobDispatch }, job.Timeout))
                    {
                        jobDispatcher.Cancel(job.CancelMessage);

                        // Finish waiting on the same job dispatch task. The first call to WaitAsync dequeues
                        // the dispatch task and then proceeds to wait on it. So we need to continue awaiting
                        // the task instance (queue is now empty).
                        await jobDispatch;
                    }
                }
            }
            finally
            {
                if (jobDispatcher != null)
                {
                    await jobDispatcher.ShutdownAsync();
                }
            }

            return(Constants.Agent.ReturnCode.Success);
        }
Beispiel #17
0
        public async Task <int> RunAsync(CommandSettings command, CancellationToken token)
        {
            Trace.Info(nameof(RunAsync));
            var           configStore = HostContext.GetService <IConfigurationStore>();
            AgentSettings settings    = configStore.GetSettings();

            // Store the HTTP client.
            // todo: fix in master to allow URL to be empty and then rebase on master.
            const string DefaultUrl = "http://127.0.0.1/local-runner-default-url";
            string       url        = command.GetUrl(DefaultUrl);

            if (!string.Equals(url, DefaultUrl, StringComparison.Ordinal))
            {
                var    credentialManager     = HostContext.GetService <ICredentialManager>();
                string authType              = command.GetAuth(defaultValue: Constants.Configuration.Integrated);
                ICredentialProvider provider = credentialManager.GetCredentialProvider(authType);
                provider.EnsureCredential(HostContext, command, url);
                _httpClient = new TaskAgentHttpClient(new Uri(url), provider.GetVssCredentials(HostContext));
            }

            // Load the YAML file.
            string yamlFile = command.GetYaml();

            ArgUtil.File(yamlFile, nameof(yamlFile));
            var parseOptions = new ParseOptions
            {
                MaxFiles = 10,
                MustacheEvaluationMaxResultLength = 512 * 1024, // 512k string length
                MustacheEvaluationTimeout         = TimeSpan.FromSeconds(10),
                MustacheMaxDepth = 5,
            };
            var pipelineParser = new PipelineParser(new PipelineTraceWriter(), new PipelineFileProvider(), parseOptions);

            Pipelines.Process process = pipelineParser.Load(
                defaultRoot: Directory.GetCurrentDirectory(),
                path: yamlFile,
                mustacheContext: null,
                cancellationToken: HostContext.AgentShutdownToken);
            ArgUtil.NotNull(process, nameof(process));
            if (command.WhatIf)
            {
                return(Constants.Agent.ReturnCode.Success);
            }

            // Create job message.
            IJobDispatcher jobDispatcher = null;

            try
            {
                jobDispatcher = HostContext.CreateService <IJobDispatcher>();
                foreach (JobInfo job in await ConvertToJobMessagesAsync(process, token))
                {
                    job.RequestMessage.Environment.Variables[Constants.Variables.Agent.RunMode] = RunMode.Local.ToString();
                    jobDispatcher.Run(job.RequestMessage);
                    Task jobDispatch = jobDispatcher.WaitAsync(token);
                    if (!Task.WaitAll(new[] { jobDispatch }, job.Timeout))
                    {
                        jobDispatcher.Cancel(job.CancelMessage);

                        // Finish waiting on the same job dispatch task. The first call to WaitAsync dequeues
                        // the dispatch task and then proceeds to wait on it. So we need to continue awaiting
                        // the task instance (queue is now empty).
                        await jobDispatch;
                    }
                }
            }
            finally
            {
                if (jobDispatcher != null)
                {
                    await jobDispatcher.ShutdownAsync();
                }
            }

            return(Constants.Agent.ReturnCode.Success);
        }
 public IdleBeatController(IJobDispatcher dispatcher)
 {
     _dispatcher = dispatcher;
 }
Beispiel #19
0
        public void Configuration(IAppBuilder appBuilder)
        {
            // Set up server configuration
            HttpConfiguration config = new HttpConfiguration();

            // DscQRouteHandler
            config.MessageHandlers.Add(new DscQRouteHandler());

            config.MapODataServiceRoute(
                routeName: "DscQuery",
                routePrefix: "{datasource}/{path}/odata",
                model: GetQueryEdmModel());

            #region DI
            Container = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient()).WithWebApi(config);

            Container.RegisterMany(new [] { GetType().Assembly }, (registrator, types, type) =>
            {
                Type[] interfaces = type.GetInterfaces();

                bool assignedFromDispatcher = interfaces.Any(i => i.IsAssignableTo(typeof(IJobDispatcher)) || i.IsAssignableTo(typeof(IQueryDispatcher)));

                if (assignedFromDispatcher || interfaces.Any(i => i.IsAssignableTo(typeof(IInterceptor)) ||
                                                             i.IsAssignableTo(typeof(IJob)) ||
                                                             i.IsAssignableTo(typeof(IQuery)) ||
                                                             (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IQueryHandler <,>))))
                {
                    // all dispatchers --> Reuse.InCurrentScope
                    IReuse reuse = assignedFromDispatcher
                        ? Reuse.InResolutionScope
                        : Reuse.Transient;

                    registrator.RegisterMany(types, type, reuse);

                    // interceptors
                    if (type.IsClass)
                    {
                        InterceptedObjectAttribute attr = (InterceptedObjectAttribute)type.GetCustomAttribute(typeof(InterceptedObjectAttribute));
                        if (attr != null)
                        {
                            Type serviceType = attr.ServiceInterfaceType ?? type.GetImplementedInterfaces().FirstOrDefault();
                            registrator.Intercept(serviceType, attr.InterceptorType);
                        }
                    }
                }
            });

            Container.RegisterInstance((IOracleEnvironmentConfiguration)System.Configuration.ConfigurationManager.GetSection("oracleEnvironment"));
            Container.RegisterInstance(System.Configuration.ConfigurationManager.AppSettings["ProviderName"], serviceKey: "ProviderName");
            Container.Register(
                reuse: Reuse.InResolutionScope,
                made: Made.Of(() => DbManagerFactory.CreateDbManager(Arg.Of <string>("ProviderName"), null), requestIgnored => string.Empty)
                );

            // IDbManager initialiazation
            Container.RegisterInitializer <IDbManager>((m, r) => m.Log = Log.Logger.Debug);

            // cache manager
            Container.Register(reuse: Reuse.Singleton, made: Made.Of(() => CacheFactory.FromConfiguration <object>("webCache")));

            Container.UseInstance(Container);
            #endregion

            // Startup Jobs
            IJobDispatcher dispatcher = Container.Resolve <IJobDispatcher>(IfUnresolved.ReturnDefault);
            dispatcher?.Dispatch <IStartupJob>();

            config.Filters.Add(new GlobalExceptionFilter());

            var odataFormatters = ODataMediaTypeFormatters.Create(new SkipNullValueODataSerializerProvider(), new DefaultODataDeserializerProvider());
            config.Formatters.InsertRange(0, odataFormatters);

            appBuilder.UseWebApi(config);
        }
Beispiel #20
0
 public JobController(IJobDispatcher jobDispatcher)
 {
     _jobDispatcher = jobDispatcher;
 }
Beispiel #21
0
        //create worker manager, create message listener and start listening to the queue
        private async Task <int> RunAsync(AgentSettings settings)
        {
            Trace.Info(nameof(RunAsync));
            _listener = HostContext.GetService <IMessageListener>();
            if (!await _listener.CreateSessionAsync(HostContext.AgentShutdownToken))
            {
                return(Constants.Agent.ReturnCode.TerminatedError);
            }

            _term.WriteLine(StringUtil.Loc("ListenForJobs", DateTime.UtcNow));

            IJobDispatcher          jobDispatcher = null;
            CancellationTokenSource messageQueueLoopTokenSource = CancellationTokenSource.CreateLinkedTokenSource(HostContext.AgentShutdownToken);

            try
            {
                var notification = HostContext.GetService <IJobNotification>();
                if (!String.IsNullOrEmpty(settings.NotificationSocketAddress))
                {
                    notification.StartClient(settings.NotificationSocketAddress);
                }
                else
                {
                    notification.StartClient(settings.NotificationPipeName, HostContext.AgentShutdownToken);
                }
                // this is not a reliable way to disable auto update.
                // we need server side work to really enable the feature
                // https://github.com/Microsoft/vsts-agent/issues/446 (Feature: Allow agent / pool to opt out of automatic updates)
                bool        disableAutoUpdate    = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("agent.disableupdate"));
                bool        autoUpdateInProgress = false;
                Task <bool> selfUpdateTask       = null;
                jobDispatcher = HostContext.CreateService <IJobDispatcher>();

                while (!HostContext.AgentShutdownToken.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 agent update is ready to apply exit the current agent 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}");
                                    }

                                    return(Constants.Agent.ReturnCode.AgentUpdating);
                                }
                                else
                                {
                                    Trace.Info("Auto update task finished at backend, there is no available agent update needs to apply, continue message queue looping.");
                                }
                            }
                        }

                        message = await getNextMessage; //get next message
                        if (string.Equals(message.MessageType, AgentRefreshMessage.MessageType, StringComparison.OrdinalIgnoreCase))
                        {
                            if (disableAutoUpdate)
                            {
                                Trace.Info("Refresh message received, skip autoupdate since environment variable agent.disableupdate is set.");
                            }
                            else
                            {
                                if (autoUpdateInProgress == false)
                                {
                                    autoUpdateInProgress = true;
                                    var agentUpdateMessage = JsonUtility.FromString <AgentRefreshMessage>(message.Body);
                                    var selfUpdater        = HostContext.GetService <ISelfUpdater>();
                                    selfUpdateTask = selfUpdater.SelfUpdate(agentUpdateMessage, jobDispatcher, HostContext.StartupType != StartupType.Service, HostContext.AgentShutdownToken);
                                    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.AgentJobRequest, StringComparison.OrdinalIgnoreCase))
                        {
                            if (autoUpdateInProgress)
                            {
                                skipMessageDeletion = true;
                            }
                            else
                            {
                                var newJobMessage = JsonUtility.FromString <AgentJobRequestMessage>(message.Body);
                                jobDispatcher.Run(newJobMessage);
                            }
                        }
                        else if (string.Equals(message.MessageType, JobCancelMessage.MessageType, StringComparison.OrdinalIgnoreCase))
                        {
                            var  cancelJobMessage = JsonUtility.FromString <JobCancelMessage>(message.Body);
                            bool jobCancelled     = jobDispatcher.Cancel(cancelJobMessage);
                            skipMessageDeletion = autoUpdateInProgress && !jobCancelled;
                        }
                        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();
            }

            return(Constants.Agent.ReturnCode.Success);
        }
Beispiel #22
0
 public JobDispatcherItem(IJobDispatcher dispatcher, Task task, CancellationTokenSource token)
 {
     Dispatcher     = dispatcher;
     DispatcherTask = task;
     Token          = token;
 }
Beispiel #23
0
        public async Task <int> LocalRunAsync(CommandSettings command, CancellationToken token)
        {
            Trace.Info(nameof(LocalRunAsync));

            // Warn preview.
            _term.WriteLine("This command is currently in preview. The interface and behavior will change in a future version.");
            if (!command.Unattended)
            {
                _term.WriteLine("Press Enter to continue.");
                _term.ReadLine();
            }

            HostContext.RunMode = RunMode.Local;

            // Resolve the YAML file path.
            string ymlFile = command.GetYml();

            if (string.IsNullOrEmpty(ymlFile))
            {
                string[] ymlFiles =
                    Directory.GetFiles(Directory.GetCurrentDirectory())
                    .Where((string filePath) =>
                {
                    return(filePath.EndsWith(".yml", IOUtil.FilePathStringComparison));
                })
                    .ToArray();
                if (ymlFiles.Length > 1)
                {
                    throw new Exception($"More than one .yml file exists in the current directory. Specify which file to use via the --'{Constants.Agent.CommandLine.Args.Yml}' command line argument.");
                }

                ymlFile = ymlFiles.FirstOrDefault();
            }

            if (string.IsNullOrEmpty(ymlFile))
            {
                throw new Exception($"Unable to find a .yml file in the current directory. Specify which file to use via the --'{Constants.Agent.CommandLine.Args.Yml}' command line argument.");
            }

            // Load the YAML file.
            var parseOptions = new ParseOptions
            {
                MaxFiles = 10,
                MustacheEvaluationMaxResultLength = 512 * 1024, // 512k string length
                MustacheEvaluationTimeout         = TimeSpan.FromSeconds(10),
                MustacheMaxDepth = 5,
            };
            var pipelineParser = new PipelineParser(new PipelineTraceWriter(), new PipelineFileProvider(), parseOptions);

            if (command.WhatIf)
            {
                pipelineParser.DeserializeAndSerialize(
                    defaultRoot: Directory.GetCurrentDirectory(),
                    path: ymlFile,
                    mustacheContext: null,
                    cancellationToken: HostContext.AgentShutdownToken);
                return(Constants.Agent.ReturnCode.Success);
            }

            YamlContracts.Process process = pipelineParser.LoadInternal(
                defaultRoot: Directory.GetCurrentDirectory(),
                path: ymlFile,
                mustacheContext: null,
                cancellationToken: HostContext.AgentShutdownToken);
            ArgUtil.NotNull(process, nameof(process));

            // Verify the current directory is the root of a git repo.
            string repoDirectory = Directory.GetCurrentDirectory();

            if (!Directory.Exists(Path.Combine(repoDirectory, ".git")))
            {
                throw new Exception("Unable to run the build locally. The command must be executed from the root directory of a local git repository.");
            }

            // Verify at least one phase was found.
            if (process.Phases == null || process.Phases.Count == 0)
            {
                throw new Exception($"No phases or steps were discovered from the file: '{ymlFile}'");
            }

            // Filter the phases.
            string phaseName = command.GetPhase();

            if (!string.IsNullOrEmpty(phaseName))
            {
                process.Phases = process.Phases
                                 .Cast <YamlContracts.Phase>()
                                 .Where(x => string.Equals(x.Name, phaseName, StringComparison.OrdinalIgnoreCase))
                                 .Cast <YamlContracts.IPhase>()
                                 .ToList();
                if (process.Phases.Count == 0)
                {
                    throw new Exception($"Phase '{phaseName}' not found.");
                }
            }

            // Verify a phase was specified if more than one phase was found.
            if (process.Phases.Count > 1)
            {
                throw new Exception($"More than one phase was discovered. Use the --{Constants.Agent.CommandLine.Args.Phase} argument to specify a phase.");
            }

            // Get the matrix.
            var phase       = process.Phases[0] as YamlContracts.Phase;
            var queueTarget = phase.Target as QueueTarget;

            // Filter to a specific matrix.
            string matrixName = command.GetMatrix();

            if (!string.IsNullOrEmpty(matrixName))
            {
                if (queueTarget?.Matrix != null)
                {
                    queueTarget.Matrix = queueTarget.Matrix.Keys
                                         .Where(x => string.Equals(x, matrixName, StringComparison.OrdinalIgnoreCase))
                                         .ToDictionary(keySelector: x => x, elementSelector: x => queueTarget.Matrix[x]);
                }

                if (queueTarget?.Matrix == null || queueTarget.Matrix.Count == 0)
                {
                    throw new Exception($"Job configuration matrix '{matrixName}' not found.");
                }
            }

            // Verify a matrix was specified if more than one matrix was found.
            if (queueTarget?.Matrix != null && queueTarget.Matrix.Count > 1)
            {
                throw new Exception($"More than one job configuration matrix was discovered. Use the --{Constants.Agent.CommandLine.Args.Matrix} argument to specify a matrix.");
            }

            // Get the URL - required if missing tasks.
            string url = command.GetUrl(suppressPromptIfEmpty: true);

            if (string.IsNullOrEmpty(url))
            {
                if (!TestAllTasksCached(process, token))
                {
                    url = command.GetUrl(suppressPromptIfEmpty: false);
                }
            }

            if (!string.IsNullOrEmpty(url))
            {
                // Initialize and store the HTTP client.
                var credentialManager = HostContext.GetService <ICredentialManager>();

                // Get the auth type. On premise defaults to negotiate (Kerberos with fallback to NTLM).
                // Hosted defaults to PAT authentication.
                string defaultAuthType = UrlUtil.IsHosted(url) ? Constants.Configuration.PAT :
                                         (Constants.Agent.Platform == Constants.OSPlatform.Windows ? Constants.Configuration.Integrated : Constants.Configuration.Negotiate);
                string authType = command.GetAuth(defaultValue: defaultAuthType);
                ICredentialProvider provider = credentialManager.GetCredentialProvider(authType);
                provider.EnsureCredential(HostContext, command, url);
                _taskStore.HttpClient = new TaskAgentHttpClient(new Uri(url), provider.GetVssCredentials(HostContext));
            }

            var           configStore = HostContext.GetService <IConfigurationStore>();
            AgentSettings settings    = configStore.GetSettings();

            // Create job message.
            JobInfo        job           = (await ConvertToJobMessagesAsync(process, repoDirectory, token)).Single();
            IJobDispatcher jobDispatcher = null;

            try
            {
                jobDispatcher = HostContext.CreateService <IJobDispatcher>();
                job.RequestMessage.Environment.Variables[Constants.Variables.Agent.RunMode] = RunMode.Local.ToString();
                jobDispatcher.Run(job.RequestMessage);
                Task jobDispatch = jobDispatcher.WaitAsync(token);
                if (!Task.WaitAll(new[] { jobDispatch }, job.Timeout))
                {
                    jobDispatcher.Cancel(job.CancelMessage);

                    // Finish waiting on the job dispatch task. The call to jobDispatcher.WaitAsync dequeues
                    // the job dispatch task. In the cancel flow, we need to continue awaiting the task instance
                    // (queue is now empty).
                    await jobDispatch;
                }

                // Translate the job result to an agent return code.
                TaskResult jobResult = jobDispatcher.GetLocalRunJobResult(job.RequestMessage);
                switch (jobResult)
                {
                case TaskResult.Succeeded:
                case TaskResult.SucceededWithIssues:
                    return(Constants.Agent.ReturnCode.Success);

                default:
                    return(Constants.Agent.ReturnCode.TerminatedError);
                }
            }
            finally
            {
                if (jobDispatcher != null)
                {
                    await jobDispatcher.ShutdownAsync();
                }
            }
        }
Beispiel #24
0
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddApplicationInsightsTelemetry(Configuration);
            services.AddOptions();

            services.Configure <AppSettings>(Configuration.GetSection("AppSettings"));
            services.Configure <ConnectionOptions>(Configuration.GetSection("Data:DefaultConnection"));
            services.Configure <ForceHttpsOptions>(Configuration.GetSection("HttpsOptions"));
            services.Configure <OracleEnvironmentConfiguration>(Configuration.GetSection("OracleEnvironment"));
            services.Configure <List <Client> >(Configuration.GetSection("Clients"));

            //identityServer
            IIdentityServerBuilder builder = services
                                             .AddIdentityServer(options =>
            {
                options.UserInteractionOptions.LoginUrl   = "/login";
                options.UserInteractionOptions.LogoutUrl  = "/logout";
                options.UserInteractionOptions.ConsentUrl = "/consent";
                options.UserInteractionOptions.ErrorUrl   = "/error";
            });

            #region certificate
            string fileName = Path.Combine(_contentRootPath, "idsrv4test.pfx");
            if (File.Exists(fileName))
            {
                X509Certificate2 cert = new X509Certificate2(fileName, "idsrv3test");
                builder.AddSigningCredential(cert);
            }
            else
            {
                builder.AddTemporarySigningCredential();
            }

            #endregion

            #region clients (from clients.json)
            builder.Services.AddSingleton <IEnumerable <Client> >(provider => provider.GetService <IOptions <List <Client> > >().Value);
            builder.Services.AddTransient <IClientStore, InMemoryClientStore>();
            builder.Services.AddTransient <ICorsPolicyService, InMemoryCorsPolicyService>();
            #endregion

            #region resources
            builder.AddInMemoryIdentityResources(accounts.Configuration.Resources.GetIdentityResources());
            #endregion

            #region users --> empty list
            builder.AddProfileService <Services.ProfileService>();
            builder.Services.AddSingleton(new List <InMemoryUser>());
            builder.Services.AddTransient <IResourceOwnerPasswordValidator, InMemoryUserResourceOwnerPasswordValidator>();
            #endregion

            // for the UI
            services
            .AddMvc(options =>
            {
                options.ModelBinderProviders.Insert(0, new EncryptModelBinderProvider());
                options.CacheProfiles.Add("1hour", new CacheProfile()
                {
                    Duration = 3600
                });
            })
            .AddJsonOptions(option =>
            {
                option.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                option.SerializerSettings.ContractResolver  = new CamelCasePropertyNamesContractResolver();
            });

            services.AddRouting(options => options.LowercaseUrls = true);
            services.Configure <MvcOptions>(options => options.Filters.Add(new GlobalExceptionFilter()));            // Global exceptions' filter
            services.Configure <RazorViewEngineOptions>(options => options.FileProviders.Add(new EmbeddedFileProvider(GetType().Assembly, "accounts")));

            // Add dependencies
            IContainer container = ConfigureDependencies(services, "domain", "Kit.Core", "Kit.Dal", "Kit.Dal.Oracle");

            // IDbManager
            container.RegisterDelegate(delegate(IResolver r)
            {
                HttpContext httpContext = r.Resolve <IHttpContextAccessor>().HttpContext;

                ClaimsPrincipal cp = httpContext.User;
                string userId      = cp.Identity.Name;

                return(httpContext.User.ToString($"Data Source={{{ConnectionClaimTypes.DataSource}}};User Id={userId};Password={{{ConnectionClaimTypes.Password}}};"));
            }, serviceKey: "ConnectionString");

            container.RegisterDelegate(r => r.Resolve <IOptions <ConnectionOptions> >().Value.ProviderName, serviceKey: "ProviderName");

            container.Register(
                reuse: Reuse.InWebRequest,
                made: Made.Of(() => DbManagerFactory.CreateDbManager(Arg.Of <string>("ProviderName"), Arg.Of <string>("ConnectionString")), requestIgnored => string.Empty)
                );

            // Startup Jobs
            IJobDispatcher dispatcher = container.Resolve <IJobDispatcher>(IfUnresolved.ReturnDefault);
            dispatcher?.Dispatch <IStartupJob>();

            return(container.Resolve <IServiceProvider>());
        }