Code Monkey home page Code Monkey logo

wskdebug's Introduction

👉 wskdebug has moved to Apache OpenWhisk

New project:

Note that the npm name has changed. Install using:

npm install -g @openwhisk/wskdebug --unsafe-perm=true

All new development will happen at apache/openwhisk-wskdebug. This repository is archived and the @adobe/wskdebug npm package deprecated.


npm version License CircleCI codecov Total alerts

wskdebug

Debugging and live development for Apache OpenWhisk. CLI tool written in Node.js and depending on a local Docker. Integrates easily into IDEs such as Visual Studio Code.


Live development of a web action using wskdebug:

screen cast showing debugging of a web action using wskdebug

On the left Visual Studio Code in debug mode. On the right, a browser with the page rendered by the web action. The developer notices the feature of handling the name is not implemented yet. A breakpoint shows them that name is set, but it's not used. They add the code to respond and greet with name. Simply by saving the code, the browser auto reloads the page and the breakpoint is hit again. They step through to see that the new code is working fine, and get the expected result in the browser: "Hello, Alex!".


Youtube video of wskdebug being demoed to the OpenWhisk community:

youtube video demoing wskdebug to the openwhisk community


Contents

Installation

wskdebug requires Node.js (version 10+), npm and a local Docker environment.

To install or update run:

npm install -g @adobe/wskdebug

Uninstall

npm uninstall -g @adobe/wskdebug

About

wskdebug is a command line tool to develop and debug OpenWhisk actions in your favorite IDE or debugger with a fast feedback loop. It features:

  • full debugging of actions of the respective language runtime
  • automatic code reloading
  • LiveReload for web actions
  • auto-invoking of actions on code changes
  • or running any shell command such as a curl request on code changes

Currently, Node.js actions are supported out of the box. For others, basic debugging can be configured on the command line, while automatic code reloading needs an extension in wskdebug.

Note on timeouts

Web actions or other blocking invocations time out after 1 minute in OpenWhisk. This limit cannot be configured. This means that if the debugging session (stepping through code) takes longer than 1 minute, any web action will return an error and any blocking invocations will just get the activation id, which most callers of a blocking invocation do not expect.

However, there is no time limit on stepping through the code itself if you do not care about the result of the action being handled synchronously.

Usage

The action to debug (e.g. myaction) must already be deployed.

Node.js: Visual Studio Code

Add the configuration below to your launch.json. Replace MYACTION with the name of your action and ACTION.js with the source file containing the action. When you run this, it will start wskdebug and should automatically connect the debugger.

    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "wskdebug MYACTION",
            "runtimeExecutable": "wskdebug",
            "args": [ "MYACTION", "ACTION.js", "-l" ],
            "localRoot": "${workspaceFolder}",
            "remoteRoot": "/code",
            "outputCapture": "std"
        }
    ]

Stop the debugger in VS Code to end the debugging session and wskdebug.

This snippets enables browser LiveReloading using -l. For other reloading options, see live reloading.

For troubleshooting, you can run the debugger in verbose mode by adding "-v" to the args array.

Node.js: Multiple actions

Each wskdebug process can debug and live reload exactly a single action. To debug multiple actions, run wskdebug for each. If all of them are using the same kind/language, where the default debug port is the same, different ports need to be used.

In VS code you can start multiple debuggers from the same window thanks to compounds. Compounds provide a way to aggregate VS code configurations to run them together. Here is a .vscode/launch.json example that uses compounds to expose a config starting 2 wskdebug instances:

{
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "mypackage/action1",
      "runtimeExecutable": "wskdebug",
      "args": [
        "mypackage/action1",
        "action1.js"
      ],
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/code",
      "outputCapture": "std"
    },
    {
      "type": "node",
      "request": "launch",
      "name": "mypackage/action2",
      "runtimeExecutable": "wskdebug",
      "args": [
        "mypackage/action2",
        "action2.js"
      ],
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/code",
      "outputCapture": "std"
    }
  ],
  "compounds": [
    {
      "name": "All actions",
      "configurations": [
        "mypackage/action1",
        "mypackage/action2"
      ]
    }
  ]
}

Alternatively, if you don't want to use compounds, you can have a separate VS code window for each action with separate VS code launch configurations.

With launch, VS Code will automatically pick an unused debug port and pass it as --inspect=port param to wskdebug as if it were node, and wskdebug understands this as alias for its --port argument.

Otherwise you have to make sure to pass a different --port to each wskdebug. Similarly, if you use browser live reloading for multiple actions, you must specify different ports for that uing --lr-port on each instance.

Node.js: Plain usage

Run wskdebug and specify the action

wskdebug myaction

This will output (in case of a nodejs action):

Debug type: nodejs
Debug port: localhost:9229
Ready, waiting for activations of myaction
Use CTRL+C to exit

You can then use a debugger to connect to the debug port, in this case localhost:9229. See below.

When done, terminate wskdebug (not kill!) using CTRL+C. It will cleanup and remove the forwarding agent and restore the original action.

Node.js: Chrome DevTools

