Example #1
0
        internal StreamingMessage ProcessWorkerInitRequest(StreamingMessage request)
        {
            var workerInitRequest = request.WorkerInitRequest;

            Environment.SetEnvironmentVariable("AZUREPS_HOST_ENVIRONMENT", $"AzureFunctions/{workerInitRequest.HostVersion}");

            StreamingMessage response = NewStreamingMessageTemplate(
                request.RequestId,
                StreamingMessage.ContentOneofCase.WorkerInitResponse,
                out StatusResult status);

            response.WorkerInitResponse.Capabilities.Add("RpcHttpBodyOnly", "true");

            // If the environment variable is set, spin up the custom named pipe server.
            // This is typically used for debugging. It will throw a friendly exception if the
            // pipe name is not a valid pipename.
            string pipeName = Environment.GetEnvironmentVariable("PSWorkerCustomPipeName");

            if (!string.IsNullOrEmpty(pipeName))
            {
                RpcLogger.WriteSystemLog(LogLevel.Trace, string.Format(PowerShellWorkerStrings.SpecifiedCustomPipeName, pipeName));
                RemoteSessionNamedPipeServer.CreateCustomNamedPipeServer(pipeName);
            }

            return(response);
        }
Example #2
0
        /// <summary>
        /// Checkout an idle PowerShellManager instance in a non-blocking asynchronous way.
        /// </summary>
        internal PowerShellManager CheckoutIdleWorker(StreamingMessage request, AzFunctionInfo functionInfo)
        {
            PowerShellManager psManager    = null;
            string            requestId    = request.RequestId;
            string            invocationId = request.InvocationRequest?.InvocationId;

            // If the pool has an idle one, just use it.
            if (!_pool.TryTake(out psManager))
            {
                // The pool doesn't have an idle one.
                if (_poolSize < _upperBound &&
                    Interlocked.Increment(ref _poolSize) <= _upperBound)
                {
                    // If the pool hasn't reached its bounded capacity yet, then
                    // we create a new item and return it.
                    var logger = new RpcLogger(_msgStream);
                    logger.SetContext(requestId, invocationId);
                    psManager = new PowerShellManager(logger);

                    RpcLogger.WriteSystemLog(string.Format(PowerShellWorkerStrings.LogNewPowerShellManagerCreated, _poolSize.ToString()));
                }
                else
                {
                    // If the pool has reached its bounded capacity, then the thread
                    // should be blocked until an idle one becomes available.
                    psManager = _pool.Take();
                }
            }

            // Register the function with the Runspace before returning the idle PowerShellManager.
            FunctionMetadata.RegisterFunctionMetadata(psManager.InstanceId, functionInfo);
            psManager.Logger.SetContext(requestId, invocationId);
            return(psManager);
        }
        /// <summary>
        /// This method invokes the FunctionApp's profile.ps1.
        /// </summary>
        internal void InvokeProfile(string profilePath)
        {
            Exception exception = null;

            if (profilePath == null)
            {
                RpcLogger.WriteSystemLog(string.Format(PowerShellWorkerStrings.FileNotFound, "profile.ps1", FunctionLoader.FunctionAppRootPath));
                return;
            }

            try
            {
                // Import-Module on a .ps1 file will evaluate the script in the global scope.
                _pwsh.AddCommand(Utils.ImportModuleCmdletInfo)
                .AddParameter("Name", profilePath)
                .AddParameter("PassThru", true)
                .AddCommand(Utils.RemoveModuleCmdletInfo)
                .AddParameter("Force", true)
                .AddParameter("ErrorAction", "SilentlyContinue")
                .InvokeAndClearCommands();
            }
            catch (Exception e)
            {
                exception = e;
                throw;
            }
            finally
            {
                if (_pwsh.HadErrors)
                {
                    string errorMsg = string.Format(PowerShellWorkerStrings.FailToRunProfile, profilePath);
                    _logger.Log(LogLevel.Error, errorMsg, exception, isUserLog: true);
                }
            }
        }
