Example #1
0
 public override void EnsureCredential(
     IHostContext context, 
     CommandSettings command, 
     String serverUrl)
 {
     // Nothing to verify here
 }
        public override bool ConfigureService(
            AgentSettings settings,
            CommandSettings command)
        {
            Trace.Entering();

            throw new NotSupportedException("Systemd Configure Service");
        }
 public override void EnsureCredential(IHostContext context, CommandSettings command, string serverUrl)
 {
     ArgUtil.NotNull(context, nameof(context));
     Tracing trace = context.GetTrace(nameof(PersonalAccessToken));
     trace.Info(nameof(EnsureCredential));
     ArgUtil.NotNull(command, nameof(command));
     CredentialData.Data[Constants.Agent.CommandLine.Args.Token] = command.GetToken();
 }
 public async Task EnsureConfiguredAsync(CommandSettings command)
 {
     Trace.Info(nameof(EnsureConfiguredAsync));
     if (!IsConfigured())
     {
         await ConfigureAsync(command);
     }
 }
 public override void EnsureCredential(IHostContext context, CommandSettings command, string serverUrl)
 {
     ArgUtil.NotNull(context, nameof(context));
     Tracing trace = context.GetTrace(nameof(PersonalAccessToken));
     trace.Info(nameof(EnsureCredential));
     ArgUtil.NotNull(command, nameof(command));
     ArgUtil.NotNullOrEmpty(serverUrl, nameof(serverUrl));
     //TODO: use Validators.NTAccountValidator when it works on Linux
     CredentialData.Data[Constants.Agent.CommandLine.Args.UserName] = command.GetUserName();
     CredentialData.Data[Constants.Agent.CommandLine.Args.Password] = command.GetPassword();
     CredentialData.Data[Constants.Agent.CommandLine.Args.Url] = serverUrl;
 }
 public override void EnsureCredential(IHostContext context, CommandSettings command, string serverUrl)
 {
     //Integrated credentials do not require any configuration parameters
 }
Example #7
0
        public async Task <TaskAgent> UpdateAgentAsync(AgentSettings agentSettings, TaskAgent agent, CommandSettings command)
        {
            var deploymentMachine = (await this.GetDeploymentMachinesAsync(agentSettings)).FirstOrDefault();

            deploymentMachine.Agent = agent;
            deploymentMachine       = await _deploymentGroupServer.ReplaceDeploymentMachineAsync(new Guid(agentSettings.ProjectId), agentSettings.DeploymentGroupId, deploymentMachine.Id, deploymentMachine);

            await GetAndAddTags(deploymentMachine, agentSettings, command);

            return(deploymentMachine.Agent);
        }
 public override void EnsureCredential(IHostContext context, CommandSettings command, string serverUrl)
 {
     CredentialData.Data[Constants.Agent.CommandLine.Args.UserName] = command.GetUserName();
     CredentialData.Data[Constants.Agent.CommandLine.Args.Password] = command.GetPassword();
 }
        public void Assign(CommandSettings settings, ITypeResolver resolver, object?value)
        {
            // Is the property pair deconstructable?
            // TODO: This needs to be better defined
            if (Property.PropertyType.IsPairDeconstructable() && WantRawValue)
            {
                var genericTypes = Property.PropertyType.GetGenericArguments();

                var multimap = (IMultiMap?)Property.GetValue(settings);
                if (multimap == null)
                {
                    multimap = Activator.CreateInstance(typeof(MultiMap <,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap;
                    if (multimap == null)
                    {
                        throw new InvalidOperationException("Could not create multimap");
                    }
                }

                // Create deconstructor.
                var deconstructorType = PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor);
                if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor))
                {
                    if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor))
                    {
                        throw new InvalidOperationException($"Could not create pair deconstructor.");
                    }

                    deconstructor = activatedDeconstructor;
                }

                // Deconstruct and add to multimap.
                var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string);
                if (pair.Key != null)
                {
                    multimap.Add(pair);
                }

                value = multimap;
            }
            else if (Property.PropertyType.IsArray)
            {
                // Add a new item to the array
                var   array = (Array?)Property.GetValue(settings);
                Array newArray;

                var elementType = Property.PropertyType.GetElementType();
                if (elementType == null)
                {
                    throw new InvalidOperationException("Could not get property type.");
                }

                if (array == null)
                {
                    newArray = Array.CreateInstance(elementType, 1);
                }
                else
                {
                    newArray = Array.CreateInstance(elementType, array.Length + 1);
                    array.CopyTo(newArray, 0);
                }

                newArray.SetValue(value, newArray.Length - 1);
                value = newArray;
            }
            else if (IsFlagValue())
            {
                var flagValue = (IFlagValue?)Property.GetValue(settings);
                if (flagValue == null)
                {
                    flagValue = (IFlagValue?)Activator.CreateInstance(ParameterType);
                    if (flagValue == null)
                    {
                        throw new InvalidOperationException("Could not create flag value.");
                    }
                }

                if (value != null)
                {
                    // Null means set, but not with a valid value.
                    flagValue.Value = value;
                }

                // If the parameter was mapped, then it's set.
                flagValue.IsSet = true;

                value = flagValue;
            }

            Property.SetValue(settings, value);
        }
        private ICredentialProvider GetCredentialProvider(CommandSettings command, string serverUrl)
        {
            Trace.Info(nameof(GetCredentialProvider));

            var credentialManager = HostContext.GetService<ICredentialManager>();
            // Get the auth type. On premise defaults to negotiate (Kerberos with fallback to NTLM).
            // Hosted defaults to PAT authentication.
            bool isHosted = serverUrl.IndexOf("visualstudio.com", StringComparison.OrdinalIgnoreCase) != -1
                || serverUrl.IndexOf("tfsallin.net", StringComparison.OrdinalIgnoreCase) != -1;
            string defaultAuth = isHosted ? Constants.Configuration.PAT :
                (Constants.Agent.Platform == Constants.OSPlatform.Windows ? Constants.Configuration.Integrated : Constants.Configuration.Negotiate);
            string authType = command.GetAuth(defaultValue: defaultAuth);

            // Create the credential.
            Trace.Info("Creating credential for auth: {0}", authType);
            var provider = credentialManager.GetCredentialProvider(authType);
            provider.EnsureCredential(HostContext, command, serverUrl);
            return provider;
        }
Example #11
0
        public async Task ConfigureAsync(CommandSettings command)
        {
            Trace.Info(nameof(ConfigureAsync));
            if (IsConfigured())
            {
                throw new InvalidOperationException(StringUtil.Loc("AlreadyConfiguredError"));
            }

            // TEE EULA
            bool acceptTeeEula = false;

            switch (Constants.Agent.Platform)
            {
            case Constants.OSPlatform.OSX:
            case Constants.OSPlatform.Linux:
                // Write the section header.
                WriteSection(StringUtil.Loc("EulasSectionHeader"));

                // Verify the EULA exists on disk in the expected location.
                string eulaFile = Path.Combine(IOUtil.GetExternalsPath(), Constants.Path.TeeDirectory, "license.html");
                ArgUtil.File(eulaFile, nameof(eulaFile));

                // Write elaborate verbiage about the TEE EULA.
                _term.WriteLine(StringUtil.Loc("TeeEula", eulaFile));
                _term.WriteLine();

                // Prompt to acccept the TEE EULA.
                acceptTeeEula = command.GetAcceptTeeEula();
                break;

            case Constants.OSPlatform.Windows:
                break;

            default:
                throw new NotSupportedException();
            }

            // Create the configuration provider as per agent type.....
            string agentType = command.MachineGroup
                ? Constants.Agent.AgentConfigurationProvider.DeploymentAgentConfiguration
                : Constants.Agent.AgentConfigurationProvider.BuildReleasesAgentConfiguration;

            var extensionManager = HostContext.GetService <IExtensionManager>();
            IConfigurationProvider agentProvider = (extensionManager.GetExtensions <IConfigurationProvider>()).FirstOrDefault(x => x.ConfigurationProviderType == agentType);

            ArgUtil.NotNull(agentProvider, agentType);

            // TODO: Check if its running with elevated permission and stop early if its not

            // Loop getting url and creds until you can connect
            string serverUrl = null;
            ICredentialProvider credProvider = null;
            VssCredentials      creds        = null;

            WriteSection(StringUtil.Loc("ConnectSectionHeader"));
            while (true)
            {
                // Get the URL
                serverUrl = agentProvider.GetServerUrl(command);

                // Get the credentials
                credProvider = GetCredentialProvider(command, serverUrl);
                creds        = credProvider.GetVssCredentials(HostContext);
                Trace.Info("cred retrieved");
                try
                {
                    // Validate can connect.
                    await agentProvider.TestConnectionAsync(serverUrl, creds);

                    Trace.Info("Test Connection complete.");
                    break;
                }
                catch (Exception e) when(!command.Unattended)
                {
                    _term.WriteError(e);
                    _term.WriteError(StringUtil.Loc("FailedToConnect"));
                }
            }

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

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

            // Loop getting agent name and pool name
            string poolName  = null;
            int    poolId    = 0;
            string agentName = null;

            WriteSection(StringUtil.Loc("RegisterAgentSectionHeader"));

            while (true)
            {
                try
                {
                    poolId = await agentProvider.GetPoolId(command);

                    break;
                }
                catch (Exception e) when(!command.Unattended)
                {
                    _term.WriteError(e);
                    _term.WriteError(agentProvider.GetFailedToFindPoolErrorString());
                }
            }

            TaskAgent agent;

            while (true)
            {
                agentName = command.GetAgentName();

                // Get the system capabilities.
                // TODO: Hook up to ctrl+c cancellation token.
                _term.WriteLine(StringUtil.Loc("ScanToolCapabilities"));
                Dictionary <string, string> systemCapabilities = await HostContext.GetService <ICapabilitiesManager>().GetCapabilitiesAsync(
                    new AgentSettings {
                    AgentName = agentName
                }, CancellationToken.None);

                _term.WriteLine(StringUtil.Loc("ConnectToServer"));
                agent = await GetAgent(agentName, poolId);

                if (agent != null)
                {
                    if (command.GetReplace())
                    {
                        // Update existing agent with new PublicKey, agent version and SystemCapabilities.
                        agent = UpdateExistingAgent(agent, publicKey, systemCapabilities);

                        try
                        {
                            agent = await agentProvider.UpdateAgentAsync(poolId, agent);

                            _term.WriteLine(StringUtil.Loc("AgentReplaced"));
                            break;
                        }
                        catch (Exception e) when(!command.Unattended)
                        {
                            _term.WriteError(e);
                            _term.WriteError(StringUtil.Loc("FailedToReplaceAgent"));
                        }
                    }
                    else if (command.Unattended)
                    {
                        // if not replace and it is unattended config.
                        throw new TaskAgentExistsException(StringUtil.Loc("AgentWithSameNameAlreadyExistInPool", poolId, agentName));
                    }
                }
                else
                {
                    // Create a new agent.
                    agent = CreateNewAgent(agentName, publicKey, systemCapabilities);

                    try
                    {
                        agent = await agentProvider.AddAgentAsync(poolId, agent);

                        _term.WriteLine(StringUtil.Loc("AgentAddedSuccessfully"));
                        break;
                    }
                    catch (Exception e) when(!command.Unattended)
                    {
                        _term.WriteError(e);
                        _term.WriteError(StringUtil.Loc("AddAgentFailed"));
                    }
                }
            }

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

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

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

            // See if the server supports our OAuth key exchange for credentials
            if (agent.Authorization != null &&
                agent.Authorization.ClientId != Guid.Empty &&
                agent.Authorization.AuthorizationUrl != null)
            {
                var credentialData = new CredentialData
                {
                    Scheme = Constants.Configuration.OAuth,
                    Data   =
                    {
                        { "clientId",         agent.Authorization.ClientId.ToString("D")       },
                        { "authorizationUrl", agent.Authorization.AuthorizationUrl.AbsoluteUri },
                    },
                };

                // Save the negotiated OAuth credential data
                _store.SaveCredential(credentialData);
            }
            else
            {
                // Save the provided admin credential data for compat with existing agent
                _store.SaveCredential(credProvider.CredentialData);
            }

            // Testing agent connection, detect any protential connection issue, like local clock skew that cause OAuth token expired.
            _term.WriteLine(StringUtil.Loc("TestAgentConnection"));
            var            credMgr    = HostContext.GetService <ICredentialManager>();
            VssCredentials credential = credMgr.LoadCredentials();
            VssConnection  conn       = ApiUtil.CreateConnection(new Uri(serverUrl), credential);
            var            agentSvr   = HostContext.GetService <IAgentServer>();

            try
            {
                await agentSvr.ConnectAsync(conn);
            }
            catch (VssOAuthTokenRequestException ex) when(ex.Message.Contains("Current server time is"))
            {
                // there are two exception messages server send that indicate clock skew.
                // 1. The bearer token expired on {jwt.ValidTo}. Current server time is {DateTime.UtcNow}.
                // 2. The bearer token is not valid until {jwt.ValidFrom}. Current server time is {DateTime.UtcNow}.
                Trace.Error("Catch exception during test agent connection.");
                Trace.Error(ex);
                throw new Exception(StringUtil.Loc("LocalClockSkewed"));
            }

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

            // notificationPipeName for Hosted agent provisioner.
            string notificationPipeName = command.GetNotificationPipeName();

            // Get Agent settings
            var settings = new AgentSettings
            {
                AcceptTeeEula        = acceptTeeEula,
                AgentId              = agent.Id,
                AgentName            = agentName,
                NotificationPipeName = notificationPipeName,
                PoolId     = poolId,
                PoolName   = poolName,
                ServerUrl  = serverUrl,
                WorkFolder = workFolder
            };

            // This is required in case agent is configured as DeploymentAgent. It will make entry for projectName and MachineGroup
            agentProvider.UpdateAgentSetting(settings);

            _store.SaveSettings(settings);
            _term.WriteLine(StringUtil.Loc("SavedSettings", DateTime.UtcNow));

#if OS_WINDOWS
            // config windows service as part of configuration
            bool runAsService = command.GetRunAsService();
            if (!runAsService)
            {
                return;
            }
            else
            {
                if (!new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator))
                {
                    Trace.Error("Needs Administrator privileges for configure agent as windows service.");
                    throw new SecurityException(StringUtil.Loc("NeedAdminForConfigAgentWinService"));
                }

                Trace.Info("Configuring to run the agent as service");
                var serviceControlManager = HostContext.GetService <IWindowsServiceControlManager>();
                serviceControlManager.ConfigureService(settings, command);
            }