Run Node.js: Plain usage and then:

  1. Open Chrome
  2. Enter about:inspect
  3. You should see a remote target app.js
  4. Click on "Open dedicated DevTools for Node" (but not on "inspect" under Target)
  5. This should open a new window
  6. Go to Sources > Node
  7. Find the runner.js
  8. Set a breakpoint on the line thisRunner.userScriptMain(args) inside this.run() (around line 97)
  9. Invoke the action
  10. Debugger should hit the breakpoint
  11. Then step into the function, it should now show the action sources in a tab named like VM201 (the openwhisk nodejs runtime evals() the script, hence it's not directly listed as source file)

See also this article.

Node.js: node-inspect command line

Run Node.js: Plain usage and then:

Use the command line Node debugger node-inspect:

node-inspect 127.0.0.1:9229

Unsupported action kinds

To enable debugging for kinds/languages not supported out of the box, you can specify these cli arguments manually:

  • --internal-port the actual language debug port inside the container
  • --command override the docker run command for the image to e.g. pass a debug flag to the language enviroment
  • --port (optional) the port as it will be exposed from the container to the host, i.e. to what clients will connect to. defaults to --internal-port if set
  • --image (optional) control the docker image used as runtime for the action

Once you found a working configuration, feel encouraged to open a pull request to add support for this out of the box!

For automatic code reloading for other languages, wskdebug needs to be extended.

Source mounting

When a <source-path> is provided, wskdebug will load the local sources and run them as action (for supported languages/kinds). This enables the hot code reloading feature.

For this to work, you must run wskdebug in the root folder of your project, below which all the sources are (e.g. in nodejs anything that is loaded through require() statements), and then provide a relative path to the main js file (the one that contains the action main function) as <source-path> . If you have sources outside the current working directory wskdebug is executed in, they would not be visible to the action that wskdebug runs.

For example, say you have a folder structure like this:

lib/
    action/
        action.js
    util.js
    other.js

Then you want to run it in the root like this:

wskdebug myaction lib/action/action.js

Under the hood, wskdebug will mount the working directory it is executed in into the local action container (under /code inside the container), and then tell it to load the lib/action/action.js file as action entry point.

If --on-build and --build-path are specified, then --build-path is used instead of the <source-path> for running the action inside the container. It still mounts the current working directory. But <source-path> is still relevant for detecting local modifications for live reloading.

Live reloading

There are 3 different live reload mechanism possible that will trigger something when sources are modified. Any of them enables the hot reloading of code on any new activation.

  • Browser LiveReload using -l: works with LiveReload browser extensions (though we noticed only Chrome worked reliably) that will automatically reload the web page. Great for web actions that render HTML to browsers.
  • Action invocation using -P and -a: specify -P pointing to a json file with the invocation parameters and the debugged action will be automatically invoked with these parameters. This will also automatically invoke if that json file is modified. If you need to trigger a different action (because there is chain of actions before the one you are debugging), define it using -a.
  • Arbitrary shell command using -r: this can be used to invoke web APIs implemented by web actions using curl, or any scenario where something needs to be triggered so that the debugged action gets activated downstream.

By default it watches for changes underneath the current working directory for these file extensions (reflecting common OpenWhisk kinds and json for -P params.json auto-execution):

json, js, ts, coffee, py, rb, erb, go, java, scala, php, swift, rs, cs, bal, php, php5

The directory or directories to watch can be changed using the --watch argument, which can be a directory path glob. You can also specify multiple via --watch one --watch two or --watch one two.

The extensions to watch can be changed through the --watch-exts argument, e.g. --watch-exts js ts.

Hit condition

If an action is invoked frequently but you only want to catch certain invocations, such as ones you control, you can set a condition to limit when the debugger should be invoked using -c or --condition. This must be a javascript expression which will be evaluated agains the input parameters.

For example, with a condition like this:

-c "debug === 'true'"

an invocation with these parameters would trigger the debugger:

{
  "debug": "true",
  "some": "value"
}

In another example for a web action, let's assume we want to catch all requests from Chrome. We would check for the header:

-c "__ow_headers['user-agent'].includes('Chrome')"

If the hit condition is true, the action will be forwarded to the local debug container. If not, the original action (copy) in the OpenWhisk system will be invoked.

Please note that if source mounting is enabled, this will not have an effect on the original action copy that is invoked if the hit condition is not met. This means if condition is met, the latest local code changes will have an effect, but if not, the version of the action before wskdebug was started will be executed.

Custom build step

For some projects, the raw source code that developers edit in the IDE goes through a build process before being deployed as OpenWhisk action. To support this, wskdebug has these arguments:

  • --on-build: Shell command for custom action build step
  • --build-path: Path to built action, result of --on-build command

As a simple example, imagine the build process for an action with source file action.js deployed as myaction is simply renaming the file and placing it as index.js in a build/ directory:

mkdir build/
cp action.js build/index.js

Replace the copy/rename here with whatever build step is happening. Make sure source maps are enabled.

Then you would invoke wskdebug like this:

wskdebug myaction action.js \
    --on-build "mkdir build/; cp action.js build/index.js" \
    --build-path build/index.js

Note: When using --on-build, you might have to set --watch to the directory that holds the source files and which is not the build directory. Otherwise you could get an endless loop as writing the build files will trigger --on-build again. The --build-path file will be explicitly excluded from watching, but other files next to it that might be generated as part of the build are not. For example, if there is a src/ and build/ directory and multiple files would be generated under build/, add --watch src:

wskdebug myaction src/action.js \
    --on-build "mkdir build/; cp action.js build/index.js; cp util.js build/util.js" \
    --build-path build/index.js \
    --watch src

Help output

wskdebug <action> [source-path]

Debug an OpenWhisk <action> by forwarding its activations to a local docker container that
has debugging enabled and its debug port exposed to the host.

If only <action> is specified, the deployed action code is debugged.

If [source-path] is set, it must point to the local action sources which will be mounted
into the debug container. Sources will be automatically reloaded on each new activation.
This feature depends on the kind.

Supported kinds:
- nodejs: Node.js V8 inspect debugger on port 9229. Supports source mount


Arguments:
  action       Name of action to debug                                            [string]
  source-path  Path to local action sources, file or folder (optional)            [string]

Action options:
  -m, --main         Name of action entry point                                   [string]
  -k, --kind         Action kind override, needed for blackbox images             [string]
  -i, --image        Docker image to use as action container                      [string]
  --on-build         Shell command for custom action build step                   [string]
  --build-path       Path to built action, result of --on-build command           [string]

LiveReload options:
  -l            Enable browser LiveReload on [source-path]                       [boolean]
  --lr-port     Port for browser LiveReload (defaults to 35729)                   [number]
  -P            Invoke action with these parameters on changes to [source-path].
                Argument can be json string or name of json file.                 [string]
  -a            Name of custom action to invoke upon changes to [source-path].
                Defaults to <action> if -P is set.                                [string]
  -r            Shell command to run upon changes to [source-path]                [string]
  --watch       Glob pattern(s) to watch for source modifications                  [array]
  --watch-exts  File extensions to watch for modifications                         [array]

Debugger options:
  -p, --port       Debug port exposed from container that debugging clients connect to.
                   Defaults to --internal-port if set or standard debug port of the kind.
                   Node.js arguments --inspect and co. can be used too.           [number]
  --internal-port  Actual debug port inside the container. Must match port opened by
                   --command. Defaults to standard debug port of kind.            [number]
  --command        Custom container command that enables debugging                [string]
  --docker-args    Additional docker run arguments for container. Must be quoted and start
                   with space: 'wskdebug --docker-args " -e key=var" myaction'    [string]
  --on-start       Shell command to run when debugger is up                       [string]

Agent options:
  -c, --condition  Hit condition to trigger debugger. Javascript expression evaluated
                   against input parameters. Example: 'debug == 'true'            [string]
  --agent-timeout  Debugging agent timeout (seconds). Default: 5 min              [number]
  --ngrok          Use ngrok.com for agent forwarding.                           [boolean]
  --ngrok-region   Ngrok region to use. Defaults to 'us'.                         [string]

Options:
  -v, --verbose  Verbose output. Logs activation parameters and result           [boolean]
  --version      Show version number                                             [boolean]
  -h, --help     Show help                                                       [boolean]

Troubleshooting

Cannot install globally

If you get an error during npm install -g @adobe/wskdebug like this:

ngrok - downloading binary https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip
ngrok - error storing binary to local file [Error: EACCES: permission denied, open '/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/ngrok/bin/aHR0cHM6Ly9iaW4uZXF1aW5veC5pby9jLzRWbUR6QTdpYUhiL25ncm9rLXN0YWJsZS1kYXJ3aW4tYW1kNjQuemlw.zip'] {
  errno: -13,
  code: 'EACCES',
  syscall: 'open',
  path: '/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/ngrok/bin/aHR0cHM6Ly9iaW4uZXF1aW5veC5pby9jLzRWbUR6QTdpYUhiL25ncm9rLXN0YWJsZS1kYXJ3aW4tYW1kNjQuemlw.zip'
}

run this command below before trying the install again:

sudo chown -R $(whoami) /usr/{lib/node_modules}

The dependency ngrok requires full write permission in /usr/local/lib/node_modules during its custom install phase. This is a known ngrok issue.

Does not work, namespace shows as undefined

Your ~/.wskprops must include the correct NAMESPACE field. See issue #3.

No invocations visible in wskdebug

  • Is wskdebug working against the correct namespace? You can see that in the "Starting debugger for ..." output at the very start. If you tend to use WSK_CONFIG_FILE in your shell, please be aware that IDEs starting wskdebug will use ~/.wskprops unless you set the environment variable for the wskdebug invocation in the IDE.
  • Wait a bit and try again. Restart (CTRL+C, then start wskdebug again), wait a bit and try again. Catching the invocations is not 100% perfect.

Port is already allocated

You can only run one wskdebug aka one action for the same runtime (debug port) at a time.

If you get an error like this:

docker: Error response from daemon: driver failed programming external connectivity on endpoint wskdebug-webaction-1559204115390 (3919892fab2981bf9feab0b6ba3fc256676de59d1a6ab67519295757313e8ac3): Bind for 0.0.0.0:9229 failed: port is already allocated.

it means that there is another wskdebug already running or that its container was left over, blocking the debug port.

Either quit the other wskdebug or if its an unexpected left over, terminate the docker container using:

docker rm -f wskdebug-webaction-1559204115390

The containers are named wskdebug-ACTION-TIMESTAMP.

Restore action

If wskdebug fails unexpectedly or gets killed, it might leave the forwarding agent behind in place of the action. You should be able to restore the original action using the copied action named *_wskdebug_original.

wsk action delete myaction
wsk action create --copy myaction myaction_wskdebug_original
wsk action delete myaction_wskdebug_original

Alternatively you could also redeploy your action and then delete the backup:

# deploy command might vary
wsk action update myaction myaction.js

wsk action delete myaction_wskdebug_original

How it works

wskdebug supports debugging of an action by forwarding it from the OpenWhisk system to a local container on your desktop and executing it there. By overriding the command to run in the container and other docker run configurations, the local container respectively the language runtime inside the container is run in debug mode and the respective debug port is opened and exposed to the local desktop.

Furthermore, the local container can mount the local source files and automatically reload them on every invocation. wskdebug can also listen for changes to the source files and trigger an automatic reload of a web action or direct invocation of the action or just any shell command, e.g. if you need to make more nuanced curl requests to trigger your API.

The forwarding works by replacing the original action with a special agent. There are different agent variations, which all achieve the same: catch activations of the action on the OpenWhisk side, pass them on to the local container and finally return the local result back to the original activation.

The fastest option (concurrency) leverages the NodeJS concurrency feature available in some OpenWhisk installations where a single container instance will receive all activations. It uses queues implemented as global variables of the action so that multiple invocations of this action (agent) can see and wait for each other.

The second fastest option - and fastest in case of an OpenWhisk that does not support concurrency - is using ngrok localhost forwarding. It must be manually selected using --ngrok on the command line. This works even without an ngrok account.

Lastly, there is the "activation DB" agent which simply stores the activation input and result as separate activations (using helper actions named *_wskdebug_invoked and *_wskdebug_completed) and polls them via wsk activation list, both from wskdebug (for new activations) and in the agent itself (waiting for results).

Inside the agents waiting for the result is where the limits have an effect: if the invocation is synchronous (blocking=true) or a web action, OpenWhisk will not wait for more than 1 minute. For asynchronous invocations, it depends on the timeout setting of the action. wskdebug sets it to 5 minute by default but it can be controlled via --agent-timeout to set it to a feasible maximum.

The debugger works with all normal actions, including web actions. Sequences are not directly supported but can be debugged by starting a debugger for each action in the sequence see Nodejs Multiple actions. Compositions itself (not the component actions) are not supported. The solution is only based on custom actions and works with any OpenWhisk system. wskdebug was inspired by the now defunct wskdb.

diagram showing wskdebug

This diagram shows how wskdebug works including debugging, source mounting and browser LiveReload. The wskdebug components are marked blue. Follow the steps from (1) to (10) to see what happens when the user edits and saves a source file.

Development

Extending wskdebug for other kinds

For automatic code reloading for other languages, wskdebug needs to be extended to support these kinds. This happens inside src/kinds.

Mapping of kinds to docker images

To change the mapping of kinds to docker images (based on runtimes.json from OpenWhisk), change src/kinds/kinds.js.

Custom debug kind

For default debug instructions and live code reloading, a custom "debug kind js" needs to be provided at src/kinds/<debugKind>/<debugKind>.js.

<debugKind> must be without the version, i.e. the part before the : in a kind. For example for nodejs:8 it will be nodejs, for nodejs:default it will be nodejs as well. This is because normally the debug mechanism is the same across language versions. To define a different debug kind, add a debug field in src/kinds/kinds.js for the particular kind, e.g. for nodejs:6set debug: "nodejsLegacy" and then it must be under src/kinds/nodejsLegacy/nodejsLegacy.js.

This js module needs to export an object with different fields. These can be either a literal value (for simple fixed things such as a port) or a function (allowing for dynamic logic based on cli arguments etc.). These functions get the invoker passed as argument, which provides certain variables such as cli arguments.

A complete example is the src/kinds/nodejs/nodejs.js.

See below for the different items to do.

Default debug ports and commands

To just add default debug ports and docker command for a kind, add a custom debug kind and export an object with description, port and command fields. Optionally dockerArgs for extra docker arguments (such as passing in environment variables using -e if necessary).

Support code reloading

To support live code reloading/mounting, add a custom debug kind and export an object with a mountAction function. This has to return an action that dynamically loads the code at the start of each activation. A typical approach is to mount the <source-path> (folder) passed on the cli as /code inside the docker container, from where the mount action can reload it. The exact mechanism will depend on the language - in node.js for example, eval() is used for plain actions. The docker mounting can be specified in dockerArgs.

The mountAction(invoker) must return an object that is an openwhisk action /init definition, which consists of:

  • binary: true if zip or binary distribution (depends on kind), false if plain code (for scripting languages)
  • main: name of the entry function
  • code: string with source code or base64 encoded if binary for the live mount

Example mounting actions from nodejs are mount-plain.js (for plain node.js actions) and mount-require.js (for action zips expecting node modules using require()).

Available variables

See also invoker.js. Note that some of these might not be set yet, for example invoker.debug.port is not yet available when port() is invoked. The raw cli args are usually available as invoker.<cli-arg>.

Variable Type Description
invoker.main string name of the main entry point (from cli args)
invoker.sourcePath string path to the source file either <source-path> or the --build-path
invoker.sourceDir string absolute path to root directory to mount in the container
invoker.sourceFile string relative path from sourceDir to sourcePath
invoker.action object the object representing the debugged action, as specified as Action model in the openwhisk REST API spec
invoker.debug.port number --port from cli args or --internal-port or the port from the debug kind js (in that preference)
invoker.debug.internalPort number --internal-port from cli args or if not specified, the port from the debug kind js
invoker.debug.command string --command from cli args or the command from the debug kind js (in that preference)

Contributing

Contributions are welcomed! Read the Contributing Guide for more information.

Licensing

This project is licensed under the Apache V2 License. See LICENSE for more information.

wskdebug's People

Contributors

alexkli avatar moritzraho avatar

Stargazers

 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

wskdebug's Issues

debug hit condition for agent

Sometimes one might want to debug an action but only for a certain condition, flag, cookie etc., while not impacting other requests that invoke the action. For this some condition expression would need to be set by the user, and if it does not match, the original backed up action would be called instead of forwarding to the local container.

Add doc on how to start multiple debuggers in same vscode window

Originally reported and contributed by @moritzraho

The doc states that only one debugger can be started per vscode window, which is not true anymore.
In fact, vscode debug config has the concept of compounds which allows to aggregate multiple configurations.
This also enables debugging for sequences OOTB (i.e. by starting a wskdebug instance for all the actions of a sequence). Which makes wskdebug even more useful :)
Here is a launch.json example that exposes a config starting 2 wskdebug instances:

