Giter Club home page Giter Club logo

azure-functions-powershell-worker's Introduction

azure-functions-logo

Branch Status
dev Build Status
v4.x/ps7.4 Build Status
v4.x/ps7.2 Build Status
v4.x/ps7.0 Build Status

Azure Functions PowerShell Language Worker

This repository will host the PowerShell language worker implementation for Azure Functions. We'll also be using it to track work items related to PowerShell support. Please feel free to leave comments about any of the features and design patterns.

Overview

PowerShell support for Functions is based on PowerShell Core 7, Functions on Linux, and the Azure Functions runtime V4.

What's available?

Triggers / Bindings

  • HTTP Trigger (Webhook)
  • Timer Trigger
  • Blob Trigger
  • Queue Trigger

What's coming?

  • More triggers and bindings
  • Tooling integration
  • A bunch of other good things

Contributing

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Building from source

Prereqs

Build

  1. Clone this repository
  2. cd azure-functions-powershell-worker
  3. ./build.ps1

NOTE: If you're missing a dependency, you will be asked to run ./build.ps1 -Bootstrap

Run & Debug

The PowerShell worker alone is not enough to establish the functions app, we also need the support from Azure Functions Host. You may either use a published host CLI or use the in-development host. But both of the methods require you to attach to the .NET process if you want a step-by-step debugging experience.

Published Host

First, follow the instructions to install the Azure Functions Core Tools. Then locate the azure-functions-core-tools\bin\workers\ folder. Here are a few hints on where it could be located:

On Windows if you installed via npm

~\AppData\Roaming\npm\node_modules\azure-functions-core-tools\bin\workers\

On macOS if you installed via brew

/usr/local/Cellar/azure-functions-core-tools/<version>/workers/

Under the workers/powershell folder, create a folder with the name 7.4 if it does not exist yet. Copy the result of the publish directory into the workers/powershell/7.4 folder, and copy the publish/worker.config.json file into the workers/powershell folder:

Copy-Item -Recurse -Force ./src/bin/Debug/net8.0/publish/ "/usr/local/Cellar/azure-functions-core-tools/$(func --version)/workers/powershell/7.4"
Copy-Item -Recurse -Force ./src/bin/Debug/net8.0/publish/worker.config.json "/usr/local/Cellar/azure-functions-core-tools/$(func --version)/workers/powershell"

NOTE: if the powershell folder already exists, you should delete it or debugging won't work.