#elif OS_LINUX || OS_OSX
            // generate service config script for OSX and Linux, GenerateScripts() will no-opt on windows.
            var serviceControlManager = HostContext.GetService <ILinuxServiceControlManager>();
            serviceControlManager.GenerateScripts(settings);
#endif
        }
Example #12
0
        //process 2 new job messages, and one cancel message
        public async void TestRunAsync()
        {
            using (var hc = new TestHostContext(this))
                using (var tokenSource = new CancellationTokenSource())
                {
                    //Arrange
                    var agent = new Agent.Listener.Agent();
                    agent.TokenSource = tokenSource;
                    hc.SetSingleton <IConfigurationManager>(_configurationManager.Object);
                    hc.SetSingleton <IJobNotification>(_jobNotification.Object);
                    hc.SetSingleton <IMessageListener>(_messageListener.Object);
                    hc.SetSingleton <IPromptManager>(_promptManager.Object);
                    hc.SetSingleton <IAgentServer>(_agentServer.Object);
                    agent.Initialize(hc);
                    var settings = new AgentSettings
                    {
                        PoolId = 43242
                    };
                    var taskAgentSession = new TaskAgentSession();
                    //we use reflection to achieve this, because "set" is internal
                    PropertyInfo sessionIdProperty = taskAgentSession.GetType().GetProperty("SessionId", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                    Assert.NotNull(sessionIdProperty);
                    sessionIdProperty.SetValue(taskAgentSession, Guid.NewGuid());

                    var message = new TaskAgentMessage()
                    {
                        Body        = JsonUtility.ToString(CreateJobRequestMessage("job1")),
                        MessageId   = 4234,
                        MessageType = JobRequestMessageTypes.AgentJobRequest
                    };

                    var messages = new Queue <TaskAgentMessage>();
                    messages.Enqueue(message);
                    var signalWorkerComplete = new SemaphoreSlim(0, 1);
                    _configurationManager.Setup(x => x.LoadSettings())
                    .Returns(settings);
                    _configurationManager.Setup(x => x.IsConfigured())
                    .Returns(true);
                    _configurationManager.Setup(x => x.EnsureConfiguredAsync(It.IsAny <CommandSettings>()))
                    .Returns(Task.CompletedTask);
                    _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny <CancellationToken>()))
                    .Returns(Task.FromResult <bool>(true));
                    _messageListener.Setup(x => x.Session)
                    .Returns(taskAgentSession);
                    _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny <CancellationToken>()))
                    .Returns(async() =>
                    {
                        if (0 == messages.Count)
                        {
                            signalWorkerComplete.Release();
                            await Task.Delay(2000, tokenSource.Token);
                        }

                        return(messages.Dequeue());
                    });
                    _messageListener.Setup(x => x.DeleteSessionAsync())
                    .Returns(Task.CompletedTask);
                    _jobDispatcher.Setup(x => x.Run(It.IsAny <AgentJobRequestMessage>()))
                    .Callback(() =>
                    {
                    });
                    _agentServer.Setup(x => x.DeleteAgentMessageAsync(settings.PoolId, message.MessageId, taskAgentSession.SessionId, It.IsAny <CancellationToken>()))
                    .Returns((Int32 poolId, Int64 messageId, Guid sessionId, CancellationToken cancellationToken) =>
                    {
                        return(Task.CompletedTask);
                    });
                    _jobNotification.Setup(x => x.StartClient(It.IsAny <String>(), It.IsAny <CancellationToken>()))
                    .Callback(() =>
                    {
                    });

                    hc.EnqueueInstance <IJobDispatcher>(_jobDispatcher.Object);

                    //Act
                    var  command   = new CommandSettings(hc, new string[0]);
                    Task agentTask = agent.ExecuteCommand(command);

                    //Assert
                    //wait for the agent to run one job
                    if (!await signalWorkerComplete.WaitAsync(2000))
                    {
                        Assert.True(false, $"{nameof(_messageListener.Object.GetNextMessageAsync)} was not invoked.");
                    }
                    else
                    {
                        //Act
                        tokenSource.Cancel(); //stop Agent

                        //Assert
                        Task[] taskToWait2 = { agentTask, Task.Delay(2000) };
                        //wait for the Agent to exit
                        await Task.WhenAny(taskToWait2);

                        Assert.True(agentTask.IsCompleted, $"{nameof(agent.ExecuteCommand)} timed out.");
                        Assert.True(!agentTask.IsFaulted, agentTask.Exception?.ToString());
                        Assert.True(agentTask.IsCanceled);

                        _jobDispatcher.Verify(x => x.Run(It.IsAny <AgentJobRequestMessage>()), Times.Once(),
                                              $"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
                        _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny <CancellationToken>()), Times.AtLeastOnce());
                        _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny <CancellationToken>()), Times.Once());
                        _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
                        _agentServer.Verify(x => x.DeleteAgentMessageAsync(settings.PoolId, message.MessageId, taskAgentSession.SessionId, It.IsAny <CancellationToken>()), Times.AtLeastOnce());
                    }
                }
        }