{
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "mypackage/action1",
      "runtimeExecutable": "wskdebug",
      "args": [
        "tmypackage/action1",
        "${workspaceFolder}/action1.js"
      ],
      "localRoot": "${workspaceFolder}/actions/hello",
      "remoteRoot": "/code",
      "outputCapture": "std"
    },
    {
      "type": "node",
      "request": "launch",
      "name": "mypackage/action2",
      "runtimeExecutable": "wskdebug",
      "args": [
        "mypackage/action2",
        "${workspaceFolder}/action2.js"
      ],
      "localRoot": "${workspaceFolder}/actions/hello2",
      "remoteRoot": "/code",
      "outputCapture": "std"
    }
  ],
  "compounds": [
    {
      "name": "All actions",
      "configurations": [
        "mypackage/action1",
        "mypackage/action2"
      ]
    }
  ]
}

wskdebug fails if action name includes chars not allowed in docker container names such as @

Steps to reproduce

  1. create action named wskdebug-examples/[email protected]
  2. run wskdebug for it:
    wskdebug wskdebug-examples/[email protected]
    

Error

wskdebug fails with Invalid container name ([email protected]).

Starting debugger for /aklimets/wskdebug-examples/[email protected]
docker: Error response from daemon: Invalid container name ([email protected]), only [a-zA-Z0-9][a-zA-Z0-9_.-] are allowed.
See 'docker run --help'.
Error: Command failed: docker run -d --name [email protected] --rm -m 268435456 -p 8080 -p 9229:9229 adobeapiplatform/adobe-action-nodejs-v10:3.0.21 node --expose-gc --inspect=0.0.0.0:9229 app.js 
docker: Error response from daemon: Invalid container name ([email protected]), only [a-zA-Z0-9][a-zA-Z0-9_.-] are allowed.

