Skip to content

Commit cbdea2f

Browse files
Merge pull request #39 from Microsoft/users/kasubram/runasasync
Not running agent interactively if its configured as runasservice
2 parents e9acf4f + 599047c commit cbdea2f

File tree

5 files changed

+74
-13
lines changed

5 files changed

+74
-13
lines changed

src/Agent.Listener/Agent.cs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,37 @@ public async Task<int> ExecuteCommand(CommandLineParser parser)
103103

104104
if (parser.IsCommand("run") && !configManager.IsConfigured())
105105
{
106-
throw new InvalidOperationException("Cannot run. Must configure first.");
106+
throw new InvalidOperationException("CanNotRunAgent");
107107
}
108108

109109
Trace.Info("Done evaluating commands");
110+
bool alreadyConfigured = configManager.IsConfigured();
110111
await configManager.EnsureConfiguredAsync();
111112

112113
_inConfigStage = false;
113114

114-
// TODO: If configured as runasservice return from here
115-
116-
return await RunAsync(TokenSource.Token);
115+
AgentSettings settings = configManager.LoadSettings();
116+
if (parser.IsCommand("run") || !settings.RunAsService)
117+
{
118+
// Run the agent interactively
119+
Trace.Verbose(
120+
StringUtil.Format(
121+
"Run command mentioned: {0}, run as service option mentioned:{1}",
122+
parser.IsCommand("run"),
123+
settings.RunAsService));
124+
125+
return await RunAsync(TokenSource.Token, settings);
126+
}
127+
128+
if (alreadyConfigured)
129+
{
130+
// This is helpful if the user tries to start the agent.listener which is already configured or running as service
131+
// However user can execute the agent by calling the run command
132+
// TODO: Should we check if the service is running and prompt user to start the service if its not already running?
133+
_term.WriteLine(StringUtil.Loc("ConfiguredAsRunAsService", settings.ServiceName));
134+
}
135+
136+
return 0;
117137
}
118138
finally
119139
{
@@ -127,13 +147,11 @@ void CtrlCHandler(object sender, EventArgs e)
127147
}
128148