Example #13
0
        public async Task ConfigureAsync(CommandSettings command)
        {
            _term.WriteLine();
            _term.WriteLine("--------------------------------------------------------------------------------", ConsoleColor.White);
            _term.WriteLine("|        ____ _ _   _   _       _          _        _   _                      |", ConsoleColor.White);
            _term.WriteLine("|       / ___(_) |_| | | |_   _| |__      / \\   ___| |_(_) ___  _ __  ___      |", ConsoleColor.White);
            _term.WriteLine("|      | |  _| | __| |_| | | | | '_ \\    / _ \\ / __| __| |/ _ \\| '_ \\/ __|     |", ConsoleColor.White);
            _term.WriteLine("|      | |_| | | |_|  _  | |_| | |_) |  / ___ \\ (__| |_| | (_) | | | \\__ \\     |", ConsoleColor.White);
            _term.WriteLine("|       \\____|_|\\__|_| |_|\\__,_|_.__/  /_/   \\_\\___|\\__|_|\\___/|_| |_|___/     |", ConsoleColor.White);
            _term.WriteLine("|                                                                              |", ConsoleColor.White);
            _term.Write("|                       ", ConsoleColor.White);
            _term.Write("Self-hosted runner registration", ConsoleColor.Cyan);
            _term.WriteLine("                        |", ConsoleColor.White);
            _term.WriteLine("|                                                                              |", ConsoleColor.White);
            _term.WriteLine("--------------------------------------------------------------------------------", ConsoleColor.White);

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

            RunnerSettings runnerSettings = new RunnerSettings();

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

            _term.WriteSection("Authentication");
            while (true)
            {
                // When testing against a dev deployment of Actions Service, set this environment variable
                var useDevActionsServiceUrl = Environment.GetEnvironmentVariable("USE_DEV_ACTIONS_SERVICE_URL");
                var inputUrl = command.GetUrl();
                if (inputUrl.Contains("codedev.ms", StringComparison.OrdinalIgnoreCase) ||
                    useDevActionsServiceUrl != null)
                {
                    runnerSettings.ServerUrl = inputUrl;
                    // Get the credentials
                    credProvider = GetCredentialProvider(command, runnerSettings.ServerUrl);
                    creds        = credProvider.GetVssCredentials(HostContext);
                    Trace.Info("legacy vss cred retrieved");
                }
                else
                {
                    runnerSettings.GitHubUrl = inputUrl;
                    var githubToken             = command.GetRunnerRegisterToken();
                    GitHubAuthResult authResult = await GetTenantCredential(inputUrl, githubToken, Constants.RunnerEvent.Register);

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

                try
                {
                    // Determine the service deployment type based on connection data. (Hosted/OnPremises)
                    runnerSettings.IsHostedServer = runnerSettings.GitHubUrl == null || IsHostedServer(new UriBuilder(runnerSettings.GitHubUrl));

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

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

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

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

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

            _term.WriteSection("Runner Registration");

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

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

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

            TaskAgent agent;

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

                _term.WriteLine();

                var userLabels = command.GetLabels();
                _term.WriteLine();

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

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

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

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

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

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

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

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

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

            // See if the server supports our OAuth key exchange for credentials
            if (agent.Authorization != null &&
                agent.Authorization.ClientId != Guid.Empty &&
                agent.Authorization.AuthorizationUrl != null)
            {
                UriBuilder configServerUrl         = new UriBuilder(runnerSettings.ServerUrl);
                UriBuilder oauthEndpointUrlBuilder = new UriBuilder(agent.Authorization.AuthorizationUrl);
                var        credentialData          = new CredentialData
                {
                    Scheme = Constants.Configuration.OAuth,
                    Data   =
                    {
                        { "clientId",         agent.Authorization.ClientId.ToString("D")       },
                        { "authorizationUrl", agent.Authorization.AuthorizationUrl.AbsoluteUri },
                        { "oauthEndpointUrl", oauthEndpointUrlBuilder.Uri.AbsoluteUri          },
                    },
                };

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

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

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

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

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

            _term.WriteSection("Runner settings");

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

            runnerSettings.MonitorSocketAddress = command.GetMonitorSocketAddress();

            _store.SaveSettings(runnerSettings);

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

#if OS_WINDOWS
            // config windows service
            bool runAsService = command.GetRunAsService();
            if (runAsService)
            {
                Trace.Info("Configuring to run the agent as service");
                var serviceControlManager = HostContext.GetService <IWindowsServiceControlManager>();
                serviceControlManager.ConfigureService(runnerSettings, command);
            }
#elif OS_LINUX || OS_OSX
            // generate service config script for OSX and Linux, GenerateScripts() will no-opt on windows.
            var serviceControlManager = HostContext.GetService <ILinuxServiceControlManager>();
            serviceControlManager.GenerateScripts(runnerSettings);
#endif
        }
Example #14
0
        public virtual async Task <TaskAgent> UpdateAgentAsync(AgentSettings agentSettings, TaskAgent agent, CommandSettings command)
        {
            ArgUtil.NotNull(agentSettings, nameof(agentSettings));
            ArgUtil.NotNull(command, nameof(command));
            var deploymentMachine = (await this.GetDeploymentTargetsAsync(agentSettings)).FirstOrDefault();

            deploymentMachine.Agent = agent;
            deploymentMachine       = await _deploymentGroupServer.ReplaceDeploymentTargetAsync(new Guid(agentSettings.ProjectId), agentSettings.DeploymentGroupId, deploymentMachine.Id, deploymentMachine);

            await GetAndAddTags(deploymentMachine, agentSettings, command);

            return(deploymentMachine.Agent);
        }
        public async Task ConfigureAsync(CommandSettings command)
        {
            ArgUtil.NotNull(command, nameof(command));
            if (!_windowsServiceHelper.IsRunningInElevatedMode())
            {
                Trace.Error("Needs Administrator privileges to configure agent with AutoLogon capability.");
                throw new SecurityException(StringUtil.Loc("NeedAdminForAutologonCapability"));
            }

            string domainName;
            string userName;
            string logonAccount;
            string logonPassword;

            while (true)
            {
                logonAccount = command.GetWindowsLogonAccount(defaultValue: string.Empty, descriptionMsg: StringUtil.Loc("AutoLogonAccountNameDescription"));
                GetAccountSegments(logonAccount, out domainName, out userName);

                if ((string.IsNullOrEmpty(domainName) || domainName.Equals(".", StringComparison.CurrentCultureIgnoreCase)) && !logonAccount.Contains("@"))
                {
                    logonAccount = String.Format("{0}\\{1}", Environment.MachineName, userName);
                    domainName   = Environment.MachineName;
                }
                Trace.Info("LogonAccount after transforming: {0}, user: {1}, domain: {2}", logonAccount, userName, domainName);

                logonPassword = command.GetWindowsLogonPassword(logonAccount);
                if (_windowsServiceHelper.IsValidAutoLogonCredential(domainName, userName, logonPassword))
                {
                    Trace.Info("Credential validation succeeded");
                    break;
                }

                if (command.Unattended())
                {
                    throw new SecurityException(StringUtil.Loc("InvalidAutoLogonCredential"));
                }

                Trace.Error("Invalid credential entered.");
                _terminal.WriteError(StringUtil.Loc("InvalidAutoLogonCredential"));
            }

            _autoLogonRegManager.GetAutoLogonUserDetails(out string currentAutoLogonUserDomainName, out string currentAutoLogonUserName);

            if (currentAutoLogonUserName != null &&
                !userName.Equals(currentAutoLogonUserName, StringComparison.CurrentCultureIgnoreCase) &&
                !domainName.Equals(currentAutoLogonUserDomainName, StringComparison.CurrentCultureIgnoreCase))
            {
                string currentAutoLogonAccount = String.Format("{0}\\{1}", currentAutoLogonUserDomainName, currentAutoLogonUserName);
                if (string.IsNullOrEmpty(currentAutoLogonUserDomainName) || currentAutoLogonUserDomainName.Equals(".", StringComparison.CurrentCultureIgnoreCase))
                {
                    currentAutoLogonAccount = String.Format("{0}\\{1}", Environment.MachineName, currentAutoLogonUserName);
                }

                Trace.Warning($"AutoLogon already enabled for {currentAutoLogonAccount}.");
                if (!command.GetOverwriteAutoLogon(currentAutoLogonAccount))
                {
                    Trace.Error("Marking the agent configuration as failed due to the denial of autologon setting overwriting by the user.");
                    throw new Exception(StringUtil.Loc("AutoLogonOverwriteDeniedError", currentAutoLogonAccount));
                }
                Trace.Info($"Continuing with the autologon configuration.");
            }

            // grant permission for agent root folder and work folder
            Trace.Info("Create local group and grant folder permission to logon account.");
            string agentRoot  = HostContext.GetDirectory(WellKnownDirectory.Root);
            string workFolder = HostContext.GetDirectory(WellKnownDirectory.Work);

            Directory.CreateDirectory(workFolder);
            _windowsServiceHelper.GrantDirectoryPermissionForAccount(logonAccount, new[] { agentRoot, workFolder });

            _autoLogonRegManager.UpdateRegistrySettings(command, domainName, userName, logonPassword);
            _windowsServiceHelper.SetAutoLogonPassword(logonPassword);

            await ConfigurePowerOptions();

            SaveAutoLogonSettings(domainName, userName);
            RestartBasedOnUserInput(command);
        }
Example #16
0
        public async Task UnconfigureAsync(CommandSettings command)
        {
            string currentAction = string.Empty;

            _term.WriteSection("Runner removal");

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

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

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

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

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

                    // Determine the service deployment type based on connection data. (Hosted/OnPremises)
                    await _runnerServer.ConnectAsync(new Uri(settings.ServerUrl), creds);

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

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

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

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

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

            _term.WriteLine();
        }
Example #17
0
 public Task <TaskAgent> AddAgentAsync(AgentSettings agentSettings, TaskAgent agent, CommandSettings command)
 {
     return(_agentServer.AddAgentAsync(agentSettings.PoolId, agent));
 }
Example #18
0
 public void GetServerUrl(AgentSettings agentSettings, CommandSettings command)
 {
     agentSettings.ServerUrl = command.GetUrl();
 }
Example #19
0
        public async Task <TaskAgent> AddAgentAsync(AgentSettings agentSettings, TaskAgent agent, CommandSettings command)
        {
            var deploymentMachine = new DeploymentMachine()
            {
                Agent = agent
            };

            deploymentMachine = await _deploymentGroupServer.AddDeploymentMachineAsync(new Guid(agentSettings.ProjectId), agentSettings.DeploymentGroupId, deploymentMachine);

            await GetAndAddTags(deploymentMachine, agentSettings, command);

            return(deploymentMachine.Agent);
        }
 public abstract bool ConfigureService(AgentSettings settings, CommandSettings command);
Example #21
0
        public virtual async Task <TaskAgent> AddAgentAsync(AgentSettings agentSettings, TaskAgent agent, CommandSettings command)
        {
            ArgUtil.NotNull(agentSettings, nameof(agentSettings));
            ArgUtil.NotNull(command, nameof(command));
            var deploymentMachine = new DeploymentMachine()
            {
                Agent = agent
            };
            var azureSubscriptionId = await GetAzureSubscriptionIdAsync();

            if (!String.IsNullOrEmpty(azureSubscriptionId))
            {
                deploymentMachine.Properties.Add("AzureSubscriptionId", azureSubscriptionId);
            }
            deploymentMachine = await _deploymentGroupServer.AddDeploymentTargetAsync(new Guid(agentSettings.ProjectId), agentSettings.DeploymentGroupId, deploymentMachine);

            await GetAndAddTags(deploymentMachine, agentSettings, command);

            return(deploymentMachine.Agent);
        }
Example #22
0
        public async Task UnconfigureAsync(CommandSettings command)
        {
            string currentAction = StringUtil.Loc("UninstallingService");

            try
            {
                //stop, uninstall service and remove service config file
                _term.WriteLine(currentAction);
                if (_store.IsServiceConfigured())
                {
#if OS_WINDOWS
                    if (!new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator))
                    {
                        Trace.Error("Needs Administrator privileges for unconfigure windows service agent.");
                        throw new SecurityException(StringUtil.Loc("NeedAdminForUnconfigWinServiceAgent"));
                    }

                    var serviceControlManager = HostContext.GetService <IWindowsServiceControlManager>();
                    serviceControlManager.UnconfigureService();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
#elif OS_LINUX
                    // unconfig system D service first
                    throw new Exception(StringUtil.Loc("UnconfigureServiceDService"));
#elif OS_OSX
                    // unconfig osx service first
                    throw new Exception(StringUtil.Loc("UnconfigureOSXService"));
#endif
                }

                //delete agent from the server
                currentAction = StringUtil.Loc("UnregisteringAgent");
                _term.WriteLine(currentAction);
                bool isConfigured   = _store.IsConfigured();
                bool hasCredentials = _store.HasCredentials();
                if (isConfigured && hasCredentials)
                {
                    AgentSettings settings          = _store.GetSettings();
                    var           credentialManager = HostContext.GetService <ICredentialManager>();

                    // Get the credentials
                    var            credProvider = GetCredentialProvider(command, settings.ServerUrl);
                    VssCredentials creds        = credProvider.GetVssCredentials(HostContext);
                    Trace.Info("cred retrieved");

                    Uri           uri      = new Uri(settings.ServerUrl);
                    VssConnection conn     = ApiUtil.CreateConnection(uri, creds);
                    var           agentSvr = HostContext.GetService <IAgentServer>();
                    await agentSvr.ConnectAsync(conn);

                    Trace.Info("Connect complete.");

                    Trace.Info("Agent configured for machineGroup : {0}", settings.MachineGroup.ToString());

                    string agentType = settings.MachineGroup
                   ? Constants.Agent.AgentConfigurationProvider.DeploymentAgentConfiguration
                   : Constants.Agent.AgentConfigurationProvider.BuildReleasesAgentConfiguration;

                    var extensionManager = HostContext.GetService <IExtensionManager>();
                    IConfigurationProvider agentProvider = (extensionManager.GetExtensions <IConfigurationProvider>()).FirstOrDefault(x => x.ConfigurationProviderType == agentType);
                    ArgUtil.NotNull(agentProvider, agentType);

                    List <TaskAgent> agents = await agentSvr.GetAgentsAsync(settings.PoolId, settings.AgentName);

                    if (agents.Count == 0)
                    {
                        _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                    }
                    else
                    {
                        await agentProvider.DeleteAgentAsync(settings.PoolId, settings.AgentId);

                        _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                    }
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("MissingConfig"));
                }

                //delete credential config files
                currentAction = StringUtil.Loc("DeletingCredentials");
                _term.WriteLine(currentAction);
                if (hasCredentials)
                {
                    _store.DeleteCredential();
                    var keyManager = HostContext.GetService <IRSAKeyManager>();
                    keyManager.DeleteKey();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                }

                //delete settings config file
                currentAction = StringUtil.Loc("DeletingSettings");
                _term.WriteLine(currentAction);
                if (isConfigured)
                {
                    _store.DeleteSettings();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                }
            }
            catch (Exception)
            {
                _term.WriteLine(StringUtil.Loc("Failed") + currentAction);
                throw;
            }
        }
        public async Task ConfigureAsync(CommandSettings command)
        {
            Trace.Info(nameof(ConfigureAsync));
            if (IsConfigured())
            {
                throw new InvalidOperationException(StringUtil.Loc("AlreadyConfiguredError"));
            }

            // TEE EULA
            bool acceptTeeEula = false;
            switch (Constants.Agent.Platform)
            {
                case Constants.OSPlatform.OSX:
                case Constants.OSPlatform.Linux:
                    // Write the section header.
                    WriteSection(StringUtil.Loc("EulasSectionHeader"));

                    // Verify the EULA exists on disk in the expected location.
                    string eulaFile = Path.Combine(IOUtil.GetExternalsPath(), Constants.Path.TeeDirectory, "license.html");
                    ArgUtil.File(eulaFile, nameof(eulaFile));

                    // Write elaborate verbiage about the TEE EULA.
                    _term.WriteLine(StringUtil.Loc("TeeEula", eulaFile));
                    _term.WriteLine();

                    // Prompt to acccept the TEE EULA.
                    acceptTeeEula = command.GetAcceptTeeEula();
                    break;
                case Constants.OSPlatform.Windows:
                    break;
                default:
                    throw new NotSupportedException();
            }

            // TODO: Check if its running with elevated permission and stop early if its not

            // Loop getting url and creds until you can connect
            string serverUrl = null;
            ICredentialProvider credProvider = null;
            WriteSection(StringUtil.Loc("ConnectSectionHeader"));
            while (true)
            {
                // Get the URL
                serverUrl = command.GetUrl();

                // Get the credentials
                credProvider = GetCredentialProvider(command, serverUrl);
                VssCredentials creds = credProvider.GetVssCredentials(HostContext);
                Trace.Info("cred retrieved");
                try
                {
                    // Validate can connect.
                    await TestConnectAsync(serverUrl, creds);
                    Trace.Info("Connect complete.");
                    break;
                }
                catch (Exception e) when (!command.Unattended)
                {
                    _term.WriteError(e);
                    _term.WriteError(StringUtil.Loc("FailedToConnect"));
                    // TODO: If the connection fails, shouldn't the URL/creds be cleared from the command line parser? Otherwise retry may be immediately attempted using the same values without prompting the user for new values. The same general problem applies to every retry loop during configure.
                }
            }

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

            // Loop getting agent name and pool
            string poolName = null;
            int poolId = 0;
            string agentName = null;
            WriteSection(StringUtil.Loc("RegisterAgentSectionHeader"));
            while (true)
            {
                poolName = command.GetPool();
                try
                {
                    poolId = await GetPoolId(poolName);
                }
                catch (Exception e) when (!command.Unattended)
                {
                    _term.WriteError(e);
                }

                if (poolId > 0)
                {
                    break;
                }

                _term.WriteError(StringUtil.Loc("FailedToFindPool"));
            }

            TaskAgent agent;
            while (true)
            {
                agentName = command.GetAgent();

                // Get the system capabilities.
                // TODO: Hook up to ctrl+c cancellation token.
                // TODO: LOC
                _term.WriteLine("Scanning for tool capabilities.");
                Dictionary<string, string> systemCapabilities = await HostContext.GetService<ICapabilitiesManager>().GetCapabilitiesAsync(
                    new AgentSettings { AgentName = agentName }, CancellationToken.None);

                // TODO: LOC
                _term.WriteLine("Connecting to the server.");
                agent = await GetAgent(agentName, poolId);
                if (agent != null)
                {
                    if (command.GetReplace())
                    {
                        agent.Authorization = new TaskAgentAuthorization
                        {
                            PublicKey = new TaskAgentPublicKey(publicKey.Exponent, publicKey.Modulus),
                        };

                        // update - update instead of delete so we don't lose user capabilities etc...
                        agent.Version = Constants.Agent.Version;

                        foreach (KeyValuePair<string, string> capability in systemCapabilities)
                        {
                            agent.SystemCapabilities[capability.Key] = capability.Value ?? string.Empty;
                        }

                        try
                        {
                            agent = await _agentServer.UpdateAgentAsync(poolId, agent);
                            _term.WriteLine(StringUtil.Loc("AgentReplaced"));
                            break;
                        }
                        catch (Exception e) when (!command.Unattended)
                        {
                            _term.WriteError(e);
                            _term.WriteError(StringUtil.Loc("FailedToReplaceAgent"));
                        }
                    }
                    else
                    {
                        // TODO: ?
                    }
                }
                else
                {
                    agent = new TaskAgent(agentName)
                    {
                        Authorization = new TaskAgentAuthorization
                        {
                            PublicKey = new TaskAgentPublicKey(publicKey.Exponent, publicKey.Modulus),
                        },
                        MaxParallelism = 1,
                        Version = Constants.Agent.Version
                    };

                    foreach (KeyValuePair<string, string> capability in systemCapabilities)
                    {
                        agent.SystemCapabilities[capability.Key] = capability.Value ?? string.Empty;
                    }

                    try
                    {
                        agent = await _agentServer.AddAgentAsync(poolId, agent);
                        _term.WriteLine(StringUtil.Loc("AgentAddedSuccessfully"));
                        break;
                    }
                    catch (Exception e) when (!command.Unattended)
                    {
                        _term.WriteError(e);
                        _term.WriteError(StringUtil.Loc("AddAgentFailed"));
                    }
                }
            }

            // See if the server supports our OAuth key exchange for credentials
            if (agent.Authorization != null &&
                agent.Authorization.ClientId != Guid.Empty &&
                agent.Authorization.AuthorizationUrl != null)
            {
                var credentialData = new CredentialData
                {
                    Scheme = Constants.Configuration.OAuth,
                    Data =
                    {
                        { "clientId", agent.Authorization.ClientId.ToString("D") },
                        { "authorizationUrl", agent.Authorization.AuthorizationUrl.AbsoluteUri },
                    },
                };

                // Save the negotiated OAuth credential data
                _store.SaveCredential(credentialData);
            }
            else
            {
                // Save the provided admin credential data for compat with existing agent
                _store.SaveCredential(credProvider.CredentialData);
            }

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

            // Get Agent settings
            var settings = new AgentSettings
            {
                AcceptTeeEula = acceptTeeEula,
                AgentId = agent.Id,
                AgentName = agentName,
                NotificationPipeName = notificationPipeName,
                PoolId = poolId,
                PoolName = poolName,
                ServerUrl = serverUrl,
                WorkFolder = workFolder,
            };

            _store.SaveSettings(settings);
            _term.WriteLine(StringUtil.Loc("SavedSettings", DateTime.UtcNow));

            bool runAsService = false;

            if (Constants.Agent.Platform == Constants.OSPlatform.Windows)
            {
                runAsService = command.GetRunAsService();
            }

            var serviceControlManager = HostContext.GetService<IServiceControlManager>();
            serviceControlManager.GenerateScripts(settings);

            bool successfullyConfigured = false;
            if (runAsService)
            {
                Trace.Info("Configuring to run the agent as service");
                successfullyConfigured = serviceControlManager.ConfigureService(settings, command);
            }

            if (runAsService && successfullyConfigured)
            {
                Trace.Info("Configuration was successful, trying to start the service");
                serviceControlManager.StartService();
            }
        }
 private void btnSettings_Click(object sender, RoutedEventArgs e)
 {
     this.ReloadList(CommandSettings.ShowBox(this));
 }
        //process 2 new job messages, and one cancel message
        public async void TestRunAsync()
        {
            using (var hc = new TestHostContext(this))
            {
                //Arrange
                var agent = new Agent.Listener.Agent();
                hc.SetSingleton <IConfigurationManager>(_configurationManager.Object);
                hc.SetSingleton <IJobNotification>(_jobNotification.Object);
                hc.SetSingleton <IMessageListener>(_messageListener.Object);
                hc.SetSingleton <IPromptManager>(_promptManager.Object);
                hc.SetSingleton <IAgentServer>(_agentServer.Object);
                hc.SetSingleton <IVstsAgentWebProxy>(_proxy.Object);
                hc.SetSingleton <IAgentCertificateManager>(_cert.Object);
                hc.SetSingleton <IConfigurationStore>(_configStore.Object);
                agent.Initialize(hc);
                var settings = new AgentSettings
                {
                    PoolId = 43242
                };

                var message = new TaskAgentMessage()
                {
                    Body        = JsonUtility.ToString(CreateJobRequestMessage("job1")),
                    MessageId   = 4234,
                    MessageType = JobRequestMessageTypes.AgentJobRequest
                };

                var messages = new Queue <TaskAgentMessage>();
                messages.Enqueue(message);
                var signalWorkerComplete = new SemaphoreSlim(0, 1);
                _configurationManager.Setup(x => x.LoadSettings())
                .Returns(settings);
                _configurationManager.Setup(x => x.IsConfigured())
                .Returns(true);
                _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult <bool>(true));
                _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny <CancellationToken>()))
                .Returns(async() =>
                {
                    if (0 == messages.Count)
                    {
                        signalWorkerComplete.Release();
                        await Task.Delay(2000, hc.AgentShutdownToken);
                    }

                    return(messages.Dequeue());
                });
                _messageListener.Setup(x => x.DeleteSessionAsync())
                .Returns(Task.CompletedTask);
                _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny <TaskAgentMessage>()))
                .Returns(Task.CompletedTask);
                _jobDispatcher.Setup(x => x.Run(It.IsAny <Pipelines.AgentJobRequestMessage>(), It.IsAny <bool>()))
                .Callback(() =>
                {
                });
                _jobNotification.Setup(x => x.StartClient(It.IsAny <String>(), It.IsAny <String>(), It.IsAny <CancellationToken>()))
                .Callback(() =>
                {
                });
                _jobNotification.Setup(x => x.StartClient(It.IsAny <String>(), It.IsAny <String>()))
                .Callback(() =>
                {
                });

                hc.EnqueueInstance <IJobDispatcher>(_jobDispatcher.Object);

                _configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
                //Act
                var  command   = new CommandSettings(hc, new string[] { "run" });
                Task agentTask = agent.ExecuteCommand(command);

                //Assert
                //wait for the agent to run one job
                if (!await signalWorkerComplete.WaitAsync(2000))
                {
                    Assert.True(false, $"{nameof(_messageListener.Object.GetNextMessageAsync)} was not invoked.");
                }
                else
                {
                    //Act
                    hc.ShutdownAgent(ShutdownReason.UserCancelled); //stop Agent

                    //Assert
                    Task[] taskToWait2 = { agentTask, Task.Delay(2000) };
                    //wait for the Agent to exit
                    await Task.WhenAny(taskToWait2);

                    Assert.True(agentTask.IsCompleted, $"{nameof(agent.ExecuteCommand)} timed out.");
                    Assert.True(!agentTask.IsFaulted, agentTask.Exception?.ToString());
                    Assert.True(agentTask.IsCanceled);

                    _jobDispatcher.Verify(x => x.Run(It.IsAny <Pipelines.AgentJobRequestMessage>(), It.IsAny <bool>()), Times.Once(),
                                          $"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
                    _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny <CancellationToken>()), Times.AtLeastOnce());
                    _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny <CancellationToken>()), Times.Once());
                    _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
                    _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny <TaskAgentMessage>()), Times.AtLeastOnce());
                }
            }
        }
        public override bool ConfigureService(AgentSettings settings, CommandSettings command)
        {
            Trace.Entering();
            // TODO: add entering with info level. By default the error leve would be info. Config changes can get lost with this as entering is at Verbose level. For config all the logs should be logged.
            // TODO: Fix bug that exists in the legacy Windows agent where configuration using mirrored credentials causes an error, but the agent is still functional (after restarting). Mirrored credentials is a supported scenario and shouldn't manifest any errors.

            string logonPassword = string.Empty;

            NTAccount defaultServiceAccount = _windowsServiceHelper.GetDefaultServiceAccount();

            _logonAccount = command.GetWindowsLogonAccount(defaultValue: defaultServiceAccount.ToString());
            NativeWindowsServiceHelper.GetAccountSegments(_logonAccount, out _domainName, out _userName);
            if ((string.IsNullOrEmpty(_domainName) || _domainName.Equals(".", StringComparison.CurrentCultureIgnoreCase)) && !_logonAccount.Contains('@'))
            {
                _logonAccount = String.Format("{0}\\{1}", Environment.MachineName, _userName);
            }

            Trace.Info("LogonAccount after transforming: {0}, user: {1}, domain: {2}", _logonAccount, _userName, _domainName);
            if (!defaultServiceAccount.Equals(new NTAccount(_logonAccount)) &&
                !NativeWindowsServiceHelper.IsWellKnownIdentity(_logonAccount))
            {
                while (true)
                {
                    logonPassword = command.GetWindowsLogonPassword(_logonAccount);

                    // TODO: Fix this for unattended (should throw if not valid).
                    // TODO: If account is locked there is no point in retrying, translate error to useful message
                    if (_windowsServiceHelper.IsValidCredential(_domainName, _userName, logonPassword) || command.Unattended)
                    {
                        break;
                    }

                    Trace.Info("Invalid credential entered");
                    _term.WriteLine(StringUtil.Loc("InvalidWindowsCredential"));
                }
            }

            CalculateServiceName(settings, ServiceNamePattern, ServiceDisplayNamePattern);

            if (CheckServiceExists(ServiceName))
            {
                _term.WriteLine(StringUtil.Loc("ServiceAleadyExists"));

                StopService();
                UninstallService(ServiceName);
            }

            Trace.Info("Verifying if the account has LogonAsService permission");
            if (!_windowsServiceHelper.CheckUserHasLogonAsServicePrivilege(_domainName, _userName))
            {
                Trace.Info(StringUtil.Format("Account: {0} already has Logon As Service Privilege.", _logonAccount));
            }
            else
            {
                if (!_windowsServiceHelper.GrantUserLogonAsServicePrivilage(_domainName, _userName))
                {
                    throw new InvalidOperationException(StringUtil.Loc("CanNotGrantPermission", _logonAccount));
                }
            }

            _windowsServiceHelper.InstallService(ServiceName, ServiceDisplayName, _logonAccount, logonPassword);

            SaveServiceSettings();

            // TODO: If its service identity add it to appropriate PoolGroup
            // TODO: Add registry key after installation
            return(true);
        }
 public object Get(CommandSettings settings)
 {
     return(Property.GetValue(settings));
 }
        public async Task UnconfigureAsync(CommandSettings command)
        {
            string currentAction = StringUtil.Loc("UninstallingService");
            try
            {
                //stop, uninstall service and remove service config file
                _term.WriteLine(currentAction);
                if (_store.IsServiceConfigured())
                {
                    var serviceControlManager = HostContext.GetService<IServiceControlManager>();
                    serviceControlManager.UnconfigureService();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }

                //delete agent from the server
                currentAction = StringUtil.Loc("UnregisteringAgent");
                _term.WriteLine(currentAction);
                bool isConfigured = _store.IsConfigured();
                bool hasCredentials = _store.HasCredentials();
                if (isConfigured && hasCredentials)
                {
                    AgentSettings settings = _store.GetSettings();
                    var credentialManager = HostContext.GetService<ICredentialManager>();

                    // Get the credentials
                    var credProvider = GetCredentialProvider(command, settings.ServerUrl);
                    VssCredentials creds = credProvider.GetVssCredentials(HostContext);
                    Trace.Info("cred retrieved");

                    Uri uri = new Uri(settings.ServerUrl);
                    VssConnection conn = ApiUtil.CreateConnection(uri, creds);
                    var agentSvr = HostContext.GetService<IAgentServer>();
                    await agentSvr.ConnectAsync(conn);
                    Trace.Info("Connect complete.");

                    List<TaskAgent> agents = await agentSvr.GetAgentsAsync(settings.PoolId, settings.AgentName);
                    if (agents.Count == 0)
                    {
                        _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                    }
                    else
                    {
                        await agentSvr.DeleteAgentAsync(settings.PoolId, settings.AgentId);
                        _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                    }
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("MissingConfig"));
                }

                //delete credential config files               
                currentAction = StringUtil.Loc("DeletingCredentials");
                _term.WriteLine(currentAction);
                if (hasCredentials)
                {
                    _store.DeleteCredential();
                    var keyManager = HostContext.GetService<IRSAKeyManager>();
                    keyManager.DeleteKey();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                }

                //delete settings config file                
                currentAction = StringUtil.Loc("DeletingSettings");
                _term.WriteLine(currentAction);
                if (isConfigured)
                {
                    _store.DeleteSettings();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                }
            }
            catch (Exception)
            {
                _term.WriteLine(StringUtil.Loc("Failed") + currentAction);
                throw;
            }
        }
        public async Task UnconfigureAsync(CommandSettings command)
        {
            ArgUtil.NotNull(command, nameof(command));
            string currentAction = string.Empty;

            try
            {
                //stop, uninstall service and remove service config file
                if (_store.IsServiceConfigured())
                {
                    currentAction = StringUtil.Loc("UninstallingService");
                    _term.WriteLine(currentAction);
                    if (PlatformUtil.RunningOnWindows)
                    {
                        var serviceControlManager = HostContext.GetService <IWindowsServiceControlManager>();
                        serviceControlManager.UnconfigureService();
                        _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                    }
                    else if (PlatformUtil.RunningOnLinux)
                    {
                        // unconfig systemd service first
                        throw new Exception(StringUtil.Loc("UnconfigureServiceDService"));
                    }
                    else if (PlatformUtil.RunningOnMacOS)
                    {
                        // unconfig macOS service first
                        throw new Exception(StringUtil.Loc("UnconfigureOSXService"));
                    }
                }
                else
                {
                    if (PlatformUtil.RunningOnWindows)
                    {
                        //running as process, unconfigure autologon if it was configured
                        if (_store.IsAutoLogonConfigured())
                        {
                            currentAction = StringUtil.Loc("UnconfigAutologon");
                            _term.WriteLine(currentAction);
                            var autoLogonConfigManager = HostContext.GetService <IAutoLogonManager>();
                            autoLogonConfigManager.Unconfigure();
                            _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                        }
                        else
                        {
                            Trace.Info("AutoLogon was not configured on the agent.");
                        }
                    }
                }

                //delete agent from the server
                currentAction = StringUtil.Loc("UnregisteringAgent");
                _term.WriteLine(currentAction);
                bool isConfigured   = _store.IsConfigured();
                bool hasCredentials = _store.HasCredentials();
                if (isConfigured && hasCredentials)
                {
                    AgentSettings settings          = _store.GetSettings();
                    var           credentialManager = HostContext.GetService <ICredentialManager>();

                    // Get the credentials
                    var            credProvider = GetCredentialProvider(command, settings.ServerUrl);
                    VssCredentials creds        = credProvider.GetVssCredentials(HostContext);
                    Trace.Info("cred retrieved");

                    bool isEnvironmentVMResource = false;
                    bool isDeploymentGroup       = (settings.MachineGroupId > 0) || (settings.DeploymentGroupId > 0);
                    if (!isDeploymentGroup)
                    {
                        isEnvironmentVMResource = settings.EnvironmentId > 0;
                    }

                    Trace.Info("Agent configured for deploymentGroup : {0}", isDeploymentGroup.ToString());

                    string agentType = isDeploymentGroup
                   ? Constants.Agent.AgentConfigurationProvider.DeploymentAgentConfiguration
                   : isEnvironmentVMResource
                   ? Constants.Agent.AgentConfigurationProvider.EnvironmentVMResourceConfiguration
                   : Constants.Agent.AgentConfigurationProvider.BuildReleasesAgentConfiguration;

                    var extensionManager = HostContext.GetService <IExtensionManager>();
                    IConfigurationProvider agentProvider = (extensionManager.GetExtensions <IConfigurationProvider>()).FirstOrDefault(x => x.ConfigurationProviderType == agentType);
                    ArgUtil.NotNull(agentProvider, agentType);

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

                    await agentProvider.TestConnectionAsync(settings, creds, isHostedServer);

                    TaskAgent agent = await agentProvider.GetAgentAsync(settings);

                    if (agent == null)
                    {
                        _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                    }
                    else
                    {
                        await agentProvider.DeleteAgentAsync(settings);

                        _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                    }
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("MissingConfig"));
                }

                //delete credential config files
                currentAction = StringUtil.Loc("DeletingCredentials");
                _term.WriteLine(currentAction);
                if (hasCredentials)
                {
                    _store.DeleteCredential();
                    var keyManager = HostContext.GetService <IRSAKeyManager>();
                    keyManager.DeleteKey();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                }

                //delete settings config file
                currentAction = StringUtil.Loc("DeletingSettings");
                _term.WriteLine(currentAction);
                if (isConfigured)
                {
                    // delete proxy setting
                    (HostContext.GetService <IVstsAgentWebProxy>() as VstsAgentWebProxy).DeleteProxySetting();

                    // delete agent cert setting
                    (HostContext.GetService <IAgentCertificateManager>() as AgentCertificateManager).DeleteCertificateSetting();

                    // delete agent runtime option
                    _store.DeleteAgentRuntimeOptions();

                    _store.DeleteSettings();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                }
            }
            catch (Exception)
            {
                _term.WriteLine(StringUtil.Loc("Failed") + currentAction);
                throw;
            }
        }