Concurrency error when using wskdebug with IBM Cloud Functions

Version

wskdebug --version
1.0.10

Description

I am trying to use wskdebug with IBM Cloud Functions.

Step 1: My action is very simple

function main(args) {
  if (args && args.name) {
    console.log(`hello ${args.name}`);
    return { msg: `hello ${args.name}` };
  } else {
    console.log(`hello world`);
    return { msg: `hello world` };
  }
}

Step 2: Created the action on IBM Cloud

ibmcloud fn action create hello-debug index.js

Step 3: started wskdebug

I get an error when it tried to create the temporary Agent action. I don’t need the LiveReload support.

Error

$ wskdebug hello-debug index.js -v
Starting debugger for /_/hello-debug
Starting local debug container wskdebug-hello-debug-1573772149542
docker run -d --name wskdebug-hello-debug-1573772149542 --rm -m 268435456 -p 8080 -p 9229:9229 -v "/Users/ulidder/Documents/icloud-documents/code-upkar/temp/openwhisk/simple:/code" ibmfunctions/action-nodejs-v10:1.13.0 node --expose-gc --inspect=0.0.0.0:9229 app.js
cf95f1d200e860c91aa179ef40f747c0065b998a2acbe1b914c18c33f4db36f9
Mounting sources onto local debug container: /Users/ulidder/Documents/icloud-documents/code-upkar/temp/openwhisk/simple/index.js
2019-11-14T22:55:50.728771670Z Debugger listening on ws://0.0.0.0:9229/5c06b464-72f7-45a4-b0f8-0c74fc9deaf2
2019-11-14T22:55:50.728824972Z For help, see: https://nodejs.org/en/docs/inspector
Installing agent in OpenWhisk (concurrency)...
Original action backed up at hello-debug_wskdebug_original.
{ OpenWhiskError: PUT https://us-south.functions.cloud.ibm.com/api/v1/namespaces/_/actions/hello-debug?overwrite=true Returned HTTP 400 (Bad Request) --> "The request content was malformed:
requirement failed: concurrency 200 exceeds allowed threshold of 1"
    at Client.handleErrors (/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/openwhisk/lib/client.js:216:11)
    at params.then.catch.err (/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/openwhisk/lib/client.js:147:58)
    at processTicksAndRejections (internal/process/task_queues.js:86:5)
  name: 'OpenWhiskError',
  message:
   'PUT https://us-south.functions.cloud.ibm.com/api/v1/namespaces/_/actions/hello-debug?overwrite=true Returned HTTP 400 (Bad Request) --> "The request content was malformed:\nrequirement failed: concurrency 200 exceeds allowed threshold of 1"',
  error:
   { code: 'df940ccf1d076f103c3743685c25d2b2',
     error:
      'The request content was malformed:\nrequirement failed: concurrency 200 exceeds allowed threshold of 1' },
  statusCode: 400 }

