Esempio n. 1
0
        public void ProcessCommand(IExecutionContext context, Command command)
        {
            // queue async command task to run agent plugin.
            context.Debug($"Process {command.Area}.{command.Event} command through agent plugin in backend.");
            if (!_supportedLoggingCommands.ContainsKey(command.Area) ||
                !_supportedLoggingCommands[command.Area].ContainsKey(command.Event))
            {
                throw new NotSupportedException(command.ToString());
            }

            var plugin = _supportedLoggingCommands[command.Area][command.Event];

            ArgUtil.NotNull(plugin, nameof(plugin));
            ArgUtil.NotNullOrEmpty(plugin.DisplayName, nameof(plugin.DisplayName));

            // construct plugin context
            AgentCommandPluginExecutionContext pluginContext = new AgentCommandPluginExecutionContext
            {
                Data       = command.Data,
                Properties = command.Properties,
                Endpoints  = context.Endpoints,
            };

            var target = context.StepTarget();

            Variables.TranslationMethod translateToHostPath = Variables.DefaultStringTranslator;

            ContainerInfo containerInfo = target as ContainerInfo;

            // Since plugins run on the host, but the inputs and variables have already been translated
            // to the container path, we need to convert them back to the host path
            // TODO: look to see if there is a better way to not have translate these back
            if (containerInfo != null)
            {
                translateToHostPath = (string val) => { return(containerInfo.TranslateToHostPath(val)); };
            }
            // variables
            context.Variables.CopyInto(pluginContext.Variables, translateToHostPath);

            var commandContext = HostContext.CreateService <IAsyncCommandContext>();

            commandContext.InitializeCommandContext(context, plugin.DisplayName);
            commandContext.Task = ProcessPluginCommandAsync(commandContext, pluginContext, plugin.CommandPluginTypeName, command, context.CancellationToken);
            context.AsyncCommands.Add(commandContext);
        }
        public AgentTaskPluginExecutionContext GeneratePluginExecutionContext(IExecutionContext context, Dictionary <string, string> inputs, Variables runtimeVariables)
        {
            ArgUtil.NotNull(context, nameof(context));
            ArgUtil.NotNull(inputs, nameof(inputs));
            ArgUtil.NotNull(runtimeVariables, nameof(runtimeVariables));

            // construct plugin context
            var target = context.StepTarget();

            Variables.TranslationMethod translateToHostPath = Variables.DefaultStringTranslator;

            ContainerInfo containerInfo = target as ContainerInfo;

            // Since plugins run on the host, but the inputs and variables have already been translated
            // to the container path, we need to convert them back to the host path
            // TODO: look to see if there is a better way to not have translate these back
            if (containerInfo != null)
            {
                var newInputs = new Dictionary <string, string>();
                foreach (var entry in inputs)
                {
                    newInputs[entry.Key] = containerInfo.TranslateToHostPath(entry.Value);
                }
                inputs = newInputs;
                translateToHostPath = (string val) => { return(containerInfo.TranslateToHostPath(val)); };
            }

            AgentTaskPluginExecutionContext pluginContext = new AgentTaskPluginExecutionContext
            {
                Inputs       = inputs,
                Repositories = context.Repositories,
                Endpoints    = context.Endpoints,
                Container    = containerInfo, //TODO: Figure out if this needs to have all the containers or just the one for the current step
                JobSettings  = context.JobSettings,
            };

            // variables
            runtimeVariables.CopyInto(pluginContext.Variables, translateToHostPath);
            context.TaskVariables.CopyInto(pluginContext.TaskVariables, translateToHostPath);

            return(pluginContext);
        }
Esempio n. 3
0
        public async Task RunPluginTaskAsync(IExecutionContext context, string plugin, Dictionary <string, string> inputs, Dictionary <string, string> environment, Variables runtimeVariables, EventHandler <ProcessDataReceivedEventArgs> outputHandler)
        {
            ArgUtil.NotNullOrEmpty(plugin, nameof(plugin));

            // Only allow plugins we defined
            if (!_taskPlugins.Contains(plugin))
            {
                throw new NotSupportedException(plugin);
            }

            // Resolve the working directory.
            string workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);

            ArgUtil.Directory(workingDirectory, nameof(workingDirectory));

            // Agent.PluginHost
            string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), $"Agent.PluginHost{Util.IOUtil.ExeExtension}");

            ArgUtil.File(file, $"Agent.PluginHost{Util.IOUtil.ExeExtension}");

            // Agent.PluginHost's arguments
            string arguments = $"task \"{plugin}\"";

            // construct plugin context
            var target = context.StepTarget();

            Variables.TranslationMethod translateToHostPath = Variables.DefaultStringTranslator;

            ContainerInfo containerInfo = target as ContainerInfo;

            // Since plugins run on the host, but the inputs and variables have already been translated
            // to the container path, we need to convert them back to the host path
            // TODO: look to see if there is a better way to not have translate these back
            if (containerInfo != null)
            {
                foreach (var key in inputs.Keys)
                {
                    inputs[key] = containerInfo.TranslateToHostPath(inputs[key]);
                }

                translateToHostPath = (string val) => { return(containerInfo.TranslateToHostPath(val)); };
            }

            AgentTaskPluginExecutionContext pluginContext = new AgentTaskPluginExecutionContext
            {
                Inputs       = inputs,
                Repositories = context.Repositories,
                Endpoints    = context.Endpoints,
                Container    = containerInfo, //TODO: Figure out if this needs to have all the containers or just the one for the current step
                JobSettings  = context.JobSettings,
            };

            // variables
            runtimeVariables.CopyInto(pluginContext.Variables, translateToHostPath);
            context.TaskVariables.CopyInto(pluginContext.TaskVariables, translateToHostPath);

            using (var processInvoker = HostContext.CreateService <IProcessInvoker>())
            {
                var redirectStandardIn = new InputQueue <string>();
                redirectStandardIn.Enqueue(JsonUtility.ToString(pluginContext));

                processInvoker.OutputDataReceived += outputHandler;
                processInvoker.ErrorDataReceived  += outputHandler;

                // Execute the process. Exit code 0 should always be returned.
                // A non-zero exit code indicates infrastructural failure.
                // Task failure should be communicated over STDOUT using ## commands.
                await processInvoker.ExecuteAsync(workingDirectory : workingDirectory,
                                                  fileName : file,
                                                  arguments : arguments,
                                                  environment : environment,
                                                  requireExitCodeZero : true,
                                                  outputEncoding : Encoding.UTF8,
                                                  killProcessOnCancel : false,
                                                  redirectStandardIn : redirectStandardIn,
                                                  cancellationToken : context.CancellationToken);
            }
        }