Example #30
0
        private async Task GetAndAddTags(DeploymentMachine deploymentMachine, AgentSettings agentSettings, CommandSettings command)
        {
            // Get and apply Tags in case agent is configured against Deployment Group
            if (command.GetDeploymentGroupTagsRequired())
            {
                try
                {
                    string tagString = command.GetDeploymentGroupTags();
                    Trace.Info("Given tags - {0} will be processed and added", tagString);

                    if (!string.IsNullOrWhiteSpace(tagString))
                    {
                        var tagsList =
                            tagString.Split(',').Where(s => !string.IsNullOrWhiteSpace(s))
                            .Select(s => s.Trim())
                            .Distinct(StringComparer.CurrentCultureIgnoreCase).ToList();

                        if (tagsList.Any())
                        {
                            Trace.Info("Adding tags - {0}", string.Join(",", tagsList.ToArray()));

                            deploymentMachine.Tags = tagsList;
                            await _deploymentGroupServer.UpdateDeploymentTargetsAsync(new Guid(agentSettings.ProjectId), agentSettings.DeploymentGroupId, new List <DeploymentMachine>() { deploymentMachine });

                            _term.WriteLine(StringUtil.Loc("DeploymentGroupTagsAddedMsg"));
                        }
                    }
                }
                catch (Exception e) when(!command.Unattended())
                {
                    _term.WriteError(e);
                    _term.WriteError(StringUtil.Loc("FailedToAddTags"));
                }
            }
        }