Restoring action

Workaround by @alexkli

It should normally automatically pick a different agent that does not require the concurrency feature, but I guess that detection is not perfect yet (it looks at the swagger api docs and maybe the ibm cloud has different information in there).
As alternative, you can try the ngrok option using --ngrok. It should just work - you don’t even need an ngrok.com account.

[nodejs] errors with mount-plain webpack bundled js file

Description

wskdebug for mount-plain.js (used in not zipped actions) is failing for webpack bundled actions while the same bundled js file works with mount-require.js (used in zipped action)

Error

> wskdebug my-bundled-action path/to/myaction.js

#do the invocation

Activation: 15632c7e0da648a0a32c7e0da6c8a022
2019-11-07T09:18:34.487541760Z RangeError: Maximum call stack size exceeded
2019-11-07T09:18:34.487609654Z     at Object.eval (/code/index.js:97:16)
2019-11-07T09:18:34.487619477Z     at __webpack_require__ (/code/index.js:21:30)
2019-11-07T09:18:34.487623701Z     at Object.module.exports.exports.main (/code/index.js:92:18)
2019-11-07T09:18:34.487627441Z     at __webpack_require__ (/code/index.js:21:30)
2019-11-07T09:18:34.487631131Z     at eval (/code/index.js:85:18)
2019-11-07T09:18:34.487634802Z     at eval (/code/index.js:88:10)
2019-11-07T09:18:34.487638372Z     at eval (/code/index.js:140:16)
2019-11-07T09:18:34.487642048Z     at load (eval at NodeActionRunner.init (/nodejsAction/runner.js:80:45), <anonymous>:30:16)
2019-11-07T09:18:34.487646464Z     at main (eval at NodeActionRunner.init (/nodejsAction/runner.js:80:45), <anonymous>:45:24)
2019-11-07T09:18:34.487650648Z     at main (eval at NodeActionRunner.init (/nodejsAction/runner.js:80:45), <anonymous>:48:12)
2019-11-07T09:18:34.487856218Z XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX
2019-11-07T09:18:34.488231343Z XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX
Completed activation 15632c7e0da648a0a32c7e0da6c8a022 in 18.025 sec