Example #4
0
        /// <summary>
        /// Entry point of the language worker.
        /// </summary>
        public async static Task Main(string[] args)
        {
            RpcLogger.WriteSystemLog(
                LogLevel.Information,
                string.Format(PowerShellWorkerStrings.PowerShellWorkerVersion, typeof(Worker).Assembly.GetName().Version));

            WorkerArguments arguments = null;

            Parser.Default.ParseArguments <WorkerArguments>(args)
            .WithParsed(ops => arguments = ops)
            .WithNotParsed(err => Environment.Exit(1));

            var msgStream        = new MessagingStream(arguments.Host, arguments.Port);
            var requestProcessor = new RequestProcessor(msgStream);

            // Send StartStream message
            var startedMessage = new StreamingMessage()
            {
                RequestId   = arguments.RequestId,
                StartStream = new StartStream()
                {
                    WorkerId = arguments.WorkerId
                }
            };

            msgStream.Write(startedMessage);
            await requestProcessor.ProcessRequestLoop();
        }
Example #5
0
        /// <summary>
        /// Constructor of the pool.
        /// </summary>
        internal PowerShellManagerPool(MessagingStream msgStream)
        {
            string upperBound = Environment.GetEnvironmentVariable("PSWorkerInProcConcurrencyUpperBound");

            if (string.IsNullOrEmpty(upperBound) || !int.TryParse(upperBound, out _upperBound))
            {
                _upperBound = 1;
            }

            _msgStream = msgStream;
            _pool      = new BlockingCollection <PowerShellManager>(_upperBound);
            RpcLogger.WriteSystemLog(LogLevel.Information, string.Format(PowerShellWorkerStrings.LogConcurrencyUpperBound, _upperBound.ToString()));
        }
        /// <summary>
        /// Checkout an idle PowerShellManager instance in a non-blocking asynchronous way.
        /// </summary>
        internal PowerShellManager CheckoutIdleWorker(
            string requestId,
            string invocationId,
            string functionName,
            ReadOnlyDictionary <string, ReadOnlyBindingInfo> outputBindings)
        {
            PowerShellManager psManager = null;

            // If the pool has an idle one, just use it.
            if (!_pool.TryTake(out psManager))
            {
                // The pool doesn't have an idle one.
                if (_poolSize < UpperBound)
                {
                    int id = Interlocked.Increment(ref _poolSize);
                    if (id <= UpperBound)
                    {
                        // If the pool hasn't reached its bounded capacity yet, then
                        // we create a new item and return it.
                        var logger = CreateLoggerWithContext(requestId, invocationId);
                        psManager = new PowerShellManager(logger, id);

                        RpcLogger.WriteSystemLog(LogLevel.Trace, string.Format(PowerShellWorkerStrings.LogNewPowerShellManagerCreated, id.ToString()));
                    }
                }

                if (psManager == null)
                {
                    var logger = CreateLoggerWithContext(requestId, invocationId);
                    logger.Log(isUserOnlyLog: true, LogLevel.Warning, string.Format(PowerShellWorkerStrings.FunctionQueuingRequest, functionName));

                    // If the pool has reached its bounded capacity, then the thread
                    // should be blocked until an idle one becomes available.
                    psManager = _pool.Take();
                }
            }

            psManager.Logger.SetContext(requestId, invocationId);

            // Finish the initialization if not yet.
            // This applies only to the very first PowerShellManager instance, whose initialization was deferred.
            psManager.Initialize();

            // Register the function with the Runspace before returning the idle PowerShellManager.
            FunctionMetadata.RegisterFunctionMetadata(psManager.InstanceId, outputBindings);

            return(psManager);
        }