Example #31
0
        public async Task UnconfigureAsync(CommandSettings command)
        {
            ArgUtil.Equal(RunMode.Normal, HostContext.RunMode, nameof(HostContext.RunMode));
            string currentAction = string.Empty;

            try
            {
                //stop, uninstall service and remove service config file
                if (_store.IsServiceConfigured())
                {
                    currentAction = StringUtil.Loc("UninstallingService");
                    _term.WriteLine(currentAction);
#if OS_WINDOWS
                    var serviceControlManager = HostContext.GetService <IWindowsServiceControlManager>();
                    serviceControlManager.UnconfigureService();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
#elif OS_LINUX
                    // unconfig system D service first
                    throw new Exception(StringUtil.Loc("UnconfigureServiceDService"));
#elif OS_OSX
                    // unconfig osx service first
                    throw new Exception(StringUtil.Loc("UnconfigureOSXService"));
#endif
                }
                else
                {
#if OS_WINDOWS
                    //running as process, unconfigure autologon if it was configured
                    if (_store.IsAutoLogonConfigured())
                    {
                        currentAction = StringUtil.Loc("UnconfigAutologon");
                        _term.WriteLine(currentAction);
                        var autoLogonConfigManager = HostContext.GetService <IAutoLogonManager>();
                        autoLogonConfigManager.Unconfigure();
                        _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                    }
                    else
                    {
                        Trace.Info("AutoLogon was not configured on the agent.");
                    }
#endif
                }

                //delete agent from the server
                currentAction = StringUtil.Loc("UnregisteringAgent");
                _term.WriteLine(currentAction);
                bool isConfigured   = _store.IsConfigured();
                bool hasCredentials = _store.HasCredentials();
                if (isConfigured && hasCredentials)
                {
                    AgentSettings settings          = _store.GetSettings();
                    var           credentialManager = HostContext.GetService <ICredentialManager>();

                    // Get the credentials
                    var            credProvider = GetCredentialProvider(command, settings.ServerUrl);
                    VssCredentials creds        = credProvider.GetVssCredentials(HostContext);
                    Trace.Info("cred retrieved");

                    bool isDeploymentGroup = (settings.MachineGroupId > 0) || (settings.DeploymentGroupId > 0);

                    Trace.Info("Agent configured for deploymentGroup : {0}", isDeploymentGroup.ToString());

                    string agentType = isDeploymentGroup
                   ? Constants.Agent.AgentConfigurationProvider.DeploymentAgentConfiguration
                   : Constants.Agent.AgentConfigurationProvider.BuildReleasesAgentConfiguration;

                    var extensionManager = HostContext.GetService <IExtensionManager>();
                    IConfigurationProvider agentProvider = (extensionManager.GetExtensions <IConfigurationProvider>()).FirstOrDefault(x => x.ConfigurationProviderType == agentType);
                    ArgUtil.NotNull(agentProvider, agentType);

                    await agentProvider.TestConnectionAsync(settings, creds);

                    TaskAgent agent = await agentProvider.GetAgentAsync(settings);

                    if (agent == null)
                    {
                        _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                    }
                    else
                    {
                        await agentProvider.DeleteAgentAsync(settings);

                        _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                    }
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("MissingConfig"));
                }

                //delete credential config files
                currentAction = StringUtil.Loc("DeletingCredentials");
                _term.WriteLine(currentAction);
                if (hasCredentials)
                {
                    _store.DeleteCredential();
                    var keyManager = HostContext.GetService <IRSAKeyManager>();
                    keyManager.DeleteKey();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                }

                //delete settings config file
                currentAction = StringUtil.Loc("DeletingSettings");
                _term.WriteLine(currentAction);
                if (isConfigured)
                {
                    // delete proxy setting
                    (HostContext.GetService <IVstsAgentWebProxy>() as VstsAgentWebProxy).DeleteProxySetting();

                    // delete agent cert setting
                    (HostContext.GetService <IAgentCertificateManager>() as AgentCertificateManager).DeleteCertificateSetting();

                    _store.DeleteSettings();
                    _term.WriteLine(StringUtil.Loc("Success") + currentAction);
                }
                else
                {
                    _term.WriteLine(StringUtil.Loc("Skipping") + currentAction);
                }
            }
            catch (Exception)
            {
                _term.WriteLine(StringUtil.Loc("Failed") + currentAction);
                throw;
            }
        }
        public async void TestRunOnceHandleUpdateMessage()
        {
            using (var hc = new TestHostContext(this))
            {
                //Arrange
                var agent = new Agent.Listener.Agent();
                hc.SetSingleton <IConfigurationManager>(_configurationManager.Object);
                hc.SetSingleton <IJobNotification>(_jobNotification.Object);
                hc.SetSingleton <IMessageListener>(_messageListener.Object);
                hc.SetSingleton <IPromptManager>(_promptManager.Object);
                hc.SetSingleton <IAgentServer>(_agentServer.Object);
                hc.SetSingleton <IVstsAgentWebProxy>(_proxy.Object);
                hc.SetSingleton <IAgentCertificateManager>(_cert.Object);
                hc.SetSingleton <IConfigurationStore>(_configStore.Object);
                hc.SetSingleton <ISelfUpdater>(_updater.Object);

                agent.Initialize(hc);
                var settings = new AgentSettings
                {
                    PoolId  = 43242,
                    AgentId = 5678
                };

                var message1 = new TaskAgentMessage()
                {
                    Body        = JsonUtility.ToString(new AgentRefreshMessage(settings.AgentId, "2.123.0")),
                    MessageId   = 4234,
                    MessageType = AgentRefreshMessage.MessageType
                };

                var messages = new Queue <TaskAgentMessage>();
                messages.Enqueue(message1);
                _updater.Setup(x => x.SelfUpdate(It.IsAny <AgentRefreshMessage>(), It.IsAny <IJobDispatcher>(), It.IsAny <bool>(), It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult(true));
                _configurationManager.Setup(x => x.LoadSettings())
                .Returns(settings);
                _configurationManager.Setup(x => x.IsConfigured())
                .Returns(true);
                _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult <bool>(true));
                _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny <CancellationToken>()))
                .Returns(async() =>
                {
                    if (0 == messages.Count)
                    {
                        await Task.Delay(2000);
                    }

                    return(messages.Dequeue());
                });
                _messageListener.Setup(x => x.DeleteSessionAsync())
                .Returns(Task.CompletedTask);
                _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny <TaskAgentMessage>()))
                .Returns(Task.CompletedTask);
                _jobNotification.Setup(x => x.StartClient(It.IsAny <String>(), It.IsAny <String>(), It.IsAny <CancellationToken>()))
                .Callback(() =>
                {
                });
                _jobNotification.Setup(x => x.StartClient(It.IsAny <String>(), It.IsAny <String>()))
                .Callback(() =>
                {
                });

                hc.EnqueueInstance <IJobDispatcher>(_jobDispatcher.Object);

                _configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
                //Act
                var        command   = new CommandSettings(hc, new string[] { "run", "--once" });
                Task <int> agentTask = agent.ExecuteCommand(command);

                //Assert
                //wait for the agent to exit with right return code
                await Task.WhenAny(agentTask, Task.Delay(30000));

                Assert.True(agentTask.IsCompleted, $"{nameof(agent.ExecuteCommand)} timed out.");
                Assert.True(!agentTask.IsFaulted, agentTask.Exception?.ToString());
                Assert.True(agentTask.Result == Constants.Agent.ReturnCode.RunOnceAgentUpdating);

                _updater.Verify(x => x.SelfUpdate(It.IsAny <AgentRefreshMessage>(), It.IsAny <IJobDispatcher>(), false, It.IsAny <CancellationToken>()), Times.Once);
                _jobDispatcher.Verify(x => x.Run(It.IsAny <Pipelines.AgentJobRequestMessage>(), true), Times.Never());
                _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny <CancellationToken>()), Times.AtLeastOnce());
                _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny <CancellationToken>()), Times.Once());
                _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
                _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny <TaskAgentMessage>()), Times.Once());
            }
        }