The problem seems to come from nested evals

Webpack config

entry: [
            actionPath
          ],
          output: {
            path: buildDir,
            filename: buildFilename,
            libraryTarget: 'commonjs2'
          },
          // see https://webpack.js.org/configuration/mode/
          mode: 'production',
          target: 'node',
          optimization: {
            // error on minification for some libraries
            minimize: false
          },
          // the following lines are used to require es6 module, e.g.node-fetch which is used by azure sdk
          resolve: {
            extensions: ['.js'],
            mainFields: ['main']
          },

Workaround

  • rename path/to/myaction.js to index.js
  • zip it
  • update your action with the new zip action
    => wskdebug works fine

wskdebug cannot install on mac os mojave

I tried to install wskdebug on mac os mojave (with root privileges) using node version 12.

The installation keeps failing with following errors:

/usr/local/bin/wskdebug -> /usr/local/lib/node_modules/@adobe/wskdebug/index.js

[email protected] install /usr/local/lib/node_modules/@adobe/wskdebug/node_modules/fsevents
node install

Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js configure --fallback-to-build --module=/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64/fse.node --module_name=fse --module_path=/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64 --napi_version=5 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v72' (1)

[email protected] postinstall /usr/local/lib/node_modules/@adobe/wskdebug/node_modules/ngrok
node ./postinstall.js