Then cd into a Function App with PowerShell as the worker runtime (NOTE: There's an example PowerShell Function App in the examples folder).

Set the environment variable FUNCTIONS_WORKER_RUNTIME_VERSION to 7.4, or add this as an app setting to the local.settings.json file.

Lastly, run:

func start

NOTE: If you would like to see more out of the logs, see the logging section in the Azure Functions Host repo.

Latest Host

A developer may also use the latest host code by cloning the git repository Azure Functions Host. Now you need to navigate to the root folder of the host project and build it through:

dotnet restore WebJobs.Script.sln
dotnet build WebJobs.Script.sln

After the build succeeded, set the environment variable "AzureWebJobsScriptRoot" to the root folder path (the folder which contains the host.json) of your test functions app.

Under the workers/powershell folder, create a folder with the name 7.4 if it does not exist yet. Then copy the publish directory to workers/powershell/7.4, and the publish/worker.config.json to workers/powershell:

Copy-Item -Recurse -Force ./src/bin/Debug/net8.0/publish/ "<Azure Functions Host Root>/src/WebJobs.Script.WebHost/bin/Debug/net8.0/workers/powershell/7.4"
Copy-Item -Force ./src/bin/Debug/net8.0/publish/worker.config.json "<Azure Functions Host Root>/src/WebJobs.Script.WebHost/bin/Debug/net8.0/workers/powershell"

Then you can start the host by running:

dotnet ./src/WebJobs.Script.WebHost/bin/Debug/net8.0/Microsoft.Azure.WebJobs.Script.WebHost.dll

Note: Remember to remove "AzureWebJobsScriptRoot" environment variable after you have finished debugging, because it will also influence the func CLI tool.

Packaging

To package the PowerShell Language Worker as a nupkg, do the following:

  • cd azure-functions-powershell-worker
  • dotnet publish
  • cd package
  • dotnet pack

That will place a Microsoft.Azure.Functions.PowerShellWorker.*.nupkg in:

azure-functions-powershell-worker/package/bin/Debug

It pulls the contents of the publish folder in:

azure-functions-powershell-worker/src/bin/Debug/net8.0/publish

if you specify a different Configuration or TargetFramework that will be honored.

azure-functions-powershell-worker's People

Contributors

alrod avatar anatolib avatar andystaples avatar anirudhgarg avatar bachuv avatar davidmrdavid avatar daxian-dbw avatar dependabot[bot] avatar francisco-gamino avatar liliankasem avatar michaelpeng36 avatar microsoft-github-policy-service[bot] avatar microsoftopensource avatar msftgits avatar pragnagopa avatar satishranjan avatar tylerleonhardt avatar yojagad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

azure-functions-powershell-worker's Issues

Container story

Can we use the CloudShell image and work off of that or do we need to use some Azure Functions base image?

I'm thinking about authentication with Azure. How can a user's script manage azure resources without doing heavy authentication lifting in their function?

cc @asavaritayal @pragnagopa

Bundle .NET runtime with PowerShell worker

I just realized that if a user does not have the .NET Core runtime on their computer and on their PATH, they will be unable to run the PowerShell worker and the error message that the Functions host throws is not very informative.

I think for the the prototype milestone this is not a blocker but certainly is for the next milestone.

Add FunctionApp "modules path" to PSModulePath

We need to do the work that will add the FunctionApp's "modules path" to the PSModulePath so that we enable a way for users to leverage modules in their functions.

The path that gets added to the PSModulePath will be a we'll-known Modules folder. That exists in the FunctionApp directory.

If my FunctionApp exists at C:\Temp\MyFuncApp then the following path will be added to the beginning of the PSModulePath:

C:\Temp\MyFuncApp\Modules

In the beginning, we will have have the user do the Save-Module to that path. This makes the pack easier (#68). In the future, we should leverage the PSModulePath on their system and have pack pull these modules from there, to the Modules while deploying.

Powershell worker finds no Powershell Functions

Hi team,

I'm trying to run the sample code in the Examples folder but when I run it from the root level (Function App level) it fails to find any of the Azure Functions in the folder. I get the following output:

azure-functions-powershell-worker/examples/PSCoreApp  master ✗ 
▶ func start

                  %%%%%%
                 %%%%%%
            @   %%%%%%    @
          @@   %%%%%%      @@
       @@@    %%%%%%%%%%%    @@@
     @@      %%%%%%%%%%        @@
       @@         %%%%       @@
         @@      %%%       @@
           @@    %%      @@
                %%
                %

Hosting environment: Production
Content root path: /Users/christosmatskas/Projects/azure-functions-powershell-worker/examples/PSCoreApp
Now listening on: http://localhost:7071
Application started. Press Ctrl+C to shut down.
[30/09/2018 12:11:30] Reading host configuration file '/Users/christosmatskas/Projects/azure-functions-powershell-worker/examples/PSCoreApp/host.json'
[30/09/2018 12:11:30] Host configuration file read:
[30/09/2018 12:11:30] {}
[30/09/2018 12:11:30] Starting Host (HostId=cm-772749736, InstanceId=80789cad-347b-483a-bf89-9fd5fec3f507, Version=2.0.11776.0, ProcessId=77364, AppDomainId=1, Debug=False, ConsecutiveErrors=0, StartupCount=1, FunctionsExtensionVersion=)
[30/09/2018 12:11:31] FUNCTIONS_WORKER_RUNTIME is specified, only powershell will be enabled
[30/09/2018 12:11:31] Reading Worker config for the language: powershell
[30/09/2018 12:11:31] Generating 0 job function(s)
[30/09/2018 12:11:31] No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
[30/09/2018 12:11:31] Host initialized (611ms)
Listening on http://localhost:7071/
Hit CTRL-C to exit...
[30/09/2018 12:11:56] Host started (25432ms)
[30/09/2018 12:11:56] Job host started
^C
Application is shutting down...                                                                                             
[30/09/2018 12:12:11] Stopping Host

Any ideas what I could be missing?

Add E2E tests using CLI from storage account

CLI builds hat include the latest functions runtime are available on

https://functionsclibuilds.blob.core.windows.net/builds/2/latest/Azure.Functions.Cli.{platform}.zip

where platform in linux-x64, osx-x64, win-x64, win-x86

You can also get the version from

GET https://functionsclibuilds.blob.core.windows.net/builds/2/latest/version.txt

Update CI to use latest CLI.

Don't require casting of [HttpResponseContext]

Right now, we require you to cast a hashtable to [HttpResponseContext] in order to send a response for http.

Push-OutputBinding -Name res -Value ([HttpResponseContext]@{
    Status = 200
    Body = "Hello World"
})

this casting shouldn't be needed.

Testing on Consumption Plan or App Service?

Hello Team,

Very much looking forward to this worker and thanks for your hard work. Is there a process for adding this worker to the v2 runtime on the Azure consumption plan or a private app service, or is it only possible to run on a functions runtime develop host today?

Just curious if it was possible to test "in production" so to speak along with integrations to app insights, etc. so thanks!

PowerShell stream order needs to be maintained

foreach (var item in pipelineItems)
{
_logger.Log(LogLevel.Information, $"OUTPUT: {_pwsh.FormatObjectToString(item)}", isUserLog: true);
}

The logging of output streams after the execution at L134 completes means that output streams will always be logged after other streams types, even if output stream is generated before other stream types in the actual script.

Beside, the wacky table output resulted from logging the pipeline object.

Errors aren't logging

This function never gets fired when you do a Write-Error so either we've got a bug in the PowerShell SDK or I've set up the host incorrectly.

Verbose, Warning, and regular logs work fine.

Investigate/understand the WindowsCompatibility scenario

Today, there are limitations in the Windows consumption sandbox that prevent us from using the WindowsCompatibility module, namely that we don't have the ability to establish a WinRM connection to do implicit remoting over localhost.

I've heard a couple threads of investigation floated that we should pursue:

  • Move WindowsCompatbility to use named pipes
  • shelling out to powershell.exe appears to work, so we could streamline, wrap, or just doc that scenario as a helper

We should close on an approach/plan by the time we reach Preview.

Lambda and other thoughts

  • Allow the user to declare assembly dependencies. (what UX?)

    • e.g. A function depends on a custom assembly, which will be loaded by using Assembly ... or Add-Type ..., or Assembly.Load(...). Do we want to support that scenario? One solution would be the AssemblyLoadContext.Default.Resolving.
  • Capture Write-Host to logging Write-Host also write the message to Information stream, so we are good here.

  • PowerShell based Lambda doesn't bundle AWSPowerShell.NetCore (AWS version of AzureRM.NetCore) with the runtime, but instead, bundle it with user's scripts in the deployment package. The user needs to use #Requires -Modules in script to specify the module dependency.

    • I don't like having AzureRM.NetCore bundle with user's Function App, that will likely cause duplications of such module, which is a waste of bandwidth. However, that would solve the module version issue, since user needs to be explicit about what version of AzRM to be deployed.
    • But we do need a way to let user specify what custom module they want to deploy along with their scripts. (what UX? use #Requires -Modules like Lambda does?)
    • Just realized that the func CLI doesn't have a pack option. Is the deployment restricted to container image? dotnet-lambda package pack the function app into a zip file, ready for deployment.
      • Lambda provides a powershell module to facilitate creating a powershell lambda, including templates, create a package (zip), publish a package to AWS.
      • By having a powershell helper module, it's able to parse the script to get the module dependencies from #Requires -Modules ..., and pack the dependencies into the package. We cannot find the dependency moduels without running in the PowerShell session that the user uses for creating the function.
  • Lambda tool is a .NET Global Tool "Amazon.Lambda.Tools". Maybe func CLI should consider to be a Global Tool too, given it's a .NET Core application. (not related to the PS worker)

Close on script/module entry point

According to #1, we're definitely starting with run.ps1 as the default entry point.

Two open questions then:

  • have we already implemented entryPoint in function.json for scripts (e.g. foo.ps1)
  • per the question posed in #17, does it make sense to implement entryPoint for .psm1?

This is something we should decide we are or are not doing for the Preview milestone.

Disable .ps1 support in entryPoint

When working on the refactoring, I found that although Import-Module -Name script.ps1 does import the script file as a module, the module doesn't expose anything, and functions from the script are actually loaded in the global scope.

This unexpected behavior will leave those functions around to pollute the Runspace.
We could use New-Module -ScriptBlock to replace the current approach.
New-Module creates a dynamc module that will be persisted in the session until the session exits. So it doesn't help.

[Programming Model] Entry Point

Script File

PowerShell support for Functions will support a run file of .ps1 format. We'll use the workflow below to determine which file to run:

If the "scriptFile" attribute is set in function.json
Else if the project contains a single .ps1 file
Else if run.ps1 is present
Else throw an error

Entry Point

Instead of running a plain script, we'll define a method for the runtime to invoke during an execution. We'll use the workflow below to determine which function to run:

If the "entryPoint" attribute is set in function.json
Else if Run() is present
Else throw an error

Tests needed

Tests still needed:

Unit

  • Worker init request tests

  • Function load request tests

  • Invocation request tests

  • TypeConverter tests

  • Startup arguments tests using a library to parse these instead

  • FunctionLoader tests

  • Pester tests for module

  • PowerShell Manager tests

  • PowerShell extension tests

Integration

  • Requests
  • Logging

MSI support for Azure PowerShell

Make Connect-AzAccount -Identity work the same way that it works in Azure Cloud Shell.

For now, this is non-blocking on the prototype, but we should work to make it happen.

build.ps1 to build and test

build.ps1 -Bootstrap : tells you what you're missing on your system
build.ps1: does the dotnet publish
build.ps1 -Package : packages into nuget package
build.ps1 -Test : runs xUnit tests and Pester tests (for module)

Autoloading the AzureRm module doesn't work in worker - but works fine interactively

Have a function that just runs:

Login-AzureRmAccount

Note the error:

{
    "Exception": {
          "Source": "Microsoft.Azure.Commands.Common.Authentication.Abstractions",
          "StackTrace": "   at Microsoft.Azure.Commands.Common.Authentication.AzureSession.get_Instance()
                            at Microsoft.Azure.Commands.ResourceManager.Common.AzureRMCmdlet.BeginProcessing()\n   
                            at System.Management.Automation.Cmdlet.DoBeginProcessing()
                            at System.Management.Automation.CommandProcessorBase.DoBegin()",
          "Message": "The Azure PowerShell session has not been properly initialized.  Please import the module and try again."
    }
}

This same cmdlet works just fine in pwsh:

> Login-AzureRmAccount
WARNING: To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code AASFDASF to authenticate.

We can fix the above error by Import-Module AzureRm.Netcore but we should understand why this is needed.

Support .psm1s via an entry point?

Previously, Functions only supported 1 file type for a worker. They've fixed this to support multiple file types.

We should give the user the ability to use a module (.psm1) and then specify an entry point that could be a function that the module exposes.

Switch to module approach

This involves:

  • having everything run in the local scope
  • using AddCommand as much as possible
  • finishing up #14 which is the PR that adds the PowerShell module
  • expose the module in the user's function

Add docs: Portal quickstart

We should have a quickstart doc outlining how to do the following from the Azure portal:

  • create a function app
  • create a function
    • timer trigger
    • HTTP trigger
  • add a module dependency
  • pack/publish to Azure
  • show it working

Investigate why the Host sends Json bodies as Strings in the TypedData

The host is packaging the Body from the request as a String rather than Json in TypedData

image

This is the data I get from the host:

[8/24/18 2:52:08 AM] {
[8/24/18 2:52:08 AM]   "Origin": "Host",
[8/24/18 2:52:08 AM]   "MessageType": "InvocationRequest",
[8/24/18 2:52:08 AM]   "WorkerId": "cdd99528-4308-497d-8513-f201784de84a",
[8/24/18 2:52:08 AM]   "Message": {
[8/24/18 2:52:08 AM]     "RequestId": "",
[8/24/18 2:52:08 AM]     "InvocationRequest": {
[8/24/18 2:52:08 AM]       "InvocationId": "cc5d6a62-d445-49e7-ac7b-88e0f8b6cce3",
[8/24/18 2:52:08 AM]       "FunctionId": "e62e1d6b-568c-4927-aa9a-2483cbfa6096",
[8/24/18 2:52:08 AM]       "InputData": [
[8/24/18 2:52:08 AM]         {
[8/24/18 2:52:08 AM]           "Name": "req",
[8/24/18 2:52:08 AM]           "Data": {
[8/24/18 2:52:08 AM]             "String": "",
[8/24/18 2:52:08 AM]             "Json": "",
[8/24/18 2:52:08 AM]             "Bytes": [],
[8/24/18 2:52:08 AM]             "Stream": [],
[8/24/18 2:52:08 AM]             "Http": {
[8/24/18 2:52:08 AM]               "Method": "POST",
[8/24/18 2:52:08 AM]               "Url": "http://localhost:7071/api/MyHttpTrigger",
[8/24/18 2:52:08 AM]               "Headers": {
[8/24/18 2:52:08 AM]                 "content-type": "application/x-www-form-urlencoded",
[8/24/18 2:52:08 AM]                 "host": "localhost:7071",
[8/24/18 2:52:08 AM]                 "user-agent": "Mozilla/5.0 (Macintosh; Darwin 18.0.0 Darwin Kernel Version 18.0.0: Sun Aug 12 14:04:39 PDT 2018; root:xnu-4903.201.1~14/RELEASE_X86_64; en-US) PowerShell/6.1.0",
[8/24/18 2:52:08 AM]                 "content-length": "17"
[8/24/18 2:52:08 AM]               },
[8/24/18 2:52:08 AM]               "Body": {
[8/24/18 2:52:08 AM]                 "String": "{\"Name\": \"Tyler\"}",
[8/24/18 2:52:08 AM]                 "Json": "",
[8/24/18 2:52:08 AM]                 "Bytes": [],
[8/24/18 2:52:08 AM]                 "Stream": [],
[8/24/18 2:52:08 AM]                 "Int": 0,
[8/24/18 2:52:08 AM]                 "Double": 0.0,
[8/24/18 2:52:08 AM]                 "DataCase": "String"
[8/24/18 2:52:08 AM]               },
[8/24/18 2:52:08 AM]               "Params": {},
[8/24/18 2:52:08 AM]               "StatusCode": "",
[8/24/18 2:52:08 AM]               "Query": {},
[8/24/18 2:52:08 AM]               "EnableContentNegotiation": false,
[8/24/18 2:52:08 AM]               "RawBody": {
[8/24/18 2:52:08 AM]                 "String": "{\"Name\": \"Tyler\"}",
[8/24/18 2:52:08 AM]                 "Json": "",
[8/24/18 2:52:08 AM]                 "Bytes": [],
[8/24/18 2:52:08 AM]                 "Stream": [],
[8/24/18 2:52:08 AM]                 "Int": 0,
[8/24/18 2:52:08 AM]                 "Double": 0.0,
[8/24/18 2:52:08 AM]                 "DataCase": "String"
[8/24/18 2:52:08 AM]               }
[8/24/18 2:52:08 AM]             },
[8/24/18 2:52:08 AM]             "Int": 0,
[8/24/18 2:52:08 AM]             "Double": 0.0,
[8/24/18 2:52:08 AM]             "DataCase": "Http"
[8/24/18 2:52:08 AM]           }
[8/24/18 2:52:08 AM]         }
[8/24/18 2:52:08 AM]       ],
[8/24/18 2:52:08 AM]       "TriggerMetadata": {
[8/24/18 2:52:08 AM]         "$request": {
[8/24/18 2:52:08 AM]           "String": "",
[8/24/18 2:52:08 AM]           "Json": "",
[8/24/18 2:52:08 AM]           "Bytes": [],
[8/24/18 2:52:08 AM]           "Stream": [],
[8/24/18 2:52:08 AM]           "Http": {
[8/24/18 2:52:08 AM]             "Method": "POST",
[8/24/18 2:52:08 AM]             "Url": "http://localhost:7071/api/MyHttpTrigger",
[8/24/18 2:52:08 AM]             "Headers": {
[8/24/18 2:52:08 AM]               "content-type": "application/x-www-form-urlencoded",
[8/24/18 2:52:08 AM]               "host": "localhost:7071",
[8/24/18 2:52:08 AM]               "user-agent": "Mozilla/5.0 (Macintosh; Darwin 18.0.0 Darwin Kernel Version 18.0.0: Sun Aug 12 14:04:39 PDT 2018; root:xnu-4903.201.1~14/RELEASE_X86_64; en-US) PowerShell/6.1.0",
[8/24/18 2:52:08 AM]               "content-length": "17"
[8/24/18 2:52:08 AM]             },
[8/24/18 2:52:08 AM]             "Body": {
[8/24/18 2:52:08 AM]               "String": "{\"Name\": \"Tyler\"}",
[8/24/18 2:52:08 AM]               "Json": "",
[8/24/18 2:52:08 AM]               "Bytes": [],
[8/24/18 2:52:08 AM]               "Stream": [],
[8/24/18 2:52:08 AM]               "Int": 0,
[8/24/18 2:52:08 AM]               "Double": 0.0,
[8/24/18 2:52:08 AM]               "DataCase": "String"
[8/24/18 2:52:08 AM]             },
[8/24/18 2:52:08 AM]             "Params": {},
[8/24/18 2:52:08 AM]             "StatusCode": "",
[8/24/18 2:52:08 AM]             "Query": {},
[8/24/18 2:52:08 AM]             "EnableContentNegotiation": false,
[8/24/18 2:52:08 AM]             "RawBody": {
[8/24/18 2:52:08 AM]               "String": "{\"Name\": \"Tyler\"}",
[8/24/18 2:52:08 AM]               "Json": "",
[8/24/18 2:52:08 AM]               "Bytes": [],
[8/24/18 2:52:08 AM]               "Stream": [],
[8/24/18 2:52:08 AM]               "Int": 0,
[8/24/18 2:52:08 AM]               "Double": 0.0,
[8/24/18 2:52:08 AM]               "DataCase": "String"
[8/24/18 2:52:08 AM]             }
[8/24/18 2:52:08 AM]           },
[8/24/18 2:52:08 AM]           "Int": 0,
[8/24/18 2:52:08 AM]           "Double": 0.0,
[8/24/18 2:52:08 AM]           "DataCase": "Http"
[8/24/18 2:52:08 AM]         },
[8/24/18 2:52:08 AM]         "Name": {
[8/24/18 2:52:08 AM]           "String": "Tyler",
[8/24/18 2:52:08 AM]           "Json": "",
[8/24/18 2:52:08 AM]           "Bytes": [],
[8/24/18 2:52:08 AM]           "Stream": [],
[8/24/18 2:52:08 AM]           "Int": 0,
[8/24/18 2:52:08 AM]           "Double": 0.0,
[8/24/18 2:52:08 AM]           "DataCase": "String"
[8/24/18 2:52:08 AM]         },
[8/24/18 2:52:08 AM]         "Query": {
[8/24/18 2:52:08 AM]           "String": "",
[8/24/18 2:52:08 AM]           "Json": "{}",
[8/24/18 2:52:08 AM]           "Bytes": [],
[8/24/18 2:52:08 AM]           "Stream": [],
[8/24/18 2:52:08 AM]           "Int": 0,
[8/24/18 2:52:08 AM]           "Double": 0.0,
[8/24/18 2:52:08 AM]           "DataCase": "Json"
[8/24/18 2:52:08 AM]         },
[8/24/18 2:52:08 AM]         "Headers": {
[8/24/18 2:52:08 AM]           "String": "",
[8/24/18 2:52:08 AM]           "Json": "{\"Content-Type\":\"application/x-www-form-urlencoded\",\"Host\":\"localhost:7071\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Darwin 18.0.0 Darwin Kernel Version 18.0.0: Sun Aug 12 14:04:39 PDT 2018; root:xnu-4903.201.1~14/RELEASE_X86_64; en-US) PowerShell/6.1.0\",\"Content-Length\":\"17\"}",
[8/24/18 2:52:08 AM]           "Bytes": [],
[8/24/18 2:52:08 AM]           "Stream": [],
[8/24/18 2:52:08 AM]           "Int": 0,
[8/24/18 2:52:08 AM]           "Double": 0.0,
[8/24/18 2:52:08 AM]           "DataCase": "Json"
[8/24/18 2:52:08 AM]         },
[8/24/18 2:52:08 AM]         "req": {
[8/24/18 2:52:08 AM]           "String": "",
[8/24/18 2:52:08 AM]           "Json": "",
[8/24/18 2:52:08 AM]           "Bytes": [],
[8/24/18 2:52:08 AM]           "Stream": [],
[8/24/18 2:52:08 AM]           "Http": {
[8/24/18 2:52:08 AM]             "Method": "POST",
[8/24/18 2:52:08 AM]             "Url": "http://localhost:7071/api/MyHttpTrigger",
[8/24/18 2:52:08 AM]             "Headers": {
[8/24/18 2:52:08 AM]               "content-type": "application/x-www-form-urlencoded",
[8/24/18 2:52:08 AM]               "host": "localhost:7071",
[8/24/18 2:52:08 AM]               "user-agent": "Mozilla/5.0 (Macintosh; Darwin 18.0.0 Darwin Kernel Version 18.0.0: Sun Aug 12 14:04:39 PDT 2018; root:xnu-4903.201.1~14/RELEASE_X86_64; en-US) PowerShell/6.1.0",
[8/24/18 2:52:08 AM]               "content-length": "17"
[8/24/18 2:52:08 AM]             },
[8/24/18 2:52:08 AM]             "Body": {
[8/24/18 2:52:08 AM]               "String": "{\"Name\": \"Tyler\"}",
[8/24/18 2:52:08 AM]               "Json": "",
[8/24/18 2:52:08 AM]               "Bytes": [],
[8/24/18 2:52:08 AM]               "Stream": [],
[8/24/18 2:52:08 AM]               "Int": 0,
[8/24/18 2:52:08 AM]               "Double": 0.0,
[8/24/18 2:52:08 AM]               "DataCase": "String"
[8/24/18 2:52:08 AM]             },
[8/24/18 2:52:08 AM]             "Params": {},
[8/24/18 2:52:08 AM]             "StatusCode": "",
[8/24/18 2:52:08 AM]             "Query": {},
[8/24/18 2:52:08 AM]             "EnableContentNegotiation": false,
[8/24/18 2:52:08 AM]             "RawBody": {
[8/24/18 2:52:08 AM]               "String": "{\"Name\": \"Tyler\"}",
[8/24/18 2:52:08 AM]               "Json": "",
[8/24/18 2:52:08 AM]               "Bytes": [],
[8/24/18 2:52:08 AM]               "Stream": [],
[8/24/18 2:52:08 AM]               "Int": 0,
[8/24/18 2:52:08 AM]               "Double": 0.0,
[8/24/18 2:52:08 AM]               "DataCase": "String"
[8/24/18 2:52:08 AM]             }
[8/24/18 2:52:08 AM]           },
[8/24/18 2:52:08 AM]           "Int": 0,
[8/24/18 2:52:08 AM]           "Double": 0.0,
[8/24/18 2:52:08 AM]           "DataCase": "Http"
[8/24/18 2:52:08 AM]         },
[8/24/18 2:52:08 AM]         "sys": {
[8/24/18 2:52:08 AM]           "String": "",
[8/24/18 2:52:08 AM]           "Json": "{\"MethodName\":\"MyHttpTrigger\",\"UtcNow\":\"2018-08-24T02:52:08.599495Z\",\"RandGuid\":\"e514f87a-a916-4229-892d-e30e90b2dd93\"}",
[8/24/18 2:52:08 AM]           "Bytes": [],
[8/24/18 2:52:08 AM]           "Stream": [],
[8/24/18 2:52:08 AM]           "Int": 0,
[8/24/18 2:52:08 AM]           "Double": 0.0,
[8/24/18 2:52:08 AM]           "DataCase": "Json"
[8/24/18 2:52:08 AM]         }
[8/24/18 2:52:08 AM]       }
[8/24/18 2:52:08 AM]     },
[8/24/18 2:52:08 AM]     "ContentCase": "InvocationRequest"
[8/24/18 2:52:08 AM]   },
[8/24/18 2:52:08 AM]   "Name": "InvocationRequest",
[8/24/18 2:52:08 AM]   "Source": "Rpc"
[8/24/18 2:52:08 AM] }

I'm invoking the script with Invoke-WebRequest in PowerShell:

iwr http://localhost:7071/api/MyHttpTrigger -Method Post -Body '{"Name": "Tyler"}'

Is this a bug in the host or by design and I need to attempt to deserialize it?

cc @pragnagopa + @asavaritayal

Understand authentication and authorization

What does this mean for HttpTriggers vs other triggers?

How does this work with multi-tenants?

How do we give functions the ability to manage Azure resources? MSI? Service Principle?

Concurrency story

Right now, I'm managing 1 runspace which isn't enough considering we want to handle multiple requests.

PSObject returned from function gets in the way of serialization to JSON

Objects returned from function run is warpped into PSObject. Further more, the objects in a container object such as array/hastable may also wrapped into PSObject. This makes it not possible to directly use Newtonsoft.Json in the language worker to serailize object to JSON. We need to consider to use ConvertTo-Json for serailizatoin. For deserialization, it should be fine to directly use Newtonsoft.Json APIs.

Repro

run.ps1

param($req)

Write-Verbose "Processing a HTTP request" -Verbose

$output = @{}
$output["GUID1"] = (New-Guid).Guid
$output["GUID2"] = (New-Guid).Guid

# You associate values to output bindings by calling 'Push-OutputBinding'.
return [HttpResponseContext]@{
    StatusCode = 202
    Body = $output
}

function.json

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

Expected Behavior

PS> irm http://localhost:7071/api/HttpStartPS
GUID1 GUID2
----- -----
xxxx  XXX

Actual Behavior

PS> irm http://localhost:7071/api/HttpStartPS
Microsoft.Azure.Functions.PowerShellWorker.HttpResponseContext

Unable to publish locally on the Dev branch

Hi team,

I'm following the instructions on my local machine trying to get a PoSH function running locally before running it on the cloud. I'm having issues with the publish process on the DEV branch.

Settings:
OS: MacOS High Sierra
.NET Core Version: 2.1.4
PoSH version: 6.1.0

Installed .NET Core and PoSH via HomeBrew. I can verify that both exist and run as expected. However, when I run dotnet publish I get a compilation error:

~/Projects/azure-functions-powershell-worker  dev ✔                                                                                    
▶ dotnet publish
Microsoft (R) Build Engine version 15.8.166+gd4e8d81a88 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 17.07 ms for /Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj.
  Restore completed in 64.85 ms for /Users/christosmatskas/Projects/azure-functions-powershell-worker/test/Microsoft.Azure.Functions.PowerShellWorker.Test.csproj.
  Restore completed in 17.32 ms for /Users/christosmatskas/Projects/azure-functions-powershell-worker/test/Microsoft.Azure.Functions.PowerShellWorker.Test.csproj.
FunctionLoader.cs(8,23): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Logging/ILogger.cs(7,34): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Logging/RpcLogger.cs(10,34): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Logging/RpcLogger.cs(9,23): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Messaging/MessagingStream.cs(11,23): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
PowerShell/PowerShellManager.cs(16,34): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
PowerShell/PowerShellManager.cs(14,23): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
PowerShell/StreamHandler.cs(7,34): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
RequestProcessor.cs(14,23): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Utility/ExecutionTimer.cs(9,34): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Utility/TypeExtensions.cs(12,23): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Worker.cs(13,23): error CS0234: The type or namespace name 'WebJobs' does not exist in the namespace 'Microsoft.Azure' (are you missing an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
FunctionLoader.cs(26,28): error CS0246: The type or namespace name 'FunctionLoadRequest' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
FunctionLoader.cs(43,29): error CS0246: The type or namespace name 'RpcFunctionMetadata' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
FunctionLoader.cs(40,44): error CS0246: The type or namespace name 'BindingInfo' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
FunctionLoader.cs(41,44): error CS0246: The type or namespace name 'BindingInfo' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
PowerShell/PowerShellManager.cs(105,19): error CS0246: The type or namespace name 'ParameterBinding' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Utility/TypeExtensions.cs(19,62): error CS0246: The type or namespace name 'RpcHttp' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Utility/TypeExtensions.cs(64,45): error CS0246: The type or namespace name 'TypedData' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Utility/TypeExtensions.cs(95,23): error CS0246: The type or namespace name 'RpcException' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Utility/TypeExtensions.cs(105,16): error CS0246: The type or namespace name 'RpcHttp' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Utility/TypeExtensions.cs(132,23): error CS0246: The type or namespace name 'TypedData' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
RequestProcessor.cs(67,60): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
RequestProcessor.cs(67,18): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
RequestProcessor.cs(94,62): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
RequestProcessor.cs(94,18): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
RequestProcessor.cs(126,60): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
RequestProcessor.cs(126,18): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Messaging/MessagingStream.cs(36,16): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Messaging/MessagingStream.cs(42,38): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Messaging/MessagingStream.cs(18,42): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]
Messaging/MessagingStream.cs(18,60): error CS0246: The type or namespace name 'StreamingMessage' could not be found (are you missing a using directive or an assembly reference?) [/Users/christosmatskas/Projects/azure-functions-powershell-worker/src/Microsoft.Azure.Functions.PowerShellWorker.csproj]

Something missing?

Investigate live objects for trigger objects and input bindings

Today, the only trigger type or input binding that gets a live object (as opposed to a dead object with a bag of static properties) is the Http trigger.

For additional triggers, it may be more useful for live objects to come in via the trigger. E.g. users may want "re-hydrated" live objects via the blob binding, so that they can take those objects and use them in scenarios with Azure PowerShell.

First step here should be to investigate where we put our rehydration logic (is it in the gRPC layer?). Then, we can decide whether this is actually something that users care about, and prioritize a list of bindings/triggers according to customer input.

We should decide which bindings we want to support for live objects within the Preview milestone.

Add to functions template repo

Similar to C# and JavaScript, we want to provide function templates in Powershell for commonly used trigger scenarios -

We should have HttpTrigger and TimerTrigger templates for the private preview. See this comment.

How should the PowerShell worker implement $returns (if at all)?

Background

In Azure Functions, there is a concept of "output bindings" which are essentially the output of your function. You define these outputs in the bindings section of the function.json. Here's an example function.json for an HttpTrigger and response:

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "Request",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "Response"
    }
  ]
}