Esempio n. 4
0
        public Task StartAsync(IExecutionContext context, List <IStep> steps, CancellationToken token)
        {
            Trace.Entering();
            ArgUtil.NotNull(context, nameof(context));

            List <PluginInfo> enabledPlugins = new List <PluginInfo>();

            if (context.Variables.GetBoolean("agent.disablelogplugin") ?? false)
            {
                // all log plugs are disabled
                context.Debug("All log plugins are disabled.");
            }
            else
            {
                foreach (var plugin in _logPlugins)
                {
                    if (context.Variables.GetBoolean($"agent.disablelogplugin.{plugin.Key}") ?? false)
                    {
                        // skip plugin
                        context.Debug($"Log plugin '{plugin.Key}' is disabled.");
                        continue;
                    }
                    else
                    {
                        enabledPlugins.Add(plugin.Value);
                    }
                }
            }

            if (enabledPlugins.Count > 0)
            {
                // Resolve the working directory.
                string workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);
                ArgUtil.Directory(workingDirectory, nameof(workingDirectory));

                // Agent.PluginHost
                string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), $"Agent.PluginHost{Util.IOUtil.ExeExtension}");
                ArgUtil.File(file, $"Agent.PluginHost{Util.IOUtil.ExeExtension}");

                // Agent.PluginHost's arguments
                string arguments = $"log \"{_instanceId.ToString("D")}\"";

                var processInvoker = HostContext.CreateService <IProcessInvoker>();

                processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
                {
                    if (e.Data != null)
                    {
                        _outputs.Enqueue(e.Data);
                    }
                };
                processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
                {
                    if (e.Data != null)
                    {
                        _outputs.Enqueue(e.Data);
                    }
                };
                _pluginHostProcess?.Dispose();
                _pluginHostProcess = processInvoker.ExecuteAsync(workingDirectory: workingDirectory,
                                                                 fileName: file,
                                                                 arguments: arguments,
                                                                 environment: null,
                                                                 requireExitCodeZero: true,
                                                                 outputEncoding: Encoding.UTF8,
                                                                 killProcessOnCancel: true,
                                                                 redirectStandardIn: _redirectedStdin,
                                                                 inheritConsoleHandler: false,
                                                                 keepStandardInOpen: true,
                                                                 cancellationToken: token);

                // construct plugin context
                AgentLogPluginHostContext pluginContext = new AgentLogPluginHostContext
                {
                    PluginAssemblies = new List <string>(),
                    Repositories     = context.Repositories,
                    Endpoints        = context.Endpoints,
                    Variables        = new Dictionary <string, VariableValue>(),
                    Steps            = new Dictionary <string, Pipelines.TaskStepDefinitionReference>()
                };

                // plugins
                pluginContext.PluginAssemblies.AddRange(_logPlugins.Values.Select(x => x.AssemblyName));

                var target = context.StepTarget();
                Variables.TranslationMethod translateToHostPath = Variables.DefaultStringTranslator;

                ContainerInfo containerInfo = target as ContainerInfo;
                // Since plugins run on the host, but the inputs and variables have already been translated
                // to the container path, we need to convert them back to the host path
                // TODO: look to see if there is a better way to not have translate these back
                if (containerInfo != null)
                {
                    translateToHostPath = (string val) => { return(containerInfo.TranslateToHostPath(val)); };
                }
                // variables
                context.Variables.CopyInto(pluginContext.Variables, translateToHostPath);

                // steps
                foreach (var step in steps)
                {
                    var taskStep = step as ITaskRunner;
                    if (taskStep != null)
                    {
                        pluginContext.Steps[taskStep.ExecutionContext.Id.ToString("D")] = taskStep.Task.Reference;
                    }
                }

                Trace.Info("Send serialized context through STDIN");
                _redirectedStdin.Enqueue(JsonUtility.ToString(pluginContext));

                foreach (var plugin in _logPlugins)
                {
                    context.Output($"Plugin: '{plugin.Value.FriendlyName}' is running in background.");
                }
            }

            return(Task.CompletedTask);
        }