Example #33
0
        public override async Task <TaskAgent> AddAgentAsync(AgentSettings agentSettings, TaskAgent agent, CommandSettings command)
        {
            ArgUtil.NotNull(agentSettings, nameof(agentSettings));
            ArgUtil.NotNull(agent, nameof(agent));
            ArgUtil.NotNull(command, nameof(command));
            var virtualMachine = new VirtualMachineResource()
            {
                Name = agent.Name, Agent = agent
            };
            var tags = GetVirtualMachineResourceTags(command);

            virtualMachine.Tags = tags;

            virtualMachine = await _environmentsServer.AddEnvironmentVMAsync(new Guid(agentSettings.ProjectId), agentSettings.EnvironmentId, virtualMachine);

            Trace.Info("Environment virtual machine resource with name: '{0}', id: '{1}' has been added successfully.", virtualMachine.Name, virtualMachine.Id);

            var pool = await _environmentsServer.GetEnvironmentPoolAsync(new Guid(agentSettings.ProjectId), agentSettings.EnvironmentId);

            Trace.Info("environment pool id: '{0}'", pool.Id);
            agentSettings.PoolId    = pool.Id;
            agentSettings.AgentName = virtualMachine.Name;
            agentSettings.EnvironmentVMResourceId = virtualMachine.Id;

            return(virtualMachine.Agent);
        }
 public void Assign(CommandSettings settings, object value)
 {
     Property.SetValue(settings, value);
 }
Example #35
0
        public override async Task <TaskAgent> UpdateAgentAsync(AgentSettings agentSettings, TaskAgent agent, CommandSettings command)
        {
            ArgUtil.NotNull(agentSettings, nameof(agentSettings));
            ArgUtil.NotNull(command, nameof(command));
            var tags = GetVirtualMachineResourceTags(command);

            var vmResource = (await GetEnvironmentVMsAsync(agentSettings)).FirstOrDefault();

            vmResource.Agent = agent;
            vmResource.Tags  = tags;
            Trace.Info("Replacing environment virtual machine resource with id: '{0}'", vmResource.Id);
            vmResource = await _environmentsServer.ReplaceEnvironmentVMAsync(new Guid(agentSettings.ProjectId), agentSettings.EnvironmentId, vmResource);

            Trace.Info("environment virtual machine resource with id: '{0}' has been replaced successfully", vmResource.Id);
            var pool = await _environmentsServer.GetEnvironmentPoolAsync(new Guid(agentSettings.ProjectId), agentSettings.EnvironmentId);

            agentSettings.AgentName = vmResource.Name;
            agentSettings.EnvironmentVMResourceId = vmResource.Id;
            agentSettings.PoolId = pool.Id;

            return(vmResource.Agent);
        }