ngrok - downloading binary https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip
ngrok - error storing binary to local file [Error: EACCES: permission denied, open '/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/ngrok/bin/aHR0cHM6Ly9iaW4uZXF1aW5veC5pby9jLzRWbUR6QTdpYUhiL25ncm9rLXN0YWJsZS1kYXJ3aW4tYW1kNjQuemlw.zip'] {
errno: -13,
code: 'EACCES',
syscall: 'open',
path: '/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/ngrok/bin/aHR0cHM6Ly9iaW4uZXF1aW5veC5pby9jLzRWbUR6QTdpYUhiL25ncm9rLXN0YWJsZS1kYXJ3aW4tYW1kNjQuemlw.zip'
}
ngrok - downloading progress: 0/13671591�[2K�[1Gngrok - downloading progress: 3768/13671591ngrok - error storing binary to local file Error [ERR_STREAM_DESTROYED]: Cannot call write after a stream was destroyed
at doWrite (_stream_writable.js:427:19)
at writeOrBuffer (_stream_writable.js:415:5)
at WriteStream.Writable.write (_stream_writable.js:305:11)
at Transform.ondata (_stream_readable.js:726:22)
at Transform.emit (events.js:210:5)
at addChunk (_stream_readable.js:308:12)
at readableAddChunk (_stream_readable.js:289:11)
at Transform.Readable.push (_stream_readable.js:223:10)
at Transform.push (_stream_transform.js:150:32)
at Transform.afterTransform (_stream_transform.js:94:10) {
code: 'ERR_STREAM_DESTROYED'
}
�[2K�[1Gngrok - downloading progress: 19696/13671591ngrok - downloading binary https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip
ngrok - error storing binary to local file [Error: EACCES: permission denied, open '/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/ngrok/bin/aHR0cHM6Ly9iaW4uZXF1aW5veC5pby9jLzRWbUR6QTdpYUhiL25ncm9rLXN0YWJsZS1kYXJ3aW4tYW1kNjQuemlw.zip'] {
errno: -13,
code: 'EACCES',
syscall: 'open',
path: '/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/ngrok/bin/aHR0cHM6Ly9iaW4uZXF1aW5veC5pby9jLzRWbUR6QTdpYUhiL25ncm9rLXN0YWJsZS1kYXJ3aW4tYW1kNjQuemlw.zip'
}

It seems strange to me that accesses are missing. Any idea what could really go wrong?
Do I need to install ngrok locally as pre-requisite? If so, where?

wskdebug fails if path argument is missing

Apparently #11 wasn't properly fixed or some other change reintroduced it.

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be one of type string, Buffer, or URL. Received type undefined
    at Object.lstatSync (fs.js:834:3)
    at Object.lstatSync (/usr/local/lib/node_modules/@adobe/wskdebug/node_modules/graceful-fs/polyfills.js:308:16)
    at OpenWhiskInvoker.startContainer (/usr/local/lib/node_modules/@adobe/wskdebug/src/invoker.js:123:16)
    at OpenWhiskInvoker.start (/usr/local/lib/node_modules/@adobe/wskdebug/src/invoker.js:78:20)
    at Debugger.run (/usr/local/lib/node_modules/@adobe/wskdebug/src/debugger.js:103:32)
    at process._tickCallback (internal/process/next_tick.js:68:7)

Support reading package name from WSK_PACKAGE env var

Motivation

Some Openwhisk applications deploy their actions in a package that is defined at deployment time and includes a version number etc. OTOH, when using a VS Code launch config one cannot easily use environment variables for the action name, so something like wskdebug $WSK_PACKAGE/myaction does NOT work. It is impractical if each developer, working against a different package, has to modify the VS code launch.json which is usually version controlled.

Solution

Users would configure wskdebug myaction in their launch.json config. Upon start, wskdebug would:

  • if WSK_PACKAGE env var is set: use $WSK_PACKAGE/myaction as fully qualified action name
  • if WSK_PACKAGE is not set: use myaction

In case the cli argument already contains a package as part of the action name (package/myaction), the cli arg would be used and the env var ignored. This would follow standard cli behavior patterns.

Notes

Sometimes the action name might also get dynamically generated. So maybe we should also support WSK_ACTION as well? What to specify on the cli then?

[nodejs] mount-require is only reloading the main source file, not any other required files

With an action project structure like this:

package.json
core.js
lib/
  helper.js

where core.js does require('./lib/helper.js') and a wskdebug invocation such as

wskdebug core core.js -l

it will see all file changes, but it won't actually reload anything other than the main file (core.js). This is because here

https://github.com/adobe/wskdebug/blob/master/src/kinds/nodejs/mount-require.js#L37

we are only clearing the require cache for the main file. It should also delete any subpaths or all deps (maybe someone did an npm install in between and node_modules should also be reloaded).

options to control source watching, to prevent endless on-build loop

With the changes from #35, the watchDir for source changes is the current working dir, and this can include the build directory if --on-build and --build-path are used. This leads to an endless loop - a source modification triggering a build, which writes e.g. a js inside the build directory, which is watched and triggers a new build.

Options:

  1. do not use current working dir as watchDir, but make it a configurable path
  2. automatically detect loop somehow and break it

[nodejs] load local sources using require() even if action is not zip/binary

Some projects have a build step that takes it from a normal commonjs code to a single action javascript (no zip) that is Ioaded using eval by the OpenWhisk nodejs runtime. However, when loading the original or intermediary sources (via --on-build), require()-based loading is required.

This could be controlled through a command line option, although that would be nodejs specific. Maybe there is also an automatic way.

add ngrok as forwarding option

Initial tests show that using ngrok is faster than the agent-no-concurrency which uses dummy activation records to exchange in- and output. (The concurrency agent still seems to be the fastest, but it isn‘t supported by all openwhisk deployments, notably IBM Cloud)

Ngrok works free and without an account for a few connections and with a timeout of ~7 hours, which works for most debugging use cases.

contribute wskdebug to Apache OpenWhisk

Contribute wskdebug to Apache OpenWhisk, possibly as replacement of wskdb.

Note: while the IP clearance is ongoing, do not merge any pull requests from new external contributors other than the existing contributors. This would complicate the process. They can be merged after the contribution to OpenWhisk.

ngrok:

On Wed, Feb 19, 2020 at 7:02 PM Alexander Klimetschek
<[email protected]> wrote:
> Bertrand wrote:
> > IIUC there's no bundling of ngrok with wskdebug and users have to download ngrok separately?
> Not quite. Their npm client library is bundled with wskdebug, and this is licensed under BSD-2-Clause...

Ok, BSD 2 clause is fine as per [1],

> When you run wskdebug you have the option to specify —ngrok on the command line which will by
> default use their free tier service, or you could also use their paid plans if you want to (I think)....

I think mentioning this in the module's README or in the --ngrok help
option text would be sufficient - I don't think anything banned by [1]
is being redistributed so you just want to warn users that by default
they are led to use that service.

-Bertrand

[1] https://apache.org/legal/resolved.html

Various small fixes for running with openwhisk-standalone

This was a PR in the previous repository. Replicating information here as fake issue so that links to the PR still resolve.

These fixes make it possible to run wskdebug with openwhisk-standalone jar apache/openwhisk#4516:

  • Concurrency fix for OpenWhisk systems w/o concurrency support, set to concurrency to 1 if not supported by the platform
  • Better error message if cannot read /api/v1/api-docs
  • added annotation to include auth key in agent action needed in newer ow versions

This fix allows to run action code that was build with parcel :

  • Remove use strict when mounting action code. see parcel-bundler/parcel#1401 (comment) for why code built with parcel needs to be loaded with no strict. Also strict is not defined in nodejs OW runtimes.

add basic tests

Would be great to have at least some basic tests, and some CI running the build and tests.

fetch runtimes for kinds dynamically from OW API

curl https://runtime.adobe.io

{
  "api_paths": [
    "/api/v1"
  ],
  "description": "OpenWhisk",
  "limits": {
    "actions_per_minute": 600,
    "concurrent_actions": 100,
    "max_action_duration": 1800000,
    "max_action_logs": 10485760,
    "max_action_memory": 52428800000,
    "min_action_duration": 100,
    "min_action_logs": 0,
    "min_action_memory": 134217728,
    "sequence_length": 50,
    "triggers_per_minute": 600
  },
  "runtimes": {
    "nodejs": [
      {
        "attached": true,
        "default": true,
        "deprecated": false,
        "image": "bladerunner/adobe-action-nodejs-v10:3.0.21",
        "kind": "nodejs:10",
        "requireMain": false
      },
      {
        "attached": true,
        "default": false,
        "deprecated": true,
        "image": "bladerunner/adobe-action-nodejs-v10-fat:3.0.17",
        "kind": "nodejs",
        "requireMain": false
      },
      {
        "attached": true,
        "default": false,
        "deprecated": true,
        "image": "bladerunner/adobe-action-nodejs-v10-fat:3.0.17",
        "kind": "nodejs:10-fat",
        "requireMain": false
      },
      {
        "attached": true,
        "default": false,
        "deprecated": true,
        "image": "bladerunner/adobe-action-nodejs-v10-fat:3.0.17",
        "kind": "nodejs:6",
        "requireMain": false
      },
      {
        "attached": true,
        "default": false,
        "deprecated": true,
        "image": "bladerunner/adobe-action-nodejs-v10-fat:3.0.17",
        "kind": "nodejs:8",
        "requireMain": false
      }
    ]
  },
  "support": {
    "github": "https://github.com/apache/incubator-openwhisk/issues",
    "slack": "http://slack.openwhisk.org"
  }
}

Docker errors when spaces or uppercase chars in src path

Originally reported by @moritzraho

  • Error if uppercase in src file path:
wskdebug hello Uppercase/hello.js
Error: Command failed: docker run -d --name wskdebug-hello-1564994363895 --rm -m 268435456 -p 8080 -p 9229:9229 -v /Users/xxxx/demos/Uppercase/hello:/code adobeapiplatform/adobe-action-nodejs-v10:3.0.13 node --expose-gc --inspect=0.0.0.0:9229 app.js
docker: invalid reference format: repository name must be lowercase.
See 'docker run --help'.

This might be still ok as docker's error is pretty specific

  • Error when space:
wskdebug hello "space path"/hello.js
Error: Command failed: docker run -d --name wskdebug-hello-1564994363895 --rm -m 268435456 -p 8080 -p 9229:9229 -v /Users/xxxx/demos/space path/hello:/code adobeapiplatform/adobe-action-nodejs-v10:3.0.13 node --expose-gc --inspect=0.0.0.0:9229 app.js
docker: invalid reference format.
See 'docker run --help'.

This is not ok as there is no mention of what caused the error

run build step after source change but before reload

Some projects might use a build process that transpiles, wraps or otherwise changes the source code (that gets changed & saved and triggers the reload) to the one that can run in OpenWhisk and needs to be mounted.

This requires two new arguments:

  • specify the "build" directory with the built code to mount in the local container
  • an argument for specifying the build command

faster time to vs code debug

If the action code is larger, downloading it as part of openwhisk.actions.get() in Debugger.getAction() at the very start can take considerable time. For example, 6-7 seconds overhead. Notably, VS Code has a default 10 second timeout when trying to attach to a nodejs debug port.

It's not needed if local sources are mounted (which is probably the more common use case) and can be skipped in this case.

Actually, it is needed to create the backup action: the openwhisk API does not support a server side copy (or rename), hence creating the backup copy always requires downloading the full action code, then creating the backup action. And we can't do anything else before we have the safe backup.

We might be able to improve the time to vs code debug by changing the order a bit, even though one still has to wait the same overall time:

  1. get action without code
  2. start docker container (this is what VSCode needs)
  3. get action with code
  4. /init local container (with code from 3 if no local sources)
  5. create backup action (with code from 3)
  6. install agent in place of existing action
  7. start live reload (watch source files & run first on build)

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.