From 40e004c60d96715d5cdcc9c6f2f84e617fdf4e82 Mon Sep 17 00:00:00 2001 From: eric sciple Date: Fri, 8 Apr 2022 19:47:44 +0000 Subject: [PATCH] support messages from broker --- src/Directory.Build.props | 5 + src/Runner.Common/BrokerServer.cs | 59 +++++ src/Runner.Common/RunServer.cs | 120 ++++++++++ src/Runner.Common/RunnerServer.cs | 43 +++- .../Configuration/CredentialManager.cs | 7 + src/Runner.Listener/JobDispatcher.cs | 44 ++-- src/Runner.Listener/MessageListener.cs | 207 ++++++++++++++++++ src/Runner.Listener/Runner.cs | 36 ++- src/Runner.Sdk/Util/VssUtil.cs | 1 + src/Runner.Worker/ActionManager.cs | 1 + .../Authentication/FederatedCredential.cs | 1 + .../Authentication/IssuedTokenCredential.cs | 4 + .../Common/Authentication/VssCredentials.cs | 13 ++ .../Common/Common/VssHttpMessageHandler.cs | 18 +- .../Generated/TaskAgentHttpClientBase.cs | 46 ++++ .../DTWebApi/WebApi/JobRequestMessageTypes.cs | 1 + .../DTWebApi/WebApi/TaskAgentHttpClient.cs | 6 +- .../WebApi/Location/ServerDataProvider.cs | 1 + .../WebApi/OAuth/VssOAuthAccessToken.cs | 1 + .../OAuth/VssOAuthAccessTokenCredential.cs | 2 + .../WebApi/WebApi/OAuth/VssOAuthCredential.cs | 9 +- .../WebApi/OAuth/VssOAuthTokenHttpClient.cs | 1 + .../WebApi/OAuth/VssOAuthTokenProvider.cs | 11 + src/Sdk/WebApi/WebApi/VssConnection.cs | 1 + src/Sdk/WebApi/WebApi/VssHttpClientBase.cs | 21 ++ src/dev.sh | 14 +- 26 files changed, 642 insertions(+), 31 deletions(-) create mode 100644 src/Runner.Common/BrokerServer.cs create mode 100644 src/Runner.Common/RunServer.cs diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 71e570e08..28668464f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -47,6 +47,11 @@ $(DefineConstants);DEBUG + + + $(DefineConstants);USE_BROKER + + true diff --git a/src/Runner.Common/BrokerServer.cs b/src/Runner.Common/BrokerServer.cs new file mode 100644 index 000000000..dd203a39d --- /dev/null +++ b/src/Runner.Common/BrokerServer.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using GitHub.DistributedTask.WebApi; +using System.Threading; +using System.Threading.Tasks; +using GitHub.Runner.Common.Util; +using GitHub.Services.WebApi; +using GitHub.Services.Common; +using GitHub.Runner.Sdk; +using System.Net; +using System.Net.Http; + +namespace GitHub.Runner.Common +{ + [ServiceLocator(Default = typeof(BrokerServer))] + public interface IBrokerServer : IRunnerService + { + Task ConnectAsync(Uri serverUrl, CancellationToken cancellationToken); + Task GetMessageAsync(TaskAgentSession session, RunnerSettings settings, long? lastMessageId, CancellationToken cancellationToken); + } + + public sealed class BrokerServer : RunnerService, IBrokerServer + { + private HttpClient _httpClient; + + public async Task ConnectAsync(Uri serverUrl, CancellationToken cancellationToken) + { + _httpClient = new HttpClient(); + _httpClient.BaseAddress = serverUrl; + _httpClient.Timeout = TimeSpan.FromSeconds(100); + await _httpClient.GetAsync("health", cancellationToken); + } + + public async Task GetMessageAsync(TaskAgentSession session, RunnerSettings settings, long? lastMessageId, CancellationToken cancellationToken) + { + var response = await _httpClient.GetAsync($"message?tenant=org:github&root_tenant=org:github&group_id={settings.PoolId}&group_name={settings.PoolName}&runner_id={settings.AgentId}&runner_name={settings.AgentName}&labels=self-hosted,linux", cancellationToken); + if (!response.IsSuccessStatusCode) + { + var content = default(string); + try + { + content = await response.Content.ReadAsStringAsync(); + } + catch + { + } + + var error = $"HTTP {(int)response.StatusCode} {Enum.GetName(typeof(HttpStatusCode), response.StatusCode)}"; + if (!string.IsNullOrEmpty(content)) + { + error = $"{error}: {content}"; + } + throw new Exception(error); + } + + return await response.Content.ReadAsStringAsync(); + } + } +} diff --git a/src/Runner.Common/RunServer.cs b/src/Runner.Common/RunServer.cs new file mode 100644 index 000000000..84327446c --- /dev/null +++ b/src/Runner.Common/RunServer.cs @@ -0,0 +1,120 @@ +using GitHub.DistributedTask.WebApi; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using GitHub.Runner.Common.Util; +using GitHub.Services.WebApi; +using GitHub.Services.Common; +using GitHub.Runner.Sdk; +using GitHub.DistributedTask.Pipelines; + +namespace GitHub.Runner.Common +{ + [ServiceLocator(Default = typeof(RunServer))] + public interface IRunServer : IRunnerService + { + Task ConnectAsync(Uri serverUrl, VssCredentials credentials); + + Task GetJobMessageAsync(Guid scopeId, Guid hostId, string planType, string planGroup, Guid planId, IList instanceRefsJson); + } + + public sealed class RunServer : RunnerService, IRunServer + { + private bool _hasConnection; + private VssConnection _connection; + private TaskAgentHttpClient _taskAgentClient; + + public async Task ConnectAsync(Uri serverUrl, VssCredentials credentials) + { + // System.Console.WriteLine("RunServer.ConnectAsync"); + _connection = await EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100)); + _taskAgentClient = _connection.GetClient(); + _hasConnection = true; + } + + private async Task EstablishVssConnection(Uri serverUrl, VssCredentials credentials, TimeSpan timeout) + { + // System.Console.WriteLine("EstablishVssConnection"); + Trace.Info($"EstablishVssConnection"); + Trace.Info($"Establish connection with {timeout.TotalSeconds} seconds timeout."); + int attemptCount = 5; + while (attemptCount-- > 0) + { + var connection = VssUtil.CreateConnection(serverUrl, credentials, timeout: timeout); + try + { + await connection.ConnectAsync(); + return connection; + } + catch (Exception ex) when (attemptCount > 0) + { + Trace.Info($"Catch exception during connect. {attemptCount} attempt left."); + Trace.Error(ex); + + await HostContext.Delay(TimeSpan.FromMilliseconds(100), CancellationToken.None); + } + } + + // should never reach here. + throw new InvalidOperationException(nameof(EstablishVssConnection)); + } + + private void CheckConnection() + { + if (!_hasConnection) + { + throw new InvalidOperationException($"SetConnection"); + } + } + + public Task GetJobMessageAsync( + Guid scopeId, + Guid hostId, + string planType, + string planGroup, + Guid planId, + IList instanceRefsJson) + { + // System.Console.WriteLine("RunServer.GetMessageAsync"); + CheckConnection(); + return _taskAgentClient.GetJobMessageAsync(scopeId, hostId, planType, planGroup, planId, StringUtil.ConvertToJson(instanceRefsJson, Newtonsoft.Json.Formatting.None)); + } + } + + // todo: move to SDK? + [DataContract] + public sealed class MessageRef + { + [DataMember(Name = "url")] + public string Url { get; set; } + [DataMember(Name = "token")] + public string Token { get; set; } + [DataMember(Name = "scopeId")] + public Guid ScopeId { get; set; } + [DataMember(Name = "hostId")] + public Guid HostId { get; set; } + [DataMember(Name = "planType")] + public string PlanType { get; set; } + [DataMember(Name = "planGroup")] + public string PlanGroup { get; set; } + [DataMember(Name = "planId")] + public Guid PlanId { get; set; } + [DataMember(Name = "instanceRefs")] + public InstanceRef[] InstanceRefs { get; set; } + [DataMember(Name = "labels")] + public string[] Labels { get; set; } + } + + [DataContract] + public sealed class InstanceRef + { + [DataMember(Name = "name")] + public string Name { get; set; } + [DataMember(Name = "instanceType")] + public string InstanceType { get; set; } + [DataMember(Name = "attempt")] + public int Attempt { get; set; } + } +} diff --git a/src/Runner.Common/RunnerServer.cs b/src/Runner.Common/RunnerServer.cs index f377622c6..10b6db203 100644 --- a/src/Runner.Common/RunnerServer.cs +++ b/src/Runner.Common/RunnerServer.cs @@ -44,7 +44,7 @@ namespace GitHub.Runner.Common // job request Task GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken); Task RenewAgentRequestAsync(int poolId, long requestId, Guid lockToken, string orchestrationId, CancellationToken cancellationToken); - Task FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken); + Task FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, Guid targetHostId, CancellationToken cancellationToken); // agent package Task> GetPackagesAsync(string packageType, string platform, int top, bool includeToken, CancellationToken cancellationToken); @@ -68,11 +68,23 @@ namespace GitHub.Runner.Common public async Task ConnectAsync(Uri serverUrl, VssCredentials credentials) { - var createGenericConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100)); + // System.Console.WriteLine("RunnerServer.ConnectAsync: Create message connection"); var createMessageConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60)); - var createRequestConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60)); + await Task.WhenAll(createMessageConnection); - await Task.WhenAll(createGenericConnection, createMessageConnection, createRequestConnection); + // System.Console.WriteLine("RunnerServer.ConnectAsync: Create generic connection"); + var createGenericConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100)); + await Task.WhenAll(createGenericConnection); + + // System.Console.WriteLine("RunnerServer.ConnectAsync: Create request connection"); + var createRequestConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60)); + await Task.WhenAll(createRequestConnection); + + // var createGenericConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100)); + // var createMessageConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60)); + // var createRequestConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60)); + + // await Task.WhenAll(createGenericConnection, createMessageConnection, createRequestConnection); _genericConnection = await createGenericConnection; _messageConnection = await createMessageConnection; @@ -182,6 +194,8 @@ namespace GitHub.Runner.Common private async Task EstablishVssConnection(Uri serverUrl, VssCredentials credentials, TimeSpan timeout) { + // System.Console.WriteLine("EstablishVssConnection"); + Trace.Info($"EstablishVssConnection"); Trace.Info($"Establish connection with {timeout.TotalSeconds} seconds timeout."); int attemptCount = 5; while (attemptCount-- > 0) @@ -238,41 +252,48 @@ namespace GitHub.Runner.Common public Task> GetAgentPoolsAsync(string agentPoolName = null, TaskAgentPoolType poolType = TaskAgentPoolType.Automation) { + // System.Console.WriteLine("RunnerServer.GetAgentPoolsAsync"); CheckConnection(RunnerConnectionType.Generic); return _genericTaskAgentClient.GetAgentPoolsAsync(agentPoolName, poolType: poolType); } public Task AddAgentAsync(Int32 agentPoolId, TaskAgent agent) { + // System.Console.WriteLine("RunnerServer.AddAgentAsync"); CheckConnection(RunnerConnectionType.Generic); return _genericTaskAgentClient.AddAgentAsync(agentPoolId, agent); } public Task> GetAgentsAsync(int agentPoolId, string agentName = null) { + // System.Console.WriteLine("RunnerServer.GetAgentsAsync 1"); CheckConnection(RunnerConnectionType.Generic); return _genericTaskAgentClient.GetAgentsAsync(agentPoolId, agentName, false); } public Task> GetAgentsAsync(string agentName) { + // System.Console.WriteLine("RunnerServer.GetAgentsAsync 2"); return GetAgentsAsync(0, agentName); // search in all all agentPools } public Task ReplaceAgentAsync(int agentPoolId, TaskAgent agent) { + // System.Console.WriteLine("RunnerServer.ReplaceAgentAsync"); CheckConnection(RunnerConnectionType.Generic); return _genericTaskAgentClient.ReplaceAgentAsync(agentPoolId, agent); } public Task DeleteAgentAsync(int agentPoolId, int agentId) { + // System.Console.WriteLine("RunnerServer.DeleteAgentAsync"); CheckConnection(RunnerConnectionType.Generic); return _genericTaskAgentClient.DeleteAgentAsync(agentPoolId, agentId); } public Task DeleteAgentAsync(int agentId) { + // System.Console.WriteLine("RunnerServer.DeleteAgentAsync"); return DeleteAgentAsync(0, agentId); // agentPool is ignored server side } @@ -282,24 +303,28 @@ namespace GitHub.Runner.Common public Task CreateAgentSessionAsync(Int32 poolId, TaskAgentSession session, CancellationToken cancellationToken) { + // System.Console.WriteLine("RunnerServer.CreateAgentSessionAsync"); CheckConnection(RunnerConnectionType.MessageQueue); return _messageTaskAgentClient.CreateAgentSessionAsync(poolId, session, cancellationToken: cancellationToken); } public Task DeleteAgentMessageAsync(Int32 poolId, Int64 messageId, Guid sessionId, CancellationToken cancellationToken) { + // System.Console.WriteLine("RunnerServer.DeleteAgentMessageAsync"); CheckConnection(RunnerConnectionType.MessageQueue); return _messageTaskAgentClient.DeleteMessageAsync(poolId, messageId, sessionId, cancellationToken: cancellationToken); } public Task DeleteAgentSessionAsync(Int32 poolId, Guid sessionId, CancellationToken cancellationToken) { + // System.Console.WriteLine("RunnerServer.DeleteAgentSessionAsync"); CheckConnection(RunnerConnectionType.MessageQueue); return _messageTaskAgentClient.DeleteAgentSessionAsync(poolId, sessionId, cancellationToken: cancellationToken); } public Task GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, CancellationToken cancellationToken) { + // System.Console.WriteLine("RunnerServer.GetAgentMessageAsync"); CheckConnection(RunnerConnectionType.MessageQueue); return _messageTaskAgentClient.GetMessageAsync(poolId, sessionId, lastMessageId, cancellationToken: cancellationToken); } @@ -310,18 +335,21 @@ namespace GitHub.Runner.Common public Task RenewAgentRequestAsync(int poolId, long requestId, Guid lockToken, string orchestrationId = null, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("RunnerServer.RenewAgentRequestAsync"); CheckConnection(RunnerConnectionType.JobRequest); return _requestTaskAgentClient.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId: orchestrationId, cancellationToken: cancellationToken); } - public Task FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken = default(CancellationToken)) + public Task FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, Guid targetHostId, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("RunnerServer.FinishAgentRequestAsync"); CheckConnection(RunnerConnectionType.JobRequest); - return _requestTaskAgentClient.FinishAgentRequestAsync(poolId, requestId, lockToken, finishTime, result, cancellationToken: cancellationToken); + return _requestTaskAgentClient.FinishAgentRequestAsync(poolId, requestId, lockToken, finishTime, result, targetHostId, cancellationToken: cancellationToken); } public Task GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("RunnerServer.GetAgentRequestAsync"); CheckConnection(RunnerConnectionType.JobRequest); return _requestTaskAgentClient.GetAgentRequestAsync(poolId, requestId, cancellationToken: cancellationToken); } @@ -331,18 +359,21 @@ namespace GitHub.Runner.Common //----------------------------------------------------------------- public Task> GetPackagesAsync(string packageType, string platform, int top, bool includeToken, CancellationToken cancellationToken) { + // System.Console.WriteLine("RunnerServer.GetPackagesAsync"); CheckConnection(RunnerConnectionType.Generic); return _genericTaskAgentClient.GetPackagesAsync(packageType, platform, top, includeToken, cancellationToken: cancellationToken); } public Task GetPackageAsync(string packageType, string platform, string version, bool includeToken, CancellationToken cancellationToken) { + // System.Console.WriteLine("RunnerServer.GetPackageAsync"); CheckConnection(RunnerConnectionType.Generic); return _genericTaskAgentClient.GetPackageAsync(packageType, platform, version, includeToken, cancellationToken: cancellationToken); } public Task UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState, string trace) { + // System.Console.WriteLine("RunnerServer.UpdateAgentUpdateStateAsync"); CheckConnection(RunnerConnectionType.Generic); return _genericTaskAgentClient.UpdateAgentUpdateStateAsync(agentPoolId, agentId, currentState, trace); } diff --git a/src/Runner.Listener/Configuration/CredentialManager.cs b/src/Runner.Listener/Configuration/CredentialManager.cs index e13d29510..adbd53452 100644 --- a/src/Runner.Listener/Configuration/CredentialManager.cs +++ b/src/Runner.Listener/Configuration/CredentialManager.cs @@ -40,6 +40,12 @@ namespace GitHub.Runner.Listener.Configuration return creds; } +#if USE_BROKER + public VssCredentials LoadCredentials() + { + return new VssCredentials(); + } +#else public VssCredentials LoadCredentials() { IConfigurationStore store = HostContext.GetService(); @@ -69,6 +75,7 @@ namespace GitHub.Runner.Listener.Configuration return creds; } +#endif } [DataContract] diff --git a/src/Runner.Listener/JobDispatcher.cs b/src/Runner.Listener/JobDispatcher.cs index 7913c9228..62791b181 100644 --- a/src/Runner.Listener/JobDispatcher.cs +++ b/src/Runner.Listener/JobDispatcher.cs @@ -23,7 +23,7 @@ namespace GitHub.Runner.Listener { bool Busy { get; } TaskCompletionSource RunOnceJobCompleted { get; } - void Run(Pipelines.AgentJobRequestMessage message, bool runOnce = false); + void Run(Guid targetHostId, Pipelines.AgentJobRequestMessage message, bool runOnce = false); bool Cancel(JobCancelMessage message); Task WaitAsync(CancellationToken token); Task ShutdownAsync(); @@ -79,7 +79,7 @@ namespace GitHub.Runner.Listener public bool Busy { get; private set; } - public void Run(Pipelines.AgentJobRequestMessage jobRequestMessage, bool runOnce = false) + public void Run(Guid targetHostId, Pipelines.AgentJobRequestMessage jobRequestMessage, bool runOnce = false) { Trace.Info($"Job request {jobRequestMessage.RequestId} for plan {jobRequestMessage.Plan.PlanId} job {jobRequestMessage.JobId} received."); @@ -112,11 +112,11 @@ namespace GitHub.Runner.Listener if (runOnce) { Trace.Info("Start dispatcher for one time used runner."); - newDispatch.WorkerDispatch = RunOnceAsync(jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token); + newDispatch.WorkerDispatch = RunOnceAsync(targetHostId, jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token); } else { - newDispatch.WorkerDispatch = RunAsync(jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token); + newDispatch.WorkerDispatch = RunAsync(targetHostId, jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token); } _jobInfos.TryAdd(newDispatch.JobId, newDispatch); @@ -317,11 +317,11 @@ namespace GitHub.Runner.Listener } } - private async Task RunOnceAsync(Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken) + private async Task RunOnceAsync(Guid targetHostId, Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken) { try { - await RunAsync(message, orchestrationId, previousJobDispatch, jobRequestCancellationToken, workerCancelTimeoutKillToken); + await RunAsync(targetHostId, message, orchestrationId, previousJobDispatch, jobRequestCancellationToken, workerCancelTimeoutKillToken); } finally { @@ -330,7 +330,7 @@ namespace GitHub.Runner.Listener } } - private async Task RunAsync(Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken) + private async Task RunAsync(Guid targetHostId, Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken) { Busy = true; try @@ -383,7 +383,7 @@ namespace GitHub.Runner.Listener await renewJobRequest; // complete job request with result Cancelled - await CompleteJobRequestAsync(_poolId, message, lockToken, TaskResult.Canceled); + await CompleteJobRequestAsync(targetHostId, _poolId, message, lockToken, TaskResult.Canceled); return; } @@ -540,7 +540,7 @@ namespace GitHub.Runner.Listener await renewJobRequest; // complete job request - await CompleteJobRequestAsync(_poolId, message, lockToken, result, detailInfo); + await CompleteJobRequestAsync(targetHostId, _poolId, message, lockToken, result, detailInfo); // print out unhandled exception happened in worker after we complete job request. // when we run out of disk space, report back to server has higher priority. @@ -637,7 +637,7 @@ namespace GitHub.Runner.Listener await renewJobRequest; // complete job request - await CompleteJobRequestAsync(_poolId, message, lockToken, resultOnAbandonOrCancel); + await CompleteJobRequestAsync(targetHostId, _poolId, message, lockToken, resultOnAbandonOrCancel); } finally { @@ -666,17 +666,25 @@ namespace GitHub.Runner.Listener { try { - request = await runnerServer.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId, token); - Trace.Info($"Successfully renew job request {requestId}, job is valid till {request.LockedUntil.Value}"); - +// #if USE_BROKER if (!firstJobRequestRenewed.Task.IsCompleted) { // fire first renew succeed event. firstJobRequestRenewed.TrySetResult(0); - - // Update settings if the runner name has been changed server-side - UpdateAgentNameIfNeeded(request.ReservedAgent?.Name); } +// #else +// request = await runnerServer.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId, token); +// Trace.Info($"Successfully renew job request {requestId}, job is valid till {request?.LockedUntil.Value}"); + +// if (!firstJobRequestRenewed.Task.IsCompleted) +// { +// // fire first renew succeed event. +// firstJobRequestRenewed.TrySetResult(0); + +// // Update settings if the runner name has been changed server-side +// UpdateAgentNameIfNeeded(request.ReservedAgent?.Name); +// } +// #endif if (encounteringError > 0) { @@ -911,7 +919,7 @@ namespace GitHub.Runner.Listener } } - private async Task CompleteJobRequestAsync(int poolId, Pipelines.AgentJobRequestMessage message, Guid lockToken, TaskResult result, string detailInfo = null) + private async Task CompleteJobRequestAsync(Guid targetHostId, int poolId, Pipelines.AgentJobRequestMessage message, Guid lockToken, TaskResult result, string detailInfo = null) { Trace.Entering(); @@ -928,7 +936,7 @@ namespace GitHub.Runner.Listener { try { - await runnerServer.FinishAgentRequestAsync(poolId, message.RequestId, lockToken, DateTime.UtcNow, result, CancellationToken.None); + await runnerServer.FinishAgentRequestAsync(poolId, message.RequestId, lockToken, DateTime.UtcNow, result, targetHostId, CancellationToken.None); return; } catch (TaskAgentJobNotFoundException) diff --git a/src/Runner.Listener/MessageListener.cs b/src/Runner.Listener/MessageListener.cs index 81afd737d..0dc561d5f 100644 --- a/src/Runner.Listener/MessageListener.cs +++ b/src/Runner.Listener/MessageListener.cs @@ -2,7 +2,11 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Runtime.InteropServices; +using System.Runtime.Serialization; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -27,10 +31,13 @@ namespace GitHub.Runner.Listener public sealed class MessageListener : RunnerService, IMessageListener { +#if !USE_BROKER private long? _lastMessageId; +#endif private RunnerSettings _settings; private ITerminal _term; private IRunnerServer _runnerServer; + private IBrokerServer _brokerServer; private TaskAgentSession _session; private TimeSpan _getNextMessageRetryInterval; private bool _accessTokenRevoked = false; @@ -45,8 +52,44 @@ namespace GitHub.Runner.Listener _term = HostContext.GetService(); _runnerServer = HostContext.GetService(); + _brokerServer = HostContext.GetService(); } +#if USE_BROKER + public async Task CreateSessionAsync(CancellationToken token) + { + Trace.Entering(); + + // Settings + var configManager = HostContext.GetService(); + _settings = configManager.LoadSettings(); + var serverUrl = _settings.ServerUrl; + Trace.Info(_settings); + + // Connect + token.ThrowIfCancellationRequested(); + Trace.Info($"Attempt to create session."); + Trace.Info("Connecting to the Runner Server..."); + _term.WriteLine($"Connecting to {new Uri(serverUrl)}"); + await _brokerServer.ConnectAsync(new Uri(serverUrl), token); + _term.WriteLine(); + _term.WriteSuccessMessage("Connected to GitHub"); + _term.WriteLine(); + + // Session info + var agent = new TaskAgentReference + { + Id = _settings.AgentId, + Name = _settings.AgentName, + Version = BuildConstants.RunnerPackage.Version, + OSDescription = RuntimeInformation.OSDescription, + }; + string sessionName = $"{Environment.MachineName ?? "RUNNER"}"; + _session = new TaskAgentSession(sessionName, agent); + + return true; + } +#else public async Task CreateSessionAsync(CancellationToken token) { Trace.Entering(); @@ -81,6 +124,7 @@ namespace GitHub.Runner.Listener Trace.Info($"Attempt to create session."); try { + Trace.Info("Connecting to the Runner Server..."); Trace.Info("Connecting to the Runner Server..."); await _runnerServer.ConnectAsync(new Uri(serverUrl), creds); Trace.Info("VssConnection created"); @@ -151,6 +195,7 @@ namespace GitHub.Runner.Listener } } } +#endif public async Task DeleteSessionAsync() { @@ -170,6 +215,167 @@ namespace GitHub.Runner.Listener } } +#if USE_BROKER + [DataContract] + public sealed class MessageRef + { + [DataMember(Name = "url")] + public string Url { get; set; } + [DataMember(Name = "token")] + public string Token { get; set; } + [DataMember(Name = "scopeId")] + public string ScopeId { get; set; } + [DataMember(Name = "planType")] + public string PlanType { get; set; } + [DataMember(Name = "planGroup")] + public string PlanGroup { get; set; } + [DataMember(Name = "instanceRefs")] + public InstanceRef[] InstanceRefs { get; set; } + [DataMember(Name = "labels")] + public string[] Labels { get; set; } + } + + [DataContract] + public sealed class InstanceRef + { + [DataMember(Name = "name")] + public string Name { get; set; } + [DataMember(Name = "instanceType")] + public string InstanceType { get; set; } + [DataMember(Name = "attempt")] + public int Attempt { get; set; } + } + + public async Task GetNextMessageAsync(CancellationToken token) + { + Trace.Entering(); + ArgUtil.NotNull(_session, nameof(_session)); + ArgUtil.NotNull(_settings, nameof(_settings)); + bool encounteringError = false; + int continuousError = 0; + string errorMessage = string.Empty; + Stopwatch heartbeat = new Stopwatch(); + heartbeat.Restart(); + while (true) + { + token.ThrowIfCancellationRequested(); + string message = null; + try + { + message = await _brokerServer.GetMessageAsync(_session, _settings, null/*_lastMessageId*/, token); + _term.WriteLine($"{DateTime.UtcNow:u}: {message}"); + if (!string.IsNullOrEmpty(message)) + { + var messageRef = StringUtil.ConvertFromJson(message); + var client = new HttpClient(); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", messageRef.Token); + var response = await client.GetAsync(messageRef.Url, token); + if (!response.IsSuccessStatusCode) + { + var content = default(string); + try + { + content = await response.Content.ReadAsStringAsync(); + } + catch + { + } + + var error = $"HTTP {(int)response.StatusCode} {Enum.GetName(typeof(HttpStatusCode), response.StatusCode)}"; + if (!string.IsNullOrEmpty(content)) + { + error = $"{error}: {content}"; + } + throw new Exception(error); + } + + var fullMessage = await response.Content.ReadAsStringAsync(); + return StringUtil.ConvertFromJson(fullMessage); + } + + if (encounteringError) //print the message once only if there was an error + { + _term.WriteLine($"{DateTime.UtcNow:u}: Runner reconnected."); + encounteringError = false; + continuousError = 0; + } + } + catch (OperationCanceledException) when (token.IsCancellationRequested) + { + Trace.Info("Get next message has been cancelled."); + throw; + } + catch (TaskAgentAccessTokenExpiredException) + { + Trace.Info("Runner OAuth token has been revoked. Unable to pull message."); + _accessTokenRevoked = true; + throw; + } + catch (Exception ex) + { + Trace.Error("Catch exception during get next message."); + Trace.Error(ex); + + // don't retry if SkipSessionRecover = true, DT service will delete agent session to stop agent from taking more jobs. + if (ex is TaskAgentSessionExpiredException && !_settings.SkipSessionRecover && await CreateSessionAsync(token)) + { + Trace.Info($"{nameof(TaskAgentSessionExpiredException)} received, recovered by recreate session."); + } + else if (!IsGetNextMessageExceptionRetriable(ex)) + { + throw; + } + else + { + continuousError++; + //retry after a random backoff to avoid service throttling + //in case of there is a service error happened and all agents get kicked off of the long poll and all agent try to reconnect back at the same time. + if (continuousError <= 5) + { + // random backoff [15, 30] + _getNextMessageRetryInterval = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30), _getNextMessageRetryInterval); + } + else + { + // more aggressive backoff [30, 60] + _getNextMessageRetryInterval = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(60), _getNextMessageRetryInterval); + } + + if (!encounteringError) + { + //print error only on the first consecutive error + _term.WriteError($"{DateTime.UtcNow:u}: Runner connect error: {ex.Message}. Retrying until reconnected."); + encounteringError = true; + } + + // re-create VssConnection before next retry + await _runnerServer.RefreshConnectionAsync(RunnerConnectionType.MessageQueue, TimeSpan.FromSeconds(60)); + + Trace.Info("Sleeping for {0} seconds before retrying.", _getNextMessageRetryInterval.TotalSeconds); + await HostContext.Delay(_getNextMessageRetryInterval, token); + } + } + + // if (message == null) + // { + // if (heartbeat.Elapsed > TimeSpan.FromMinutes(30)) + // { + // Trace.Info($"No message retrieved from session '{_session.SessionId}' within last 30 minutes."); + // heartbeat.Restart(); + // } + // else + // { + // Trace.Verbose($"No message retrieved from session '{_session.SessionId}'."); + // } + + // continue; + // } + + // Trace.Info($"Message '{message.MessageId}' received from session '{_session.SessionId}'."); + // return message; + } + } +#else public async Task GetNextMessageAsync(CancellationToken token) { Trace.Entering(); @@ -281,6 +487,7 @@ namespace GitHub.Runner.Listener return message; } } +#endif public async Task DeleteMessageAsync(TaskAgentMessage message) { diff --git a/src/Runner.Listener/Runner.cs b/src/Runner.Listener/Runner.cs index 5ef0a3d64..c48060bb7 100644 --- a/src/Runner.Listener/Runner.cs +++ b/src/Runner.Listener/Runner.cs @@ -13,6 +13,10 @@ using GitHub.Runner.Sdk; using System.Linq; using GitHub.Runner.Listener.Check; using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; namespace GitHub.Runner.Listener { @@ -449,7 +453,37 @@ namespace GitHub.Runner.Listener { Trace.Info($"Received job message of length {message.Body.Length} from service, with hash '{IOUtil.GetSha256Hash(message.Body)}'"); var jobMessage = StringUtil.ConvertFromJson(message.Body); - jobDispatcher.Run(jobMessage, runOnce); + jobDispatcher.Run(Guid.Empty, jobMessage, runOnce); + if (runOnce) + { + Trace.Info("One time used runner received job message."); + runOnceJobReceived = true; + } + } + } + // Broker flow + else if (string.Equals(message.MessageType, JobRequestMessageTypes.RunnerJobRequest, StringComparison.OrdinalIgnoreCase)) + { + if (autoUpdateInProgress || runOnceJobReceived) + { + skipMessageDeletion = true; + Trace.Info($"Skip message deletion for job request message '{message.MessageId}'."); + } + else + { + var messageRef = StringUtil.ConvertFromJson(message.Body); + + // Create connection + var credMgr = HostContext.GetService(); + var creds = credMgr.LoadCredentials(); + + // todo: add retries + var runServer = HostContext.CreateService(); + await runServer.ConnectAsync(new Uri(settings.ServerUrl), creds); + var jobMessage = await runServer.GetJobMessageAsync(messageRef.ScopeId, messageRef.HostId, messageRef.PlanType, messageRef.PlanGroup, messageRef.PlanId, messageRef.InstanceRefs); + + // todo: Trace.Info($"Received job message of length {message.Body.Length} from service, with hash '{IOUtil.GetSha256Hash(message.Body)}'"); + jobDispatcher.Run(messageRef.HostId, jobMessage, runOnce); if (runOnce) { Trace.Info("One time used runner received job message."); diff --git a/src/Runner.Sdk/Util/VssUtil.cs b/src/Runner.Sdk/Util/VssUtil.cs index e6b6f9f83..f163c54c9 100644 --- a/src/Runner.Sdk/Util/VssUtil.cs +++ b/src/Runner.Sdk/Util/VssUtil.cs @@ -36,6 +36,7 @@ namespace GitHub.Runner.Sdk public static VssConnection CreateConnection(Uri serverUri, VssCredentials credentials, IEnumerable additionalDelegatingHandler = null, TimeSpan? timeout = null) { + // System.Console.WriteLine("VssUtil.CreateConnection"); VssClientHttpRequestSettings settings = VssClientHttpRequestSettings.Default.Clone(); int maxRetryRequest; diff --git a/src/Runner.Worker/ActionManager.cs b/src/Runner.Worker/ActionManager.cs index 954d9a691..54a49814d 100644 --- a/src/Runner.Worker/ActionManager.cs +++ b/src/Runner.Worker/ActionManager.cs @@ -817,6 +817,7 @@ namespace GitHub.Runner.Worker { // Something else bad happened, let's go to our retry logic response.EnsureSuccessStatusCode(); + throw new Exception("Unexpected response code: " + response.StatusCode); } } } diff --git a/src/Sdk/Common/Common/Authentication/FederatedCredential.cs b/src/Sdk/Common/Common/Authentication/FederatedCredential.cs index 2a03c63bb..4beb49852 100644 --- a/src/Sdk/Common/Common/Authentication/FederatedCredential.cs +++ b/src/Sdk/Common/Common/Authentication/FederatedCredential.cs @@ -18,6 +18,7 @@ namespace GitHub.Services.Common public override bool IsAuthenticationChallenge(IHttpResponse webResponse) { + // System.Console.WriteLine($"FederatedCredential.IsAuthenticationChallenge"); if (webResponse == null) { return false; diff --git a/src/Sdk/Common/Common/Authentication/IssuedTokenCredential.cs b/src/Sdk/Common/Common/Authentication/IssuedTokenCredential.cs index 1bed7d720..9697a3de5 100644 --- a/src/Sdk/Common/Common/Authentication/IssuedTokenCredential.cs +++ b/src/Sdk/Common/Common/Authentication/IssuedTokenCredential.cs @@ -88,6 +88,7 @@ namespace GitHub.Services.Common IHttpResponse response, IssuedToken failedToken) { + // System.Console.WriteLine("IssuedTokenCredential.CreateTokenProvider"); if (response != null && !IsAuthenticationChallenge(response)) { throw new InvalidOperationException(); @@ -99,12 +100,14 @@ namespace GitHub.Services.Common { throw new InvalidOperationException($"The {nameof(TokenStorageUrl)} property must have a value if the {nameof(Storage)} property is set on this instance of {GetType().Name}."); } + // System.Console.WriteLine($"IssuedTokenCredential.CreateTokenProvider: TokenStorageUrl: {TokenStorageUrl}"); InitialToken = Storage.RetrieveToken(TokenStorageUrl, CredentialType); } IssuedTokenProvider provider = OnCreateTokenProvider(serverUrl, response); if (provider != null) { + // System.Console.WriteLine($"IssuedTokenCredential.CreateTokenProvider: provider: {provider}"); provider.TokenStorageUrl = TokenStorageUrl; } @@ -123,6 +126,7 @@ namespace GitHub.Services.Common internal virtual string GetAuthenticationChallenge(IHttpResponse webResponse) { + // System.Console.WriteLine($"IssuedTokenCredential.GetAuthenticationChallenge"); IEnumerable values; if (!webResponse.Headers.TryGetValues(Internal.HttpHeaders.WwwAuthenticate, out values)) { diff --git a/src/Sdk/Common/Common/Authentication/VssCredentials.cs b/src/Sdk/Common/Common/Authentication/VssCredentials.cs index c29c5fa31..35bbb44df 100644 --- a/src/Sdk/Common/Common/Authentication/VssCredentials.cs +++ b/src/Sdk/Common/Common/Authentication/VssCredentials.cs @@ -108,6 +108,7 @@ namespace GitHub.Services.Common TaskScheduler scheduler, IVssCredentialPrompt credentialPrompt) { + // System.Console.WriteLine($"VssCredentials.ctor"); this.PromptType = promptType; if (promptType == CredentialPromptType.PromptIfNeeded && scheduler == null) @@ -150,6 +151,7 @@ namespace GitHub.Services.Common { get { + // System.Console.WriteLine($"VssCredentials.get_PromptType"); return m_promptType; } set @@ -170,6 +172,7 @@ namespace GitHub.Services.Common { get { + // System.Console.WriteLine($"VssCredentials.get_Federated"); return m_federatedCredential; } } @@ -184,6 +187,7 @@ namespace GitHub.Services.Common { get { + // System.Console.WriteLine($"VssCredentials.get_Storage"); return m_credentialStorage; } set @@ -203,6 +207,7 @@ namespace GitHub.Services.Common /// internal virtual bool TryGetValidAdalToken(IVssCredentialPrompt prompt) { + // System.Console.WriteLine($"VssCredentials.TryGetValidAdalToken"); return false; } @@ -218,6 +223,7 @@ namespace GitHub.Services.Common IHttpResponse webResponse, IssuedToken failedToken) { + // System.Console.WriteLine("VssCredential.CreateTokenProvider"); ArgumentUtility.CheckForNull(serverUrl, "serverUrl"); IssuedTokenProvider tokenProvider = null; @@ -263,6 +269,7 @@ namespace GitHub.Services.Common Uri serverUrl, out IssuedTokenProvider provider) { + // System.Console.WriteLine($"VssCredentials.TryGetTokenProvider"); ArgumentUtility.CheckForNull(serverUrl, "serverUrl"); lock (m_thisLock) @@ -272,11 +279,13 @@ namespace GitHub.Services.Common { if (m_federatedCredential != null) { + // System.Console.WriteLine($"VssCredentials.TryGetTokenProvider: Using federated credential"); m_currentProvider = m_federatedCredential.CreateTokenProvider(serverUrl, null, null); } if (m_currentProvider != null) { + // System.Console.WriteLine($"VssCredentials.TryGetTokenProvider: Issued token provider created"); VssHttpEventSource.Log.IssuedTokenProviderCreated(VssTraceActivity.Current, m_currentProvider); } } @@ -294,6 +303,7 @@ namespace GitHub.Services.Common /// True if this is an token authentication redirect, false otherwise internal bool IsAuthenticationChallenge(IHttpResponse webResponse) { + // System.Console.WriteLine($"VssCredentials.IsAuthenticationChallenge"); if (webResponse == null) { return false; @@ -313,6 +323,7 @@ namespace GitHub.Services.Common Uri serviceLocation, string identityProvider) { + // System.Console.WriteLine($"VssCredentials.SignOut"); // Remove the token in the storage and the current token provider. Note that we don't // call InvalidateToken here because we want to remove the whole token not just its value if ((m_currentProvider != null) && (m_currentProvider.CurrentToken != null)) @@ -349,6 +360,7 @@ namespace GitHub.Services.Common string token, IDictionary attributes) { + // System.Console.WriteLine($"VssCredentials.WriteAuthorizationToken"); int i = 0; for (int j = 0; j < token.Length; i++, j += 128) { @@ -360,6 +372,7 @@ namespace GitHub.Services.Common protected static string ReadAuthorizationToken(IDictionary attributes) { + // System.Console.WriteLine($"VssCredentials.ReadAuthorizationToken"); string authTokenCountValue; if (attributes.TryGetValue("AuthTokenSegmentCount", out authTokenCountValue)) { diff --git a/src/Sdk/Common/Common/VssHttpMessageHandler.cs b/src/Sdk/Common/Common/VssHttpMessageHandler.cs index 84ac561a1..61c1de6f8 100644 --- a/src/Sdk/Common/Common/VssHttpMessageHandler.cs +++ b/src/Sdk/Common/Common/VssHttpMessageHandler.cs @@ -49,6 +49,7 @@ namespace GitHub.Services.Common VssHttpRequestSettings settings, HttpMessageHandler innerHandler) { + // System.Console.WriteLine("VssHttpMessageHandler.ctor"); this.Credentials = credentials; this.Settings = settings; this.ExpectContinue = settings.ExpectContinue; @@ -122,6 +123,7 @@ namespace GitHub.Services.Common HttpRequestMessage request, CancellationToken cancellationToken) { + // System.Console.WriteLine("VssHttpMessageHandler.SendAsync"); VssTraceActivity traceActivity = VssTraceActivity.Current; var traceInfo = VssHttpMessageHandlerTraceInfo.GetTraceInfo(request); @@ -130,6 +132,7 @@ namespace GitHub.Services.Common if (!m_appliedClientCertificatesToTransportHandler && request.RequestUri.Scheme == "https") { + // System.Console.WriteLine("VssHttpMessageHandler.SendAsync: !appliedClientCertificatesToTransportHandler"); HttpClientHandler httpClientHandler = m_transportHandler as HttpClientHandler; if (httpClientHandler != null && this.Settings.ClientCertificateManager != null && @@ -144,6 +147,7 @@ namespace GitHub.Services.Common if (!m_appliedServerCertificateValidationCallbackToTransportHandler && request.RequestUri.Scheme == "https") { + // System.Console.WriteLine("VssHttpMessageHandler.SendAsync: !appliedServerCertificateValidationCallbackToTransportHandler"); HttpClientHandler httpClientHandler = m_transportHandler as HttpClientHandler; if (httpClientHandler != null && this.Settings.ServerCertificateValidationCallback != null) @@ -165,6 +169,7 @@ namespace GitHub.Services.Common IssuedTokenProvider provider; if (this.Credentials.TryGetTokenProvider(request.RequestUri, out provider)) { + // System.Console.WriteLine("VssHttpMessageHandler.SendAsync: Got token provider from credentials"); token = provider.CurrentToken; } @@ -225,6 +230,7 @@ namespace GitHub.Services.Common traceInfo?.TraceResponseContentTime(); + // System.Console.WriteLine($"VssHttpMessageHandler.SendAsync: Creating response wrapper"); responseWrapper = new HttpResponseMessageWrapper(response); if (!this.Credentials.IsAuthenticationChallenge(responseWrapper)) @@ -232,6 +238,7 @@ namespace GitHub.Services.Common // Validate the token after it has been successfully authenticated with the server. if (provider != null) { + // System.Console.WriteLine("VssHttpMessageHandler.SendAsync: Validating token"); provider.ValidateToken(token, responseWrapper); } @@ -243,6 +250,7 @@ namespace GitHub.Services.Common } else { + // System.Console.WriteLine($"VssHttpMessageHandler.SendAsync: Auth challenge. Response status code {response.StatusCode}; headers {response.Headers}"); // In the case of a Windows token, only apply it to the web proxy if it // returned a 407 Proxy Authentication Required. If we didn't get this // status code back, then the proxy (if there is one) is clearly working fine, @@ -288,6 +296,7 @@ namespace GitHub.Services.Common } // Now invoke the provider and await the result + // System.Console.WriteLine($"VssHttpMessageHandler.SendAsync: Calling GetTokenAsync"); token = await provider.GetTokenAsync(token, tokenSource.Token).ConfigureAwait(false); // I always see 0 here, but the method above could take more time so keep for now @@ -432,6 +441,7 @@ namespace GitHub.Services.Common activity != VssTraceActivity.Empty && !request.Headers.Contains(HttpHeaders.TfsSessionHeader)) { + // System.Console.WriteLine($"VssHttpMessageHandler.ApplyHeaders: Activity ID {activity.Id}"); request.Headers.Add(HttpHeaders.TfsSessionHeader, activity.Id.ToString("D")); } @@ -452,13 +462,16 @@ namespace GitHub.Services.Common ICredentials credentialsToken = token as ICredentials; if (credentialsToken != null) { + // System.Console.WriteLine("VssHttpMessageHandler.ApplyToken: Credentials token != null"); if (applyICredentialsToWebProxy) { + // System.Console.WriteLine("VssHttpMessageHandler.ApplyToken: Apply credentials to web proxy"); HttpClientHandler httpClientHandler = m_transportHandler as HttpClientHandler; if (httpClientHandler != null && httpClientHandler.Proxy != null) { + // System.Console.WriteLine("VssHttpMessageHandler.ApplyToken: Setting proxy crednetials"); httpClientHandler.Proxy.Credentials = credentialsToken; } } @@ -467,6 +480,7 @@ namespace GitHub.Services.Common } else { + // System.Console.WriteLine("VssHttpMessageHandler.ApplyToken: Applying credentials to request"); token.ApplyTo(new HttpRequestMessageWrapper(request)); } } @@ -479,7 +493,8 @@ namespace GitHub.Services.Common HttpClientHandler httpClientHandler = handler as HttpClientHandler; if (httpClientHandler != null) { - httpClientHandler.AllowAutoRedirect = settings.AllowAutoRedirect; + // System.Console.WriteLine($"VssHttpMessageHandler.ApplySettings: Default credentials = {defaultCredentials} AllowAutoRedirect = {settings.AllowAutoRedirect}"); + httpClientHandler.AllowAutoRedirect = true; //settings.AllowAutoRedirect; httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual; //Setting httpClientHandler.UseDefaultCredentials to false in .Net Core, clears httpClientHandler.Credentials if //credentials is already set to defaultcredentials. Therefore httpClientHandler.Credentials must be @@ -550,6 +565,7 @@ namespace GitHub.Services.Common Uri uri, String authType) { + // System.Console.WriteLine($"CredentialWrapper.GetCredential: InnerCredentials = {InnerCredentials}"); return InnerCredentials != null ? InnerCredentials.GetCredential(uri, authType) : null; } } diff --git a/src/Sdk/DTGenerated/Generated/TaskAgentHttpClientBase.cs b/src/Sdk/DTGenerated/Generated/TaskAgentHttpClientBase.cs index 29fe07c0d..763aa9bf8 100644 --- a/src/Sdk/DTGenerated/Generated/TaskAgentHttpClientBase.cs +++ b/src/Sdk/DTGenerated/Generated/TaskAgentHttpClientBase.cs @@ -27,6 +27,7 @@ using System.Net.Http.Headers; using System.Net.Http.Formatting; using System.Threading; using System.Threading.Tasks; +using GitHub.DistributedTask.Pipelines; using GitHub.Services.Common; using GitHub.Services.WebApi; @@ -378,6 +379,7 @@ namespace GitHub.DistributedTask.WebApi /// /// /// + /// /// /// The cancellation token to cancel operation. [EditorBrowsable(EditorBrowsableState.Never)] @@ -386,6 +388,7 @@ namespace GitHub.DistributedTask.WebApi long requestId, Guid lockToken, TaskAgentJobRequest request, + Guid targetHostId, object userState = null, CancellationToken cancellationToken = default) { @@ -396,6 +399,7 @@ namespace GitHub.DistributedTask.WebApi List> queryParams = new List>(); queryParams.Add("lockToken", lockToken.ToString()); + queryParams.Add("targetHostId", targetHostId.ToString()); return SendAsync( httpMethod, @@ -703,6 +707,47 @@ namespace GitHub.DistributedTask.WebApi cancellationToken: cancellationToken); } + /// + /// [Preview API] + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token to cancel operation. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Task GetJobMessageAsync( + Guid scopeId, + Guid hostId, + string planType, + string planGroup, + Guid planId, + string instanceRefsJson, + object userState = null, + CancellationToken cancellationToken = default) + { + HttpMethod httpMethod = new HttpMethod("GET"); + Guid locationId = new Guid("25adab70-1379-4186-be8e-b643061ebe3a"); + + List> queryParams = new List>(); + queryParams.Add("scopeId", scopeId.ToString()); + queryParams.Add("hostId", hostId.ToString()); + queryParams.Add("planType", planType); + queryParams.Add("planGroup", planGroup); + queryParams.Add("planId", planId.ToString()); + queryParams.Add("instanceRefsJson", instanceRefsJson); + + return SendAsync( + httpMethod, + locationId, + version: new ApiResourceVersion(6.0, 1), + queryParameters: queryParams, + userState: userState, + cancellationToken: cancellationToken); + } + /// /// [Preview API] /// @@ -717,6 +762,7 @@ namespace GitHub.DistributedTask.WebApi object userState = null, CancellationToken cancellationToken = default) { + // System.Console.WriteLine("TaskAgentHttpClientBase.CreateAgentSessionAsync"); HttpMethod httpMethod = new HttpMethod("POST"); Guid locationId = new Guid("134e239e-2df3-4794-a6f6-24f1f19ec8dc"); object routeValues = new { poolId = poolId }; diff --git a/src/Sdk/DTWebApi/WebApi/JobRequestMessageTypes.cs b/src/Sdk/DTWebApi/WebApi/JobRequestMessageTypes.cs index 326473750..c2f3a87ee 100644 --- a/src/Sdk/DTWebApi/WebApi/JobRequestMessageTypes.cs +++ b/src/Sdk/DTWebApi/WebApi/JobRequestMessageTypes.cs @@ -5,5 +5,6 @@ namespace GitHub.DistributedTask.WebApi public static class JobRequestMessageTypes { public const String PipelineAgentJobRequest = "PipelineAgentJobRequest"; + public const String RunnerJobRequest = "RunnerJobRequest"; } } diff --git a/src/Sdk/DTWebApi/WebApi/TaskAgentHttpClient.cs b/src/Sdk/DTWebApi/WebApi/TaskAgentHttpClient.cs index c97fea0a4..e21687329 100644 --- a/src/Sdk/DTWebApi/WebApi/TaskAgentHttpClient.cs +++ b/src/Sdk/DTWebApi/WebApi/TaskAgentHttpClient.cs @@ -64,6 +64,7 @@ namespace GitHub.DistributedTask.WebApi Guid lockToken, DateTime finishTime, TaskResult result, + Guid targetHostId, Object userState = null, CancellationToken cancellationToken = default(CancellationToken)) { @@ -74,7 +75,7 @@ namespace GitHub.DistributedTask.WebApi Result = result, }; - return UpdateAgentRequestAsync(poolId, requestId, lockToken, request, userState, cancellationToken); + return UpdateAgentRequestAsync(poolId, requestId, lockToken, request, targetHostId, userState, cancellationToken); } public Task> GetAgentsAsync( @@ -152,6 +153,7 @@ namespace GitHub.DistributedTask.WebApi CancellationToken cancellationToken = default(CancellationToken), Func> processResponse = null) { + // System.Console.WriteLine("TaskAgentHttpClient.SendAsync 1"); return SendAsync(method, null, locationId, routeValues, version, content, queryParameters, userState, cancellationToken, processResponse); } @@ -170,6 +172,7 @@ namespace GitHub.DistributedTask.WebApi using (VssTraceActivity.GetOrCreate().EnterCorrelationScope()) using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, additionalHeaders, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false)) { + // System.Console.WriteLine("TaskAgentHttpClient.SendAsync 2"); return await SendAsync(requestMessage, userState, cancellationToken, processResponse).ConfigureAwait(false); } } @@ -180,6 +183,7 @@ namespace GitHub.DistributedTask.WebApi CancellationToken cancellationToken = default(CancellationToken), Func> processResponse = null) { + // System.Console.WriteLine("TaskAgentHttpClient.SendAsync 3"); if (processResponse == null) { processResponse = ReadContentAsAsync; diff --git a/src/Sdk/WebApi/WebApi/Location/ServerDataProvider.cs b/src/Sdk/WebApi/WebApi/Location/ServerDataProvider.cs index 7cbcd80c9..f1b7800cc 100644 --- a/src/Sdk/WebApi/WebApi/Location/ServerDataProvider.cs +++ b/src/Sdk/WebApi/WebApi/Location/ServerDataProvider.cs @@ -801,6 +801,7 @@ namespace GitHub.Services.WebApi.Location private async Task GetConnectionDataAsync(ConnectOptions connectOptions, int lastChangeId, CancellationToken cancellationToken) { + // System.Console.WriteLine("ServerDataProvider.GetConnectionDataAsync"); int timeoutRetries = 1; while (true) diff --git a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthAccessToken.cs b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthAccessToken.cs index 530d4c4d9..7dbd0d6ed 100644 --- a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthAccessToken.cs +++ b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthAccessToken.cs @@ -75,6 +75,7 @@ namespace GitHub.Services.OAuth internal override void ApplyTo(IHttpRequest request) { + // System.Console.WriteLine($"VssOAuthAccessToken.ApplyTo: Bearer {m_value}"); request.Headers.SetValue(Common.Internal.HttpHeaders.Authorization, $"Bearer {m_value}"); } diff --git a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthAccessTokenCredential.cs b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthAccessTokenCredential.cs index 03cf0c012..7bbe68a96 100644 --- a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthAccessTokenCredential.cs +++ b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthAccessTokenCredential.cs @@ -60,6 +60,7 @@ namespace GitHub.Services.OAuth Uri serverUrl, IHttpResponse response) { + // System.Console.WriteLine($"VssOAuthAccessTokenCredential.OnCreateTokenProvider"); return new VssOAuthAccessTokenProvider(this, serverUrl, null); } @@ -71,6 +72,7 @@ namespace GitHub.Services.OAuth Uri signInUrl) : base(credential, serverUrl, signInUrl) { + // System.Console.WriteLine($"VssOAuthAccessTokenProvider.ctor"); } public override Boolean GetTokenIsInteractive diff --git a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthCredential.cs b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthCredential.cs index b5c4ea5c1..b85e9870a 100644 --- a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthCredential.cs +++ b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthCredential.cs @@ -103,17 +103,23 @@ namespace GitHub.Services.OAuth /// True if the web response indicates an authorization challenge; otherwise, false public override Boolean IsAuthenticationChallenge(IHttpResponse webResponse) { + // System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge"); if (webResponse == null) { + // System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge: webResponse is null"); return false; } if (webResponse.StatusCode == HttpStatusCode.Found || webResponse.StatusCode == HttpStatusCode.Unauthorized) { - return webResponse.Headers.GetValues(Common.Internal.HttpHeaders.WwwAuthenticate).Any(x => x.IndexOf("Bearer", StringComparison.OrdinalIgnoreCase) >= 0); + // System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge: found or unauthorized"); + var result = webResponse.Headers.GetValues(Common.Internal.HttpHeaders.WwwAuthenticate).Any(x => x.IndexOf("Bearer", StringComparison.OrdinalIgnoreCase) >= 0); + // System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge: {result}"); + return result; } + // System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge: false"); return false; } @@ -121,6 +127,7 @@ namespace GitHub.Services.OAuth Uri serverUrl, IHttpResponse response) { + // System.Console.WriteLine($"VssOAuthCredential.OnCreateTokenProvider"); return new VssOAuthTokenProvider(this, serverUrl); } diff --git a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthTokenHttpClient.cs b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthTokenHttpClient.cs index 994675e41..27ec89e09 100644 --- a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthTokenHttpClient.cs +++ b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthTokenHttpClient.cs @@ -54,6 +54,7 @@ namespace GitHub.Services.OAuth VssOAuthTokenParameters tokenParameters = null, CancellationToken cancellationToken = default(CancellationToken)) { + // todo: qqq VssTraceActivity traceActivity = VssTraceActivity.Current; using (HttpClient client = new HttpClient(CreateMessageHandler(this.AuthorizationUrl))) { diff --git a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthTokenProvider.cs b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthTokenProvider.cs index 84122a494..6acf83937 100644 --- a/src/Sdk/WebApi/WebApi/OAuth/VssOAuthTokenProvider.cs +++ b/src/Sdk/WebApi/WebApi/OAuth/VssOAuthTokenProvider.cs @@ -47,6 +47,7 @@ namespace GitHub.Services.OAuth VssOAuthTokenParameters tokenParameters) : base(credential, serverUrl, authorizationUrl) { + // System.Console.WriteLine($"VssOAuthTokenProvider.ctor"); m_grant = grant; m_tokenParameters = tokenParameters; m_clientCredential = clientCrential; @@ -59,6 +60,7 @@ namespace GitHub.Services.OAuth { get { + // System.Console.WriteLine($"VssOAuthTokenProvider.get_Grant"); return m_grant; } } @@ -70,6 +72,7 @@ namespace GitHub.Services.OAuth { get { + // System.Console.WriteLine($"VssOAuthTokenProvider.get_ClientCredential"); return m_clientCredential; } } @@ -81,6 +84,7 @@ namespace GitHub.Services.OAuth { get { + // System.Console.WriteLine($"VssOAuthTokenProvider.get_TokenParameters"); return m_tokenParameters; } } @@ -92,6 +96,7 @@ namespace GitHub.Services.OAuth { get { + // System.Console.WriteLine($"VssOAuthTokenProvider.get_GetTokenIsInteractive"); return false; } } @@ -100,6 +105,7 @@ namespace GitHub.Services.OAuth { get { + // System.Console.WriteLine($"VssOAuthTokenProvider.get_AuthenticationParameter"); if (this.ClientCredential == null) { return null; @@ -115,12 +121,14 @@ namespace GitHub.Services.OAuth { get { + // System.Console.WriteLine($"VssOAuthTokenProvider.get_AuthenticationScheme"); return "Bearer"; } } public async Task ValidateCredentialAsync(CancellationToken cancellationToken) { + // System.Console.WriteLine($"VssOAuthTokenProvider.ValidateCredentialAsync: Calling VssOAuthTokenHttpClient.GetTokenAsync"); var tokenHttpClient = new VssOAuthTokenHttpClient(this.SignInUrl); var tokenResponse = await tokenHttpClient.GetTokenAsync(this.Grant, this.ClientCredential, this.TokenParameters, cancellationToken); @@ -139,6 +147,7 @@ namespace GitHub.Services.OAuth IssuedToken failedToken, CancellationToken cancellationToken) { + // System.Console.WriteLine($"VssOAuthTokenProvider.OnGetTokenAsync"); if (this.SignInUrl == null || this.Grant == null || this.ClientCredential == null) @@ -151,6 +160,7 @@ namespace GitHub.Services.OAuth try { var tokenHttpClient = new VssOAuthTokenHttpClient(this.SignInUrl); + // System.Console.WriteLine($"VssOAuthTokenProvider.OnGetTokenAsync: Calling VssOAuthTokenHttpClient.GetTokenAsync; sign-in url {this.SignInUrl.AbsoluteUri}"); var tokenResponse = await tokenHttpClient.GetTokenAsync(this.Grant, this.ClientCredential, this.TokenParameters, cancellationToken).ConfigureAwait(false); if (!String.IsNullOrEmpty(tokenResponse.AccessToken)) { @@ -197,6 +207,7 @@ namespace GitHub.Services.OAuth protected virtual IssuedToken CreateIssuedToken(VssOAuthTokenResponse tokenResponse) { + // System.Console.WriteLine($"VssOAuthTokenProvider.CreateIssuedToken"); if (tokenResponse.ExpiresIn > 0) { return new VssOAuthAccessToken(tokenResponse.AccessToken, DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn)); diff --git a/src/Sdk/WebApi/WebApi/VssConnection.cs b/src/Sdk/WebApi/WebApi/VssConnection.cs index 38bfad8c7..3c48811f8 100644 --- a/src/Sdk/WebApi/WebApi/VssConnection.cs +++ b/src/Sdk/WebApi/WebApi/VssConnection.cs @@ -100,6 +100,7 @@ namespace GitHub.Services.WebApi IDictionary parameters, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("VssConnection.ConnectAsync"); CheckForDisposed(); // Set the connectMode on the credential's FederatedPrompt if (Credentials.Federated != null && Credentials.Federated.Prompt != null) diff --git a/src/Sdk/WebApi/WebApi/VssHttpClientBase.cs b/src/Sdk/WebApi/WebApi/VssHttpClientBase.cs index d5a9c8b11..08d01a0cd 100644 --- a/src/Sdk/WebApi/WebApi/VssHttpClientBase.cs +++ b/src/Sdk/WebApi/WebApi/VssHttpClientBase.cs @@ -390,6 +390,7 @@ namespace GitHub.Services.WebApi Object userState = null, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("VssHttpClientBase.SendAsync 1"); return SendAsync(method, null, locationId, routeValues, version, content, queryParameters, userState, cancellationToken); } @@ -404,6 +405,7 @@ namespace GitHub.Services.WebApi Object userState = null, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("VssHttpClientBase.SendAsync 2"); using (VssTraceActivity.GetOrCreate().EnterCorrelationScope()) using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, additionalHeaders, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false)) { @@ -422,6 +424,7 @@ namespace GitHub.Services.WebApi Object userState = null, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("VssHttpClientBase.SendAsync 3"); using (VssTraceActivity.GetOrCreate().EnterCorrelationScope()) using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, additionalHeaders, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false)) { @@ -455,6 +458,7 @@ namespace GitHub.Services.WebApi Object userState = null, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("VssHttpClientBase.SendAsync 4"); using (VssTraceActivity.GetOrCreate().EnterCorrelationScope()) using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false)) { @@ -473,6 +477,7 @@ namespace GitHub.Services.WebApi Object userState = null, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("VssHttpClientBase.SendAsync 5"); using (VssTraceActivity.GetOrCreate().EnterCorrelationScope()) using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false)) { @@ -501,6 +506,7 @@ namespace GitHub.Services.WebApi CancellationToken cancellationToken = default(CancellationToken), String mediaType = c_jsonMediaType) { + // System.Console.WriteLine("VssHttpClientBase.CreateRequestMessageAsync 1"); return CreateRequestMessageAsync(method, null, locationId, routeValues, version, content, queryParameters, userState, cancellationToken, mediaType); } @@ -526,6 +532,7 @@ namespace GitHub.Services.WebApi CancellationToken cancellationToken = default(CancellationToken), String mediaType = c_jsonMediaType) { + // System.Console.WriteLine("VssHttpClientBase.CreateRequestMessageAsync 2"); // Lookup the location ApiResourceLocation location = await GetResourceLocationAsync(locationId, userState, cancellationToken).ConfigureAwait(false); if (location == null) @@ -555,6 +562,7 @@ namespace GitHub.Services.WebApi IEnumerable> queryParameters = null, String mediaType = c_jsonMediaType) { + // System.Console.WriteLine("VssHttpClientBase.CreateRequestMessageAsync 3"); return CreateRequestMessage(method, null, location, routeValues, version, content, queryParameters, mediaType); } @@ -578,6 +586,7 @@ namespace GitHub.Services.WebApi IEnumerable> queryParameters = null, String mediaType = c_jsonMediaType) { + // System.Console.WriteLine("VssHttpClientBase.CreateRequestMessageAsync 4"); CheckForDisposed(); // Negotiate the request version to send ApiResourceVersion requestVersion = NegotiateRequestVersion(location, version); @@ -749,12 +758,14 @@ namespace GitHub.Services.WebApi //from deadlocking... using (HttpResponseMessage response = await this.SendAsync(message, userState, cancellationToken).ConfigureAwait(false)) { + // System.Console.WriteLine("VssHttpClientBase.SendAsync 6"); return await ReadContentAsAsync(response, cancellationToken).ConfigureAwait(false); } } protected async Task ReadContentAsAsync(HttpResponseMessage response, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine($"VssHttpClientBase.ReadContentAsAsync {response.Headers}"); CheckForDisposed(); Boolean isJson = IsJsonResponse(response); bool mismatchContentType = false; @@ -766,17 +777,20 @@ namespace GitHub.Services.WebApi !typeof(Byte[]).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()) && !typeof(JObject).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())) { + // System.Console.WriteLine("VssHttpClientBase.ReadContentAsAsync: isJson 1"); // expect it to come back wrapped, if it isn't it is a bug! var wrapper = await ReadJsonContentAsync>(response, cancellationToken).ConfigureAwait(false); return wrapper.Value; } else if (isJson) { + // System.Console.WriteLine("VssHttpClientBase.ReadContentAsAsync: isJson 2"); return await ReadJsonContentAsync(response, cancellationToken).ConfigureAwait(false); } } catch (JsonReaderException) { + // System.Console.WriteLine("VssHttpClientBase.ReadContentAsAsync: mismatchContentType"); // We thought the content was JSON but failed to parse. // In this case, do nothing and utilize the HandleUnknownContentType call below mismatchContentType = true; @@ -802,6 +816,7 @@ namespace GitHub.Services.WebApi Object userState = null, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("VssHttpClientBase.SendAsync 7"); // the default in httpClient for HttpCompletionOption is ResponseContentRead so that is what we do here return this.SendAsync( message, @@ -816,6 +831,7 @@ namespace GitHub.Services.WebApi Object userState = null, CancellationToken cancellationToken = default(CancellationToken)) { + // System.Console.WriteLine("VssHttpClientBase.SendAsync 8"); CheckForDisposed(); if (message.Headers.UserAgent != null) { @@ -851,6 +867,7 @@ namespace GitHub.Services.WebApi //ConfigureAwait(false) enables the continuation to be run outside //any captured SyncronizationContext (such as ASP.NET's) which keeps things //from deadlocking... + // System.Console.WriteLine($"VssHttpClientBase.SendAsync 8: Calling Client.SendAsync {message}"); HttpResponseMessage response = await Client.SendAsync(message, completionOption, cancellationToken).ConfigureAwait(false); // Inject delay or failure for testing @@ -868,6 +885,7 @@ namespace GitHub.Services.WebApi [Obsolete("Use VssHttpClientBase.HandleResponseAsync instead")] protected virtual void HandleResponse(HttpResponseMessage response) { + // System.Console.WriteLine("VssHttpClientBase.HandleResponse 1"); } @@ -875,6 +893,7 @@ namespace GitHub.Services.WebApi HttpResponseMessage response, CancellationToken cancellationToken) { + // System.Console.WriteLine($"VssHttpClientBase.HandleResponse 2 status code {response.StatusCode} headers {response.Headers}"); response.Trace(); VssHttpEventSource.Log.HttpRequestStop(VssTraceActivity.Current, response); @@ -886,6 +905,7 @@ namespace GitHub.Services.WebApi } else if (ShouldThrowError(response)) { + // System.Console.WriteLine("VssHttpClientBase.HandleResponse: Should throw error"); Exception exToThrow = null; if (IsJsonResponse(response)) { @@ -909,6 +929,7 @@ namespace GitHub.Services.WebApi { message = response.ReasonPhrase; } + // System.Console.WriteLine($"VssHttpClientBase.HandleResponse: Exception message {message}"); exToThrow = new VssServiceResponseException(response.StatusCode, message, exToThrow); } diff --git a/src/dev.sh b/src/dev.sh index e7b075ca5..13ccbc747 100755 --- a/src/dev.sh +++ b/src/dev.sh @@ -2,7 +2,7 @@ ############################################################################### # -# ./dev.sh build/layout/test/package [Debug/Release] +# ./dev.sh build/layout/test/package [Debug/Release] [linux-x64|linux-x86|linux-arm64|linux-arm|osx-x64|win-x64|win-x86] [use-broker] # ############################################################################### @@ -11,6 +11,7 @@ set -e DEV_CMD=$1 DEV_CONFIG=$2 DEV_TARGET_RUNTIME=$3 +DEV_USE_BROKER=$4 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LAYOUT_DIR="$SCRIPT_DIR/../_layout" @@ -81,6 +82,13 @@ elif [[ "$CURRENT_PLATFORM" == 'darwin' ]]; then fi fi +if [ -n "$DEV_USE_BROKER" ]; then + USE_BROKER='-p:USE_BROKER="true"' +else + USE_BROKER='' +fi + + function failed() { local error=${1:-Undefined error} @@ -114,13 +122,13 @@ function heading() function build () { heading "Building ..." - dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build + dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" $USE_BROKER ./dir.proj || failed build } function layout () { heading "Create layout ..." - dotnet msbuild -t:layout -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build + dotnet msbuild -t:layout -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" $USE_BROKER ./dir.proj || failed build #change execution flag to allow running with sudo if [[ ("$CURRENT_PLATFORM" == "linux") || ("$CURRENT_PLATFORM" == "darwin") ]]; then