Example #36
0
        public void ConfigureService(AgentSettings settings, CommandSettings command)
        {
            Trace.Entering();

            if (!_windowsServiceHelper.IsRunningInElevatedMode())
            {
                Trace.Error("Needs Administrator privileges for configure agent as windows service.");
                throw new SecurityException(StringUtil.Loc("NeedAdminForConfigAgentWinService"));
            }

            // TODO: Fix bug that exists in the legacy Windows agent where configuration using mirrored credentials causes an error, but the agent is still functional (after restarting). Mirrored credentials is a supported scenario and shouldn't manifest any errors.

            // We use NetworkService as default account for build and release agent
            // We use Local System as default account for deployment agent, deployment pool agent, environment vm agent
            bool      isDeploymentGroupScenario = command.GetDeploymentOrMachineGroup() || command.GetDeploymentPool() || command.GetEnvironmentVMResource();
            NTAccount defaultServiceAccount     = isDeploymentGroupScenario ? _windowsServiceHelper.GetDefaultAdminServiceAccount() : _windowsServiceHelper.GetDefaultServiceAccount();
            string    logonAccount = command.GetWindowsLogonAccount(defaultValue: defaultServiceAccount.ToString(), descriptionMsg: StringUtil.Loc("WindowsLogonAccountNameDescription"));

            string domainName;
            string userName;

            GetAccountSegments(logonAccount, out domainName, out userName);

            if ((string.IsNullOrEmpty(domainName) || domainName.Equals(".", StringComparison.CurrentCultureIgnoreCase)) && !logonAccount.Contains('@'))
            {
                logonAccount = String.Format("{0}\\{1}", Environment.MachineName, userName);
                domainName   = Environment.MachineName;
            }

            Trace.Info("LogonAccount after transforming: {0}, user: {1}, domain: {2}", logonAccount, userName, domainName);

            string logonPassword = string.Empty;

            if (!defaultServiceAccount.Equals(new NTAccount(logonAccount)) && !NativeWindowsServiceHelper.IsWellKnownIdentity(logonAccount))
            {
                while (true)
                {
                    logonPassword = command.GetWindowsLogonPassword(logonAccount);
                    if (_windowsServiceHelper.IsValidCredential(domainName, userName, logonPassword))
                    {
                        Trace.Info("Credential validation succeed");
                        break;
                    }
                    else
                    {
                        if (!command.Unattended())
                        {
                            Trace.Info("Invalid credential entered");
                            _term.WriteLine(StringUtil.Loc("InvalidWindowsCredential"));
                        }
                        else
                        {
                            throw new SecurityException(StringUtil.Loc("InvalidWindowsCredential"));
                        }
                    }
                }
            }

            string serviceName;
            string serviceDisplayName;

            CalculateServiceName(settings, ServiceNamePattern, ServiceDisplayNamePattern, out serviceName, out serviceDisplayName);
            if (_windowsServiceHelper.IsServiceExists(serviceName))
            {
                _term.WriteLine(StringUtil.Loc("ServiceAlreadyExists", serviceName));
                _windowsServiceHelper.UninstallService(serviceName);
            }

            Trace.Info("Verifying if the account has LogonAsService permission");
            if (_windowsServiceHelper.IsUserHasLogonAsServicePrivilege(domainName, userName))
            {
                Trace.Info($"Account: {logonAccount} already has Logon As Service Privilege.");
            }
            else
            {
                if (!_windowsServiceHelper.GrantUserLogonAsServicePrivilage(domainName, userName))
                {
                    throw new InvalidOperationException(StringUtil.Loc("CanNotGrantPermission", logonAccount));
                }
            }

            // grant permission for agent root folder and work folder
            Trace.Info("Create local group and grant folder permission to service logon account.");
            string agentRoot  = HostContext.GetDirectory(WellKnownDirectory.Root);
            string workFolder = HostContext.GetDirectory(WellKnownDirectory.Work);

            Directory.CreateDirectory(workFolder);
            _windowsServiceHelper.GrantDirectoryPermissionForAccount(logonAccount, new[] { agentRoot, workFolder });
            _term.WriteLine(StringUtil.Loc("GrantingFilePermissions", logonAccount));

            // install service.
            _windowsServiceHelper.InstallService(serviceName, serviceDisplayName, logonAccount, logonPassword);

            // create .service file with service name.
            SaveServiceSettings(serviceName);

            // Add registry key after installation
            _windowsServiceHelper.CreateVstsAgentRegistryKey();

            Trace.Info("Configuration was successful, trying to start the service");
            _windowsServiceHelper.StartService(serviceName);
        }