notice the binding Response has a direction of out.

There exists a "special" output binding called $returns which would look like this:

    {
      "type": "http",
      "direction": "out",
      "name": "$returns"
    }

This, in every language that Azure Functions supports in V2, gives the user the ability to "return" the result. Rather than explicitly specifying that value X goes to the output binding of "Foo".

For example, in C# you would normally declare outputs using the out keyword in the function definition:

function.json

    {
      "type": "http",
      "direction": "out",
      "name": "output"
    }

run.cs

public static Run(string input, out string output)
{
    output = "Hello World";
}

But if you want to leverage $returns you would do:

function.json

    {
      "type": "http",
      "direction": "out",
      "name": "$returns"
    }

run.cs

public static Run(string input)
{
    return "Hello World";
}

Note the use of the return keyword.

The problem

PowerShell is different than most languages because it can return multiple things by leveraging the Pipeline.

In addition to that, a lot of folks write to the pipeline as a way to log something.

So implementing $returns for PowerShell is strange because it's not clear what the intended behavior should be.

The possible solutions

Solution 1: Take everything

Everything that gets thrown onto the pipeline, will be added to a list. That list will be set as the output for the output binding $returns. In addition to that, everything added to the pipeline can be logged to the host.

This idea comes from the fact that since PowerShell can "return" multiple things, a list of the things written to the pipeline would be the most "PowerShell-y" experience for $returns.