Example #7
0
        internal StreamingMessage ProcessWorkerInitRequest(StreamingMessage request)
        {
            StreamingMessage response = NewStreamingMessageTemplate(
                request.RequestId,
                StreamingMessage.ContentOneofCase.WorkerInitResponse,
                out StatusResult status);

            // If the environment variable is set, spin up the custom named pipe server.
            // This is typically used for debugging. It will throw a friendly exception if the
            // pipe name is not a valid pipename.
            string pipeName = Environment.GetEnvironmentVariable("PSWorkerCustomPipeName");

            if (!string.IsNullOrEmpty(pipeName))
            {
                RpcLogger.WriteSystemLog(LogLevel.Trace, string.Format(PowerShellWorkerStrings.SpecifiedCustomPipeName, pipeName));
                RemoteSessionNamedPipeServer.CreateCustomNamedPipeServer(pipeName);
            }

            return(response);
        }
Example #8
0
        internal async Task ProcessRequestLoop()
        {
            StreamingMessage request, response;

            while (await _msgStream.MoveNext())
            {
                request = _msgStream.GetCurrentMessage();

                if (_requestHandlers.TryGetValue(request.ContentCase, out Func <StreamingMessage, StreamingMessage> requestFunc))
                {
                    response = requestFunc(request);
                }
                else
                {
                    RpcLogger.WriteSystemLog(LogLevel.Warning, string.Format(PowerShellWorkerStrings.UnsupportedMessage, request.ContentCase));
                    continue;
                }

                if (response != null)
                {
                    _msgStream.Write(response);
                }
            }
        }
        /// <summary>
        /// Entry point of the language worker.
        /// </summary>
        public async static Task Main(string[] args)
        {
            RpcLogger.WriteSystemLog(
                LogLevel.Information,
                string.Format(PowerShellWorkerStrings.PowerShellWorkerVersion, typeof(Worker).Assembly.GetName().Version));

            WorkerArguments arguments = null;

            Parser.Default.ParseArguments <WorkerArguments>(args)
            .WithParsed(ops => arguments = ops)
            .WithNotParsed(err => Environment.Exit(1));

            // Create the very first Runspace so the debugger has the target to attach to.
            // This PowerShell instance is shared by the first PowerShellManager instance created in the pool,
            // and the dependency manager (used to download dependent modules if needed).
            var firstPowerShellInstance = Utils.NewPwshInstance();

            LogPowerShellVersion(firstPowerShellInstance);
            WarmUpPowerShell(firstPowerShellInstance);

            var msgStream        = new MessagingStream(arguments.Host, arguments.Port);
            var requestProcessor = new RequestProcessor(msgStream, firstPowerShellInstance);

            // Send StartStream message
            var startedMessage = new StreamingMessage()
            {
                RequestId   = arguments.RequestId,
                StartStream = new StartStream()
                {
                    WorkerId = arguments.WorkerId
                }
            };

            msgStream.Write(startedMessage);
            await requestProcessor.ProcessRequestLoop();
        }
Example #10
0
 /// <summary>
 /// Constructor of the pool.
 /// </summary>
 internal PowerShellManagerPool(MessagingStream msgStream)
 {
     _msgStream = msgStream;
     _pool      = new BlockingCollection <PowerShellManager>(UpperBound);
     RpcLogger.WriteSystemLog(LogLevel.Information, string.Format(PowerShellWorkerStrings.LogConcurrencyUpperBound, UpperBound.ToString()));
 }
 /// <summary>
 /// Constructor of the pool.
 /// </summary>
 internal PowerShellManagerPool(Func <ILogger> createLogger)
 {
     _createLogger = createLogger;
     _pool         = new BlockingCollection <PowerShellManager>(UpperBound);
     RpcLogger.WriteSystemLog(LogLevel.Information, string.Format(PowerShellWorkerStrings.LogConcurrencyUpperBound, UpperBound.ToString()));
 }
        private static void LogPowerShellVersion(System.Management.Automation.PowerShell pwsh)
        {
            var message = string.Format(PowerShellWorkerStrings.PowerShellVersion, Utils.GetPowerShellVersion(pwsh));

            RpcLogger.WriteSystemLog(LogLevel.Information, message);
        }