Example #37
0
 public void GetServerUrl(AgentSettings agentSettings, CommandSettings command)
 {
     ArgUtil.NotNull(agentSettings, nameof(agentSettings));
     ArgUtil.NotNull(command, nameof(command));
     agentSettings.ServerUrl = command.GetUrl();
 }
        public async Task ConfigureAsync(CommandSettings command)
        {
            ArgUtil.NotNull(command, nameof(command));
            Trace.Info(nameof(ConfigureAsync));
            if (IsConfigured())
            {
                throw new InvalidOperationException(StringUtil.Loc("AlreadyConfiguredError"));
            }

            // Populate proxy setting from commandline args
            var    vstsProxy        = HostContext.GetService <IVstsAgentWebProxy>();
            bool   saveProxySetting = false;
            string proxyUrl         = command.GetProxyUrl();

            if (!string.IsNullOrEmpty(proxyUrl))
            {
                if (!Uri.IsWellFormedUriString(proxyUrl, UriKind.Absolute))
                {
                    throw new ArgumentOutOfRangeException(nameof(proxyUrl));
                }

                Trace.Info("Reset proxy base on commandline args.");
                string proxyUserName = command.GetProxyUserName();
                string proxyPassword = command.GetProxyPassword();
                (vstsProxy as VstsAgentWebProxy).SetupProxy(proxyUrl, proxyUserName, proxyPassword);
                saveProxySetting = true;
            }

            // Populate cert setting from commandline args
            var    agentCertManager   = HostContext.GetService <IAgentCertificateManager>();
            bool   saveCertSetting    = false;
            bool   skipCertValidation = command.GetSkipCertificateValidation();
            string caCert             = command.GetCACertificate();
            string clientCert         = command.GetClientCertificate();
            string clientCertKey      = command.GetClientCertificatePrivateKey();
            string clientCertArchive  = command.GetClientCertificateArchrive();
            string clientCertPassword = command.GetClientCertificatePassword();

            // We require all Certificate files are under agent root.
            // So we can set ACL correctly when configure as service
            if (!string.IsNullOrEmpty(caCert))
            {
                caCert = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), caCert);
                ArgUtil.File(caCert, nameof(caCert));
            }

            if (!string.IsNullOrEmpty(clientCert) &&
                !string.IsNullOrEmpty(clientCertKey) &&
                !string.IsNullOrEmpty(clientCertArchive))
            {
                // Ensure all client cert pieces are there.
                clientCert        = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), clientCert);
                clientCertKey     = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), clientCertKey);
                clientCertArchive = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), clientCertArchive);

                ArgUtil.File(clientCert, nameof(clientCert));
                ArgUtil.File(clientCertKey, nameof(clientCertKey));
                ArgUtil.File(clientCertArchive, nameof(clientCertArchive));
            }
            else if (!string.IsNullOrEmpty(clientCert) ||
                     !string.IsNullOrEmpty(clientCertKey) ||
                     !string.IsNullOrEmpty(clientCertArchive))
            {
                // Print out which args are missing.
                ArgUtil.NotNullOrEmpty(Constants.Agent.CommandLine.Args.SslClientCert, Constants.Agent.CommandLine.Args.SslClientCert);
                ArgUtil.NotNullOrEmpty(Constants.Agent.CommandLine.Args.SslClientCertKey, Constants.Agent.CommandLine.Args.SslClientCertKey);
                ArgUtil.NotNullOrEmpty(Constants.Agent.CommandLine.Args.SslClientCertArchive, Constants.Agent.CommandLine.Args.SslClientCertArchive);
            }

            if (skipCertValidation || !string.IsNullOrEmpty(caCert) || !string.IsNullOrEmpty(clientCert))
            {
                Trace.Info("Reset agent cert setting base on commandline args.");
                (agentCertManager as AgentCertificateManager).SetupCertificate(skipCertValidation, caCert, clientCert, clientCertKey, clientCertArchive, clientCertPassword);
                saveCertSetting = true;
            }

            AgentSettings agentSettings = new AgentSettings();

            // TEE EULA
            agentSettings.AcceptTeeEula = false;
            switch (PlatformUtil.HostOS)
            {
            case PlatformUtil.OS.OSX:
            case PlatformUtil.OS.Linux:
                // Write the section header.
                WriteSection(StringUtil.Loc("EulasSectionHeader"));

                // Verify the EULA exists on disk in the expected location.
                string eulaFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), Constants.Path.TeeDirectory, "license.html");
                ArgUtil.File(eulaFile, nameof(eulaFile));

                // Write elaborate verbiage about the TEE EULA.
                _term.WriteLine(StringUtil.Loc("TeeEula", eulaFile));
                _term.WriteLine();

                // Prompt to acccept the TEE EULA.
                agentSettings.AcceptTeeEula = command.GetAcceptTeeEula();
                break;

            case PlatformUtil.OS.Windows:
                // Warn and continue if .NET 4.6 is not installed.
                if (!NetFrameworkUtil.Test(new Version(4, 6), Trace))
                {
                    WriteSection(StringUtil.Loc("PrerequisitesSectionHeader"));     // Section header.
                    _term.WriteLine(StringUtil.Loc("MinimumNetFrameworkTfvc"));     // Warning.
                }

                break;

            default:
                throw new NotSupportedException();
            }

            // Create the configuration provider as per agent type.
            string agentType;

            if (command.GetDeploymentOrMachineGroup())
            {
                agentType = Constants.Agent.AgentConfigurationProvider.DeploymentAgentConfiguration;
            }
            else if (command.GetDeploymentPool())
            {
                agentType = Constants.Agent.AgentConfigurationProvider.SharedDeploymentAgentConfiguration;
            }
            else if (command.GetEnvironmentVMResource())
            {
                agentType = Constants.Agent.AgentConfigurationProvider.EnvironmentVMResourceConfiguration;
            }
            else
            {
                agentType = Constants.Agent.AgentConfigurationProvider.BuildReleasesAgentConfiguration;
            }

            var extensionManager = HostContext.GetService <IExtensionManager>();
            IConfigurationProvider agentProvider =
                (extensionManager.GetExtensions <IConfigurationProvider>())
                .FirstOrDefault(x => x.ConfigurationProviderType == agentType);

            ArgUtil.NotNull(agentProvider, agentType);

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

            WriteSection(StringUtil.Loc("ConnectSectionHeader"));
            while (true)
            {
                // Get the URL
                agentProvider.GetServerUrl(agentSettings, command);

                // Get the credentials
                credProvider = GetCredentialProvider(command, agentSettings.ServerUrl);
                creds        = credProvider.GetVssCredentials(HostContext);
                Trace.Info("cred retrieved");
                try
                {
                    // Determine the service deployment type based on connection data. (Hosted/OnPremises)
                    isHostedServer = await IsHostedServer(agentSettings.ServerUrl, creds);

                    // Get the collection name for deployment group
                    agentProvider.GetCollectionName(agentSettings, command, isHostedServer);

                    // Validate can connect.
                    await agentProvider.TestConnectionAsync(agentSettings, creds, isHostedServer);

                    Trace.Info("Test Connection complete.");
                    break;
                }
                catch (Exception e) when(!command.Unattended())
                {
                    _term.WriteError(e);
                    _term.WriteError(StringUtil.Loc("FailedToConnect"));
                }
            }

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

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

            // Loop getting agent name and pool name
            WriteSection(StringUtil.Loc("RegisterAgentSectionHeader"));

            while (true)
            {
                try
                {
                    await agentProvider.GetPoolIdAndName(agentSettings, command);

                    break;
                }
                catch (Exception e) when(!command.Unattended())
                {
                    _term.WriteError(e);
                    _term.WriteError(agentProvider.GetFailedToFindPoolErrorString());
                }
            }

            TaskAgent agent;

            while (true)
            {
                agentSettings.AgentName = command.GetAgentName();

                // Get the system capabilities.
                // TODO: Hook up to ctrl+c cancellation token.
                _term.WriteLine(StringUtil.Loc("ScanToolCapabilities"));
                Dictionary <string, string> systemCapabilities = await HostContext.GetService <ICapabilitiesManager>().GetCapabilitiesAsync(agentSettings, CancellationToken.None);

                _term.WriteLine(StringUtil.Loc("ConnectToServer"));
                agent = await agentProvider.GetAgentAsync(agentSettings);

                if (agent != null)
                {
                    if (command.GetReplace())
                    {
                        // Update existing agent with new PublicKey, agent version and SystemCapabilities.
                        agent = UpdateExistingAgent(agent, publicKey, systemCapabilities);

                        try
                        {
                            agent = await agentProvider.UpdateAgentAsync(agentSettings, agent, command);

                            _term.WriteLine(StringUtil.Loc("AgentReplaced"));
                            break;
                        }
                        catch (Exception e) when(!command.Unattended())
                        {
                            _term.WriteError(e);
                            _term.WriteError(StringUtil.Loc("FailedToReplaceAgent"));
                        }
                    }
                    else if (command.Unattended())
                    {
                        // if not replace and it is unattended config.
                        agentProvider.ThrowTaskAgentExistException(agentSettings);
                    }
                }
                else
                {
                    // Create a new agent.
                    agent = CreateNewAgent(agentSettings.AgentName, publicKey, systemCapabilities);

                    try
                    {
                        agent = await agentProvider.AddAgentAsync(agentSettings, agent, command);

                        _term.WriteLine(StringUtil.Loc("AgentAddedSuccessfully"));
                        break;
                    }
                    catch (Exception e) when(!command.Unattended())
                    {
                        _term.WriteError(e);
                        _term.WriteError(StringUtil.Loc("AddAgentFailed"));
                    }
                }
            }
            // Add Agent Id to settings
            agentSettings.AgentId = agent.Id;

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

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

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

            // See if the server supports our OAuth key exchange for credentials
            if (agent.Authorization != null &&
                agent.Authorization.ClientId != Guid.Empty &&
                agent.Authorization.AuthorizationUrl != null)
            {
                // We use authorizationUrl as the oauth endpoint url by default.
                // For TFS, we need make sure the Schema/Host/Port component of the oauth endpoint url also match configuration url. (Incase of customer's agent configure URL and TFS server public URL are different)
                // Which means, we will keep use the original authorizationUrl in the VssOAuthJwtBearerClientCredential (authorizationUrl is the audience),
                // But might have different Url in VssOAuthCredential (connection url)
                // We can't do this for VSTS, since its SPS/TFS urls are different.
                UriBuilder configServerUrl         = new UriBuilder(agentSettings.ServerUrl);
                UriBuilder oauthEndpointUrlBuilder = new UriBuilder(agent.Authorization.AuthorizationUrl);
                if (!isHostedServer && Uri.Compare(configServerUrl.Uri, oauthEndpointUrlBuilder.Uri, UriComponents.SchemeAndServer, UriFormat.Unescaped, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    oauthEndpointUrlBuilder.Scheme = configServerUrl.Scheme;
                    oauthEndpointUrlBuilder.Host   = configServerUrl.Host;
                    oauthEndpointUrlBuilder.Port   = configServerUrl.Port;
                    Trace.Info($"Set oauth endpoint url's scheme://host:port component to match agent configure url's scheme://host:port: '{oauthEndpointUrlBuilder.Uri.AbsoluteUri}'.");
                }

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

                // Save the negotiated OAuth credential data
                _store.SaveCredential(credentialData);
            }
            else
            {
                switch (PlatformUtil.HostOS)
                {
                case PlatformUtil.OS.OSX:
                case PlatformUtil.OS.Linux:
                    // Save the provided admin cred for compat with previous agent.
                    _store.SaveCredential(credProvider.CredentialData);
                    break;

                case PlatformUtil.OS.Windows:
                    // Not supported against TFS 2015.
                    _term.WriteError(StringUtil.Loc("Tfs2015NotSupported"));
                    return;

                default:
                    throw new NotSupportedException();
                }
            }

            // Testing agent connection, detect any protential connection issue, like local clock skew that cause OAuth token expired.
            _term.WriteLine(StringUtil.Loc("TestAgentConnection"));
            var            credMgr    = HostContext.GetService <ICredentialManager>();
            VssCredentials credential = credMgr.LoadCredentials();
            var            agentSvr   = HostContext.GetService <IAgentServer>();

            try
            {
                await agentSvr.ConnectAsync(new Uri(agentSettings.ServerUrl), credential);
            }
            catch (VssOAuthTokenRequestException ex) when(ex.Message.Contains("Current server time is"))
            {
                // there are two exception messages server send that indicate clock skew.
                // 1. The bearer token expired on {jwt.ValidTo}. Current server time is {DateTime.UtcNow}.
                // 2. The bearer token is not valid until {jwt.ValidFrom}. Current server time is {DateTime.UtcNow}.
                Trace.Error("Catch exception during test agent connection.");
                Trace.Error(ex);
                throw new Exception(StringUtil.Loc("LocalClockSkewed"));
            }

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

            // notificationPipeName for Hosted agent provisioner.
            agentSettings.NotificationPipeName = command.GetNotificationPipeName();

            agentSettings.MonitorSocketAddress = command.GetMonitorSocketAddress();

            agentSettings.NotificationSocketAddress = command.GetNotificationSocketAddress();

            _store.SaveSettings(agentSettings);

            if (saveProxySetting)
            {
                Trace.Info("Save proxy setting to disk.");
                (vstsProxy as VstsAgentWebProxy).SaveProxySetting();
            }

            if (saveCertSetting)
            {
                Trace.Info("Save agent cert setting to disk.");
                (agentCertManager as AgentCertificateManager).SaveCertificateSetting();
            }

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

            bool saveRuntimeOptions = false;
            var  runtimeOptions     = new AgentRuntimeOptions();

            if (PlatformUtil.RunningOnWindows && command.GetGitUseSChannel())
            {
                saveRuntimeOptions = true;
                runtimeOptions.GitUseSecureChannel = true;
            }
            if (saveRuntimeOptions)
            {
                Trace.Info("Save agent runtime options to disk.");
                _store.SaveAgentRuntimeOptions(runtimeOptions);
            }

            if (PlatformUtil.RunningOnWindows)
            {
                // config windows service
                bool runAsService = command.GetRunAsService();
                if (runAsService)
                {
                    Trace.Info("Configuring to run the agent as service");
                    var serviceControlManager = HostContext.GetService <IWindowsServiceControlManager>();
                    serviceControlManager.ConfigureService(agentSettings, command);
                }
                // config auto logon
                else if (command.GetRunAsAutoLogon())
                {
                    Trace.Info("Agent is going to run as process setting up the 'AutoLogon' capability for the agent.");
                    var autoLogonConfigManager = HostContext.GetService <IAutoLogonManager>();
                    await autoLogonConfigManager.ConfigureAsync(command);

                    //Important: The machine may restart if the autologon user is not same as the current user
                    //if you are adding code after this, keep that in mind
                }
            }
            else if (PlatformUtil.RunningOnLinux)
            {
                // generate service config script for Linux
                var serviceControlManager = HostContext.GetService <ILinuxServiceControlManager>();
                serviceControlManager.GenerateScripts(agentSettings);
            }
            else if (PlatformUtil.RunningOnMacOS)
            {
                // generate service config script for macOS
                var serviceControlManager = HostContext.GetService <IMacOSServiceControlManager>();
                serviceControlManager.GenerateScripts(agentSettings);
            }
        }
Example #39
0
 public void GetCollectionName(AgentSettings agentSettings, CommandSettings command, bool isHosted)
 {
     // Collection name is not required for Build/Release agent
 }
 public abstract void EnsureCredential(IHostContext context, CommandSettings command, string serverUrl);
Example #41
0
 public Task <TaskAgent> UpdateAgentAsync(AgentSettings agentSettings, TaskAgent agent, CommandSettings command)
 {
     ArgUtil.NotNull(agentSettings, nameof(agentSettings));
     return(_agentServer.UpdateAgentAsync(agentSettings.PoolId, agent));
 }
        public override bool ConfigureService(AgentSettings settings, CommandSettings command)
        {
            Trace.Entering();
            // TODO: add entering with info level. By default the error leve would be info. Config changes can get lost with this as entering is at Verbose level. For config all the logs should be logged.
            // TODO: Fix bug that exists in the legacy Windows agent where configuration using mirrored credentials causes an error, but the agent is still functional (after restarting). Mirrored credentials is a supported scenario and shouldn't manifest any errors.

            string logonPassword = string.Empty;

            NTAccount defaultServiceAccount = _windowsServiceHelper.GetDefaultServiceAccount();
            _logonAccount = command.GetWindowsLogonAccount(defaultValue: defaultServiceAccount.ToString());
            NativeWindowsServiceHelper.GetAccountSegments(_logonAccount, out _domainName, out _userName);
            if ((string.IsNullOrEmpty(_domainName) || _domainName.Equals(".", StringComparison.CurrentCultureIgnoreCase)) && !_logonAccount.Contains('@'))
            {
                _logonAccount = String.Format("{0}\\{1}", Environment.MachineName, _userName);
            }

            Trace.Info("LogonAccount after transforming: {0}, user: {1}, domain: {2}", _logonAccount, _userName, _domainName);
            if (!defaultServiceAccount.Equals(new NTAccount(_logonAccount)) &&
                !NativeWindowsServiceHelper.IsWellKnownIdentity(_logonAccount))
            {
                while (true)
                {
                    logonPassword = command.GetWindowsLogonPassword(_logonAccount);

                    // TODO: Fix this for unattended (should throw if not valid).
                    // TODO: If account is locked there is no point in retrying, translate error to useful message
                    if (_windowsServiceHelper.IsValidCredential(_domainName, _userName, logonPassword) || command.Unattended)
                    {
                        break;
                    }

                    Trace.Info("Invalid credential entered");
                    _term.WriteLine(StringUtil.Loc("InvalidWindowsCredential"));
                }
            }

            CalculateServiceName(settings, ServiceNamePattern, ServiceDisplayNamePattern);

            if (CheckServiceExists(ServiceName))
            {
                _term.WriteLine(StringUtil.Loc("ServiceAleadyExists"));

                StopService();
                UninstallService(ServiceName);
            }

            Trace.Info("Verifying if the account has LogonAsService permission");
            if (!_windowsServiceHelper.CheckUserHasLogonAsServicePrivilege(_domainName, _userName))
            {
                Trace.Info(StringUtil.Format("Account: {0} already has Logon As Service Privilege.", _logonAccount));
            }
            else
            {
                if (!_windowsServiceHelper.GrantUserLogonAsServicePrivilage(_domainName, _userName))
                {
                    throw new InvalidOperationException(StringUtil.Loc("CanNotGrantPermission", _logonAccount));
                }
            }

            _windowsServiceHelper.InstallService(ServiceName, ServiceDisplayName, _logonAccount, logonPassword);

            SaveServiceSettings();

            // TODO: If its service identity add it to appropriate PoolGroup
            // TODO: Add registry key after installation
            return true;
        }
Example #43
0
 public abstract void EnsureCredential(IHostContext context, CommandSettings command, string serverUrl);