This does mean that the user would need to log using Write-Host or others instead of simply writing to the pipeline otherwise their log statements will be included in the $returns output.

Solution 2: Take one thing

Everything that gets thrown onto the pipeline will be logged, but the LAST item added to the pipeline will be the output for the output binding $returns.

This idea comes from wanting to align with other languages. It also gives the user the ability to use the pipeline for logging and "returning".

FWIW, AWS Lambda went with this approach - so I've heard.

Solution 3: Take nothing

This would mean that $returns doesn't make sense for PowerShell and the only way to specify output is by using the Push-OutputBinding command.

That said, everything added to the pipeline can be logged to the host.

Add docs: `func` CLI quickstart

We should have a quickstart doc outlining how to:

  • create a function app
  • create a function
    • timer trigger
    • HTTP trigger
  • add a module dependency
  • pack/publish to Azure
  • show it working

[Programming Model] Function Format

Summary

TBD (general information about the function format)

Binding to arguments

Input bindings

  1. Trigger input
    TBD

  2. Additional input
    TBD

Output bindings

  1. $return type
    TBD

  2. Generic type
    TBD

  3. Multiple output values for a single binding
    TBD

Referencing external modules

TBD

Logging

TBD

Async

TBD

Dependency story

How will the user package up module dependencies in their function app?

We will have the user package up their modules to a Modules folder either at the function level or at the function app level. We will also modify the PSModulePath so it looks like (in order):

/path/to/function/Modules - modules that apply to a specific function
/path/to/functionapp/Modules - modules that apply to all functions
/path/to/powershellworker/Modules - modules that ship with the worker

We can also have pack put the modules in the right module path but that will be covered in #68

Add docs for programming model

This should describe how our triggers, input/output bindings work, $return, capturing different streams, Push-OutputBinding, etc.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.