129149
//create worker manager, create message listener and start listening to the queue
130-
private async Task<int> RunAsync(CancellationToken token)
150+
private async Task<int> RunAsync(CancellationToken token, AgentSettings settings)
131151
{
132152
Trace.Info(nameof(RunAsync));
133153

134154
// Load the settings.
135-
var configManager = HostContext.GetService<IConfigurationManager>();
136-
AgentSettings settings = configManager.LoadSettings();
137155
_poolId = settings.PoolId;
138156

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

src/Agent.Listener/Configuration/ConfigurationManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
using Microsoft.VisualStudio.Services.Agent.Util;
33
using Microsoft.VisualStudio.Services.Client;
44
using Microsoft.VisualStudio.Services.Common;
5+
56
using System;
67
using System.Collections.Generic;
7-
using System.Linq;
88
using System.Threading;
9+
using System.Linq;
910
using System.Threading.Tasks;
1011

1112
namespace Microsoft.VisualStudio.Services.Agent.Listener.Configuration
@@ -127,6 +128,7 @@ public async Task ConfigureAsync(Dictionary<string, string> args, HashSet<string
127128
Trace.Info("Read agent settings");
128129
var consoleWizard = HostContext.GetService<IConsoleWizard>();
129130

131+
// TODO: Check if its running with elevated permission and stop early if its not
130132
//
131133
// Loop getting url and creds until you can connect
132134
//
@@ -221,9 +223,7 @@ public async Task ConfigureAsync(Dictionary<string, string> args, HashSet<string
221223
agentName = consoleWizard.ReadValue(CliArgs.Agent,
222224
StringUtil.Loc("AgentName"),
223225
false,
224-
// TODO: coreCLR doesn't expose till very recently (Jan 15)
225-
// Environment.MachineName,
226-
"myagent",
226+
Environment.MachineName ?? "myagent",
227227
// can do better
228228
Validators.NonEmptyValidator,
229229
args,

src/Agent.Listener/Configuration/WindowsServiceControlManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public override void StopService(string serviceName)
192192
catch (Exception exception)
193193
{
194194
Trace.Error(exception);
195-
_term.WriteError(StringUtil.Loc("CanNotStopService"));
195+
_term.WriteError(StringUtil.Loc("CanNotStopService", serviceName));
196196

197197
// Log the exception but do not report it as error. We can try uninstalling the service and then report it as error if something goes wrong.
198198
}

src/Misc/layoutbin/en-US/strings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
"CanNotFindSystemd": "Can not find if systemd is installed",
2828
"CanNotGrantPermission": "Can not grant LogonAsService permission to the user {0}",
2929
"CanNotInstallService": "Can not install the service, check the logs for more details ",
30+
"CanNotRunAgent": "Cannot run. Must configure first",
3031
"CanNotSetPermissionForAccount": "Can not set permission for service account, check the logs for more details",
3132
"CanNotStartService": "Can not start the service, check the logs for more details",
3233
"CanNotStopService": "Can not stop the service {0} in a timely fashion, please stop the service and reconfigure again",
3334
"CanNotVerifyLogonAccountPassword": "Can not verify if the password entered is valid",
3435
"Cleanup": "Post Job Clean Up",
3536
"CommandNotFound": "Can't find command extension for ##vso[{0}.command]. TODO: DOC aka link",
37+
"ConfiguredAsRunAsService": "Agent is configured to run as service {0}",
3638
"ConnectingToServer": "Connecting to server ...",
3739
"CouldNotRemoveService": "Could not delete service {0}",
3840
"CustomLogDoesNotExist": "Log file path is not provided or file doesn't exist: '{data}'",

src/Test/L0/Listener/AgentL0.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Threading;
99
using System.Threading.Tasks;
1010
using Xunit;
11+
using Xunit.Extensions;
1112

1213
namespace Microsoft.VisualStudio.Services.Agent.Tests.Listener
1314
{
@@ -17,13 +18,15 @@ public sealed class AgentL0
1718
private Mock<IMessageListener> _messageListener;
1819
private Mock<IWorkerManager> _workerManager;
1920
private Mock<IAgentServer> _agentServer;
21+
private Mock<ITerminal> _term;
2022

2123
public AgentL0()
2224
{
2325
_configurationManager = new Mock<IConfigurationManager>();
2426
_messageListener = new Mock<IMessageListener>();
2527
_workerManager = new Mock<IWorkerManager>();
2628
_agentServer = new Mock<IAgentServer>();
29+
_term = new Mock<ITerminal>();
2730
}
2831

2932
private JobRequestMessage CreateJobRequestMessage(string jobName)
@@ -53,7 +56,7 @@ public async void TestRunAsync()
5356
using (var tokenSource = new CancellationTokenSource())
5457
{
5558
//Arrange
56-
var agent = new Microsoft.VisualStudio.Services.Agent.Listener.Agent();
59+
var agent = new Agent.Listener.Agent();
5760
agent.TokenSource = tokenSource;
5861
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
5962
hc.SetSingleton<IMessageListener>(_messageListener.Object);
@@ -171,5 +174,43 @@ public async void TestRunAsync()
171174
}
172175
}
173176
}
177+
178+
public static TheoryData<string[], bool, Times> RunAsServiceTestData = new TheoryData<string[], bool, Times>()
179+
{
180+
// staring with run command, configured as run as service, should start the agent
181+
{ new [] { "run" }, true, Times.Once() },
182+
// starting with no argument, configured as run as service, should not start agent
183+
{ new string[] { }, true, Times.Never() },
184+
// starting with no argument, configured not to run as service, should start agent interactively
185+
{ new string[] { }, false, Times.Once() }
186+
};
187+
[Theory]
188+
[MemberData("RunAsServiceTestData")]
189+
[Trait("Level", "L0")]
190+
[Trait("Category", "Agent")]
191+
public async void TestExecuteCommandForRunAsService(string[] args, bool configureAsService, Times expectedTimes)
192+
{
193+
using (var hc = new TestHostContext(this))
194+
{
195+
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
196+
hc.SetSingleton<IMessageListener>(_messageListener.Object);
197+
198+
CommandLineParser clp = new CommandLineParser(hc);
199+
clp.Parse(args);
200+
201+
_configurationManager.Setup(x => x.IsConfigured()).Returns(true);
202+
_configurationManager.Setup(x => x.LoadSettings())
203+
.Returns(new AgentSettings { RunAsService = configureAsService });
204+
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
205+
.Returns(Task.FromResult(false));
206+
207+
var agent = new Agent.Listener.Agent();
208+
agent.Initialize(hc);
209+
agent.TokenSource = new CancellationTokenSource();
210+
await agent.ExecuteCommand(clp);
211+
212+
_messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), expectedTimes);
213+
}
214+
}
174215
}
175216
}

0 commit comments

Comments
 (0)