├── .asf.yaml ├── .gitattributes ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── CHANGES.md ├── CONTRIBUTING.md ├── CREDITS.txt ├── LICENSE-testify.txt ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── actionloop ├── Dockerfile └── build.gradle ├── build.gradle ├── common ├── gobuild.py └── gobuild.py.launcher.go ├── docs ├── ACTION.md ├── BUILD.md ├── DEPLOY.md └── ENVVARS.md ├── examples ├── EXAMPLES.md ├── Makefile ├── aws-main │ ├── Makefile │ ├── go.mod │ ├── go.sum │ └── main.go ├── bash │ ├── Makefile │ └── hello.sh ├── module-main │ ├── Makefile │ ├── go.mod │ ├── go.sum │ └── main.go ├── package-main │ ├── Makefile │ ├── go.mod │ ├── hello │ │ ├── go.mod │ │ ├── hello.go │ │ └── hello_test.go │ └── main.go ├── single-hello │ ├── Makefile │ └── hello.go ├── single-main │ ├── Makefile │ └── main.go ├── standalone │ ├── Makefile │ └── exec.go └── test.expected ├── go.mod ├── go.sum ├── golang1.21 ├── Dockerfile ├── Makefile ├── bin │ └── compile ├── build.gradle └── lib │ └── launcher.go ├── golang1.22 ├── Dockerfile ├── Makefile ├── bin │ └── compile ├── build.gradle └── lib │ └── launcher.go ├── golang1.23 ├── Dockerfile ├── Makefile ├── bin │ └── compile ├── build.gradle └── lib │ └── launcher.go ├── gradle ├── README.md ├── docker.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── licenses └── LICENSE-testify.txt ├── main └── proxy.go ├── openwhisk ├── _test │ ├── action │ │ ├── .gitignore │ │ ├── hello.go │ │ ├── hello_test.go │ │ └── main.go │ ├── badack.sh │ ├── badack2.sh │ ├── badcompile.sh │ ├── bc.sh │ ├── build.sh │ ├── compile.py │ ├── dir │ │ └── etc │ ├── env.sh │ ├── error.src │ ├── etc │ ├── exec.src │ ├── find.sh │ ├── first │ │ └── 3 │ │ │ └── .gitkeep │ ├── hello.sh │ ├── hello.src │ ├── hello │ │ └── hello.go │ ├── hello1.src │ ├── hello2.src │ ├── hello_greeting.src │ ├── hello_message.src │ ├── helloack │ │ └── exec │ ├── hi.src │ ├── jar │ │ ├── META-INF │ │ │ └── MANIFEST.MF │ │ └── hello.txt │ ├── postcompile.sh │ ├── precompile.sh │ ├── pysample │ │ ├── exec │ │ └── lib │ │ │ ├── action │ │ │ ├── __init__.py │ │ │ └── main.py │ │ │ └── exec.py │ ├── second │ │ ├── 3 │ │ │ └── .gitkeep │ │ ├── 8 │ │ │ └── .gitkeep │ │ └── 17 │ │ │ └── .gitkeep │ ├── src │ │ ├── hello │ │ │ └── hello.go │ │ └── main.go │ └── zips.sh ├── actionProxy.go ├── actionProxy_test.go ├── compiler.go ├── compiler_test.go ├── debug.go ├── executor.go ├── executor_test.go ├── extractor.go ├── extractor_test.go ├── filetype.go ├── filetype_test.go ├── initHandler.go ├── initHandler_test.go ├── runHandler.go ├── tar.go ├── util_test.go ├── version.go ├── zip.go └── zip_test.go ├── settings.gradle └── tests ├── build.gradle └── src └── test └── scala └── runtime └── actionContainers ├── ActionLoopBasicGo21Tests.scala ├── ActionLoopBasicGo22Tests.scala ├── ActionLoopBasicGo23Tests.scala ├── ActionLoopBasicGoTests.scala ├── ActionLoopBasicTests.scala ├── ActionLoopContainerTests.scala ├── ActionLoopGo21ContainerTests.scala ├── ActionLoopGo22ContainerTests.scala ├── ActionLoopGo23ContainerTests.scala ├── ActionLoopGoContainerTests.scala └── GoResourceHelpers.scala /.asf.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | github: 19 | description: "Apache OpenWhisk Runtime Go supports Apache OpenWhisk functions written in Go" 20 | homepage: https://openwhisk.apache.org/ 21 | labels: 22 | - openwhisk 23 | - apache 24 | - serverless 25 | - faas 26 | - functions-as-a-service 27 | - cloud 28 | - serverless-architectures 29 | - serverless-functions 30 | - docker 31 | - functions 32 | - openwhisk-runtime 33 | - go 34 | protected_branches: 35 | master: 36 | required_status_checks: 37 | strict: false 38 | required_pull_request_reviews: 39 | required_approving_review_count: 1 40 | required_signatures: false 41 | enabled_merge_buttons: 42 | merge: false 43 | squash: true 44 | rebase: true 45 | features: 46 | issues: true 47 | 48 | notifications: 49 | commits: commits@openwhisk.apache.org 50 | issues_status: issues@openwhisk.apache.org 51 | issues_comment: issues@openwhisk.apache.org 52 | pullrequests_status: issues@openwhisk.apache.org 53 | pullrequests_comment: issues@openwhisk.apache.org 54 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization. 2 | # Resources: 3 | # - https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html 4 | # - http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ 5 | # - https://help.github.com/articles/dealing-with-line-endings/ 6 | * text=auto 7 | 8 | *.go text eol=lf 9 | *.java text 10 | *.js text 11 | *.md text 12 | *.py text eol=lf 13 | *.scala text 14 | *.sh text eol=lf 15 | *.gradle text 16 | *.xml text 17 | *.bat text eol=crlf 18 | 19 | *.jar binary 20 | *.png binary 21 | 22 | 23 | # bash files not having the .sh extension 24 | gradlew text eol=lf 25 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | 19 | name: Continuous Integration 20 | 21 | on: 22 | push: 23 | branches: [ master ] 24 | tags: [ '*' ] 25 | pull_request: 26 | branches: [ master ] 27 | types: [ opened, synchronize, reopened ] 28 | schedule: 29 | - cron: '30 1 * * 1,3,5' 30 | 31 | permissions: read-all 32 | 33 | jobs: 34 | ci: 35 | runs-on: ubuntu-22.04 36 | env: 37 | PUSH_NIGHTLY: ${{ (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/master' }} 38 | PUSH_RELEASE: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} 39 | steps: 40 | # Checkout just this repo and run scanCode before we do anything else 41 | - name: Checkout runtime repo 42 | uses: actions/checkout@v4 43 | with: 44 | path: runtime 45 | - name: Scan Code 46 | uses: apache/openwhisk-utilities/scancode@master 47 | 48 | # Install core OpenWhisk artifacts needed to build/test anything else 49 | - name: Checkout OpenWhisk core repo 50 | uses: actions/checkout@v4 51 | with: 52 | repository: apache/openwhisk 53 | path: core 54 | - name: Setup Java 55 | uses: actions/setup-java@v4 56 | with: 57 | distribution: 'temurin' 58 | java-version: '11' 59 | - name: Compile and Install Core OpenWhisk 60 | working-directory: core 61 | run: | 62 | ./gradlew :tests:compileTestScala 63 | ./gradlew install 64 | 65 | # Build this repository 66 | - name: Build Runtime 67 | working-directory: runtime 68 | run: | 69 | ./gradlew distDocker 70 | 71 | # Test this repository 72 | - name: Test Runtime 73 | working-directory: runtime 74 | run: | 75 | ./gradlew :tests:checkScalafmtAll 76 | ./gradlew :tests:test 77 | 78 | # Conditionally publish runtime images to DockerHub 79 | # Important: naming convention for release tags is runtime@version 80 | - name: Docker Login 81 | if: ${{ env.PUSH_NIGHTLY == 'true' || env.PUSH_RELEASE == 'true' }} 82 | uses: docker/login-action@v3 83 | with: 84 | username: ${{ secrets.DOCKERHUB_USER_OPENWHISK }} 85 | password: ${{ secrets.DOCKERHUB_TOKEN_OPENWHISK }} 86 | - name: Push Nightly Images 87 | if: ${{ env.PUSH_NIGHTLY == 'true' }} 88 | working-directory: runtime 89 | run: | 90 | SHORT_COMMIT=$(git rev-parse --short "$GITHUB_SHA") 91 | ./gradlew :actionloop:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=nightly 92 | ./gradlew :actionloop:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT 93 | ./gradlew :golang1.21:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=nightly 94 | ./gradlew :golang1.21:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT 95 | ./gradlew :golang1.22:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=nightly 96 | ./gradlew :golang1.22:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT 97 | ./gradlew :golang1.23:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=nightly 98 | ./gradlew :golang1.23:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT 99 | - name: Push Release Images 100 | if: ${{ env.PUSH_RELEASE == 'true' }} 101 | working-directory: runtime 102 | run: | 103 | RUNTIME_VERSION=${GITHUB_REF_NAME%@*} 104 | IMAGE_TAG=${GITHUB_REF_NAME##*@} 105 | if [[ ${RUNTIME_VERSION} =~ 1\.[0-9]+ ]]; then 106 | RUNTIME="golang$RUNTIME_VERSION" 107 | elif [ ${RUNTIME_VERSION} == "actionloop" ]; then 108 | RUNTIME="actionloop" 109 | fi 110 | ./gradlew $RUNTIME:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$IMAGE_TAG 111 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac 2 | .DS_Store 3 | 4 | # goenv 5 | .go-version 6 | 7 | # Gradle 8 | .gradle/ 9 | .gogradle/ 10 | *.log 11 | tests/build/ 12 | test.out 13 | 14 | # Dependencies 15 | vendor/ 16 | 17 | # Go binary proxy 18 | common/proxy 19 | actionloop/proxy 20 | golang1.20/proxy 21 | golang1.21/proxy 22 | golang1.22/proxy 23 | golang1.23/proxy 24 | 25 | # Go test transient files 26 | openwhisk/_test/exec 27 | openwhisk/_test/exec.go 28 | openwhisk/_test/hi 29 | openwhisk/_test/hello_greeting 30 | openwhisk/_test/hello_message 31 | openwhisk/_test/*.zip 32 | openwhisk/_test/*.jar 33 | openwhisk/_test/compile/ 34 | openwhisk/_test/output/ 35 | openwhisk/_test/venv/ 36 | openwhisk/action/ 37 | openwhisk/compile/ 38 | openwhisk/debug.test 39 | *.pyc 40 | *.env 41 | 42 | # Eclipse 43 | tests/bin/ 44 | **/.project 45 | .settings/ 46 | .classpath 47 | .cache-main 48 | .cache-tests 49 | 50 | # IntelliJ 51 | .idea 52 | *.class 53 | *.iml 54 | tests/out/ 55 | 56 | # VSCode 57 | .vscode 58 | 59 | # examples 60 | exec 61 | *.done 62 | *.zip 63 | *_launcher_.go 64 | test.json 65 | pkg/ 66 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | 19 | # 1.25.0 20 | - Remove obsolete buster-backports repository from build. (#199) 21 | - Add support for golang 1.23 (#201) 22 | - Drop support for golang 1.20 (#202) 23 | 24 | # 1.24.0 25 | - Add support for golang 1.22 (#195) 26 | - Drop support for golang 1.19 (#197) 27 | 28 | # 1.23.0 29 | - Add support for golang 1.21 (#193) 30 | 31 | # 1.22.0 32 | - Add tar.gz support to the go Proxy (#191) 33 | - Update net Package as temporary vulnerability fix (#190) 34 | - Update minimum version to 1.19; go mod tidy (#188) 35 | 36 | # 1.21.0 37 | - Add support for go 1.20 (#184) 38 | - Add support for go 1.19 (#175) 39 | - Drop support for go 1.17 and 1.18 (#186) 40 | 41 | # 1.20.0 42 | - Support array result include sequence action (#170) 43 | - Upgrade to Gradle 6 (#172) 44 | - Drop support for go 1.16 (#169) 45 | 46 | # 1.19.0 47 | - Add support for go 1.18 and go 1.17 48 | - Drop support for go 1.13 and go 1.15 49 | - Add Zip support for the runtimes (#164) 50 | - Golang compilescript works with both Python 3 and Python 2 (#160) 51 | 52 | # 1.18.0 53 | - Added support for go 1.16 (#149) 54 | - Updated go 1.15 runtime to 1.15.14 55 | - Added aws example and use actionloop-base for bash example (#152) 56 | - Extend `proxy -version` to also show the go runtime version. (#150) 57 | - Support for zipping and unzipping symbolic links (required to support virtualenvs) (#148) 58 | - Resolve akka versions explicitly. (#147) 59 | 60 | # 1.17.0 61 | - go 1.15 runtime upgraded to 1.15.7 62 | - go 1.13 runtime upgraded to 1.13.15 63 | - add 'apt-get upgrade' to the image build of go 1.15 and go 1.13 to get latest security fixes during each build, for the case the base images are not updated frequently 64 | 65 | # 1.16.0 66 | - added go 1.13 and 1.15 with Go modules 67 | - removed support for go1.11 and go1.12 68 | - updated examples 69 | - add 'apt-get upgrade' to the image build to get latest security fixes during each build, for the case the base images are not updated frequently 70 | - added OW_WAIT_FOR_ACK such at if true, the proxy waits for an acknowledgement from the action on startup 71 | - added OW_EXECUTION_ENV to validate the execution environment before starting an action 72 | - write compilation logs to standard out 73 | # 1.15.0 74 | - added OW_ACTION_VERSION to action environment (PR#113) 75 | - propagate API_HOST from parent to child process (PR#115) 76 | 77 | # 1.14.0 78 | - Removed the -incubation 79 | - Now all runtimes use source release so no more actionloop-v2, renamed to actionloop-base 80 | - upgraded to go 1.12.9 and 1.11.13 81 | 82 | # Actionloop v2 83 | Versioning 84 | - renamed actionloop docker image to actionloop-v2 85 | Docker Images Support 86 | - static build of the executable docker image, so actionloop can be used also in alpine images 87 | ActionLoop for Scripting Languages 88 | - any script starting with '#!' is recognized as executable 89 | - now the -compile will zip the entire directory of the `bin` directory after compilation 90 | - if you upload a folder `src/exec` the entire directory is moved to `bin`, including other uploaded files 91 | - Support for Go 1.12.4 92 | - Support for jar not expanded for Java when set OW_SAVE_JAR 93 | - You can initialize multiple times when debugging 94 | - Removed gogradle plugin, now building directly with go 95 | 96 | # ActionLoop v1.0.1 97 | - embedded file type detection 98 | - now showing the commend 99 | - librdkafka in golang image 100 | - showing version number with -debug 101 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 19 | 20 | # Contributing to Apache OpenWhisk 21 | 22 | Anyone can contribute to the OpenWhisk project and we welcome your contributions. 23 | 24 | There are multiple ways to contribute: report bugs, improve the docs, and 25 | contribute code, but you must follow these prerequisites and guidelines: 26 | 27 | - [Contributor License Agreement](#contributor-license-agreement) 28 | - [Raising issues](#raising-issues) 29 | - [Coding Standards](#coding-standards) 30 | 31 | ### Contributor License Agreement 32 | 33 | All contributors must sign and submit an Apache CLA (Contributor License Agreement). 34 | 35 | Instructions on how to do this can be found here: 36 | [http://www.apache.org/licenses/#clas](http://www.apache.org/licenses/#clas) 37 | 38 | Once submitted, you will receive a confirmation email from the Apache Software Foundation (ASF) and be added to 39 | the following list: http://people.apache.org/unlistedclas.html. 40 | 41 | Project committers will use this list to verify pull requests (PRs) come from contributors that have signed a CLA. 42 | 43 | We look forward to your contributions! 44 | 45 | ## Raising issues 46 | 47 | Please raise any bug reports or enhancement requests on the respective project repository's GitHub issue tracker. Be sure to search the 48 | list to see if your issue has already been raised. 49 | 50 | A good bug report is one that make it easy for us to understand what you were trying to do and what went wrong. 51 | Provide as much context as possible so we can try to recreate the issue. 52 | 53 | A good enhancement request comes with an explanation of what you are trying to do and how that enhancement would help you. 54 | 55 | ### Discussion 56 | 57 | Please use the project's developer email list to engage our community: 58 | [dev@openwhisk.apache.org](dev@openwhisk.apache.org) 59 | 60 | In addition, we provide a "dev" Slack team channel for conversations at: 61 | https://openwhisk-team.slack.com/messages/dev/ 62 | 63 | ### Coding standards 64 | 65 | Please ensure you follow the coding standards used throughout the existing 66 | code base. Some basic rules include: 67 | 68 | - all files must have the Apache license in the header. 69 | - all PRs must have passing builds for all operating systems. 70 | - the code is correctly formatted as defined in the [Scalariform plugin properties](tools/eclipse/scala.properties). If you use IntelliJ for development this [page](https://plugins.jetbrains.com/plugin/7480-scalariform) describes the setup and configuration of the plugin. 71 | -------------------------------------------------------------------------------- /CREDITS.txt: -------------------------------------------------------------------------------- 1 | Michele Sciabarra 2 | 3 | Carlos Santana 4 | 5 | Rodric Rabbah 6 | 7 | James Thomas 8 | -------------------------------------------------------------------------------- /LICENSE-testify.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell 2 | 3 | Please consider promoting this project if you find it useful. 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of the Software, 10 | and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 21 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 22 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | Apache OpenWhisk Runtime Go 2 | Copyright 2016-2024 The Apache Software Foundation 3 | 4 | This product includes software developed at 5 | The Apache Software Foundation (http://www.apache.org/). 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 19 | # Apache OpenWhisk Runtimes for Go 20 | 21 | [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0) 22 | [![Continuous Integration](https://github.com/apache/openwhisk-runtime-go/actions/workflows/ci.yaml/badge.svg)](https://github.com/apache/openwhisk-runtime-go/actions/workflows/ci.yaml) 23 | [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/) 24 | 25 | This repository contains both the OpenWhisk runtime for Golang Actions, as well as a runtime for Generic executables. 26 | 27 | - If you are in a hurry, check the [examples](examples/EXAMPLES.md) 28 | - Writing Actions for the runtime in [Golang](docs/ACTION.md#golang) 29 | - How to deploy your [Golang](docs/DEPLOY.md#golang) sources 30 | - Precompiling [Golang](docs/DEPLOY.md#precompile) actions 31 | - How to use VSCode to write [Golang](docs/DEPLOY.md#vscode) actions 32 | - How to [Build](docs/BUILD.md#building) the runtime, with development notes 33 | 34 | ## Actionloop runtime 35 | 36 | ### Using the Go runtime for Generic executables 37 | 38 | - Writing [Generic](docs/ACTION.md#generic) actions, in bash or as a generic linux binary 39 | - Deployment for [Generic](docs/DEPLOY.md#generic) actions 40 | - The [ActionLoop](docs/ACTION.md#actionloop) protocol for generic actions 41 | - Environment [Variables](docs/ENVVARS.md) to configure the proxy 42 | 43 | # Change Log 44 | 45 | [CHANGES.md](CHANGES.md) 46 | 47 | # License 48 | [Apache 2.0](LICENSE.txt) 49 | -------------------------------------------------------------------------------- /actionloop/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | FROM ubuntu:xenial 18 | RUN apt-get update && apt-get install -y \ 19 | curl \ 20 | jq \ 21 | zsh \ 22 | && rm -rf /var/lib/apt/lists/* 23 | RUN mkdir /action 24 | WORKDIR /action 25 | ADD proxy /bin/proxy 26 | ENTRYPOINT [ "/bin/proxy" ] 27 | -------------------------------------------------------------------------------- /actionloop/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | ext.dockerImageName = 'actionloop-base' 19 | apply from: '../gradle/docker.gradle' 20 | 21 | distDocker.dependsOn 'staticBuildProxy' 22 | distDocker.finalizedBy('cleanup') 23 | 24 | task staticBuildProxy(type: Exec) { 25 | environment CGO_ENABLED: "0" 26 | environment GOOS: "linux" 27 | environment GOARCH: "amd64" 28 | environment GO111MODULE: "on" 29 | 30 | commandLine 'go', 'build', 31 | '-o', 'proxy', '-a', 32 | '-ldflags', '-extldflags "-static"', 33 | '../main/proxy.go' 34 | } 35 | 36 | task cleanup(type: Delete) { 37 | delete 'proxy' 38 | delete 'gobuild.py' 39 | delete 'gobuild.py.launcher.go' 40 | } 41 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | buildscript { 19 | repositories { 20 | mavenCentral() 21 | gradlePluginPortal() 22 | } 23 | dependencies { 24 | classpath "gradle.plugin.cz.alenkacz:gradle-scalafmt:${gradle.scalafmt.version}" 25 | } 26 | } 27 | 28 | subprojects { 29 | apply plugin: 'scalafmt' 30 | scalafmt.configFilePath = gradle.scalafmt.config 31 | } 32 | 33 | -------------------------------------------------------------------------------- /common/gobuild.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """Golang Action Compiler 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one or more 5 | # contributor license agreements. See the NOTICE file distributed with 6 | # this work for additional information regarding copyright ownership. 7 | # The ASF licenses this file to You under the Apache License, Version 2.0 8 | # (the "License"); you may not use this file except in compliance with 9 | # the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | """ 20 | 21 | import os 22 | import re 23 | import sys 24 | import codecs 25 | import subprocess 26 | 27 | def sources(launcher, source_dir, main): 28 | 29 | func = main.capitalize() 30 | has_main = None 31 | 32 | # copy the exec to exec.go 33 | # also check if it has a main in it 34 | src = "%s/exec" % source_dir 35 | dst = "%s/exec__.go" % source_dir 36 | if os.path.isfile(src): 37 | with codecs.open(src, 'r', 'utf-8') as s: 38 | with codecs.open(dst, 'w', 'utf-8') as d: 39 | body = s.read() 40 | has_main = re.match(r".*package\s+main\W.*func\s+main\s*\(\s*\)", body, flags=re.DOTALL) 41 | d.write(body) 42 | 43 | # copy the launcher fixing the main 44 | if not has_main: 45 | dst = "%s/main__.go" % source_dir 46 | if os.path.isdir("%s/main" % source_dir): 47 | dst = "%s/main/main__.go" % source_dir 48 | with codecs.open(dst, 'w', 'utf-8') as d: 49 | with codecs.open(launcher, 'r', 'utf-8') as e: 50 | code = e.read() 51 | code = code.replace("Main", func) 52 | d.write(code) 53 | 54 | def build(parent, source_dir, target): 55 | # compile... 56 | env = { 57 | "PATH": os.environ["PATH"], 58 | "GOPATH": os.path.abspath(parent), 59 | "GOCACHE": "/tmp", 60 | "GO111MODULE": "off" 61 | } 62 | if os.path.isdir("%s/main" % source_dir): 63 | source_dir += "/main" 64 | p = subprocess.Popen( 65 | ["go", "build", "-ldflags=-s -w", "-o", target], 66 | stdout=subprocess.PIPE, 67 | stderr=subprocess.PIPE, 68 | cwd=source_dir, 69 | env=env) 70 | (o, e) = p.communicate() 71 | 72 | # stdout/stderr may be either text or bytes, depending on Python 73 | # version, so if bytes, decode to text. Note that in Python 2 74 | # a string will match both types; so also skip decoding in that case 75 | if isinstance(o, bytes) and not isinstance(o, str): 76 | o = o.decode('utf-8') 77 | if isinstance(e, bytes) and not isinstance(e, str): 78 | e = e.decode('utf-8') 79 | 80 | # remove the comments mentioning the folder in order to normalize output 81 | o = re.sub(r"# .*\n", "", o, flags=re.MULTILINE) 82 | e = re.sub(r"# .*\n", "", e, flags=re.MULTILINE) 83 | 84 | if o: 85 | sys.stdout.write(o) 86 | sys.stdout.flush() 87 | 88 | if e: 89 | sys.stderr.write(e) 90 | sys.stderr.flush() 91 | 92 | def main(argv): 93 | if len(argv) < 4: 94 | print("usage: ") 95 | sys.exit(1) 96 | 97 | main = argv[1] 98 | source_dir = argv[2] 99 | target_dir = argv[3] 100 | 101 | parent = os.path.dirname(os.path.abspath(source_dir)) 102 | target = os.path.abspath("%s/exec" % target_dir) 103 | 104 | sources(argv[0]+".launcher.go", source_dir, main) 105 | build(parent, source_dir, target) 106 | 107 | if __name__ == '__main__': 108 | main(sys.argv) 109 | -------------------------------------------------------------------------------- /common/gobuild.py.launcher.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "bufio" 22 | "bytes" 23 | "encoding/json" 24 | "fmt" 25 | "io" 26 | "log" 27 | "os" 28 | "reflect" 29 | "strings" 30 | ) 31 | 32 | func main() { 33 | // debugging 34 | var debug = os.Getenv("OW_DEBUG") != "" 35 | 36 | if debug { 37 | filename := os.Getenv("OW_DEBUG") 38 | f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 39 | if err == nil { 40 | log.SetOutput(f) 41 | defer f.Close() 42 | } 43 | log.Printf("ACTION ENV: %v", os.Environ()) 44 | } 45 | 46 | resultKind := reflect.TypeOf(Main).Out(0).Kind() 47 | if resultKind != reflect.Map && resultKind != reflect.Slice && resultKind != reflect.Array { 48 | fmt.Println("Support map and slice and array only") 49 | os.Exit(1) 50 | } 51 | 52 | // input 53 | out := os.NewFile(3, "pipe") 54 | defer out.Close() 55 | reader := bufio.NewReader(os.Stdin) 56 | 57 | // read-eval-print loop 58 | if debug { 59 | log.Println("started") 60 | } 61 | for { 62 | // read one line 63 | inbuf, err := reader.ReadBytes('\n') 64 | if err != nil { 65 | if err != io.EOF { 66 | log.Println(err) 67 | } 68 | break 69 | } 70 | if debug { 71 | log.Printf(">>>'%s'>>>", inbuf) 72 | } 73 | // parse one line 74 | var input map[string]interface{} 75 | err = json.Unmarshal(inbuf, &input) 76 | if err != nil { 77 | log.Println(err.Error()) 78 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 79 | continue 80 | } 81 | if debug { 82 | log.Printf("%v\n", input) 83 | } 84 | // set environment variables 85 | for k, v := range input { 86 | if k == "value" { 87 | continue 88 | } 89 | if s, ok := v.(string); ok { 90 | os.Setenv("__OW_"+strings.ToUpper(k), s) 91 | } 92 | } 93 | // get payload if not empty 94 | isJsonObjectParam := true 95 | var payloadForJsonObject map[string]interface{} 96 | var payloadForJsonArray []interface{} 97 | if value, ok := input["value"].(map[string]interface{}); ok { 98 | payloadForJsonObject = value 99 | } else { 100 | if value, ok := input["value"].([]interface{}); ok { 101 | payloadForJsonArray = value 102 | isJsonObjectParam = false 103 | } 104 | } 105 | // process the request 106 | var result interface{} 107 | funcMain := reflect.ValueOf(Main) 108 | if isJsonObjectParam { 109 | param := []reflect.Value{reflect.ValueOf(payloadForJsonObject)} 110 | reflectResult := funcMain.Call(param) 111 | result = reflectResult[0].Interface() 112 | } else { 113 | param := []reflect.Value{reflect.ValueOf(payloadForJsonArray)} 114 | reflectResult := funcMain.Call(param) 115 | result = reflectResult[0].Interface() 116 | } 117 | // encode the answer 118 | output, err := json.Marshal(&result) 119 | if err != nil { 120 | log.Println(err.Error()) 121 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 122 | continue 123 | } 124 | output = bytes.Replace(output, []byte("\n"), []byte(""), -1) 125 | if debug { 126 | log.Printf("'<<<%s'<<<", output) 127 | } 128 | fmt.Fprintf(out, "%s\n", output) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /docs/BUILD.md: -------------------------------------------------------------------------------- 1 | 19 | # Developers Guide for Runtime itself 20 | 21 | 22 | 23 | ## How to Build and run tests 24 | 25 | You need a Linux or an OSX environment, with Java and Docker installed to build the sources. 26 | 27 | Prerequisites for running build and tests with gradle: 28 | 29 | - docker 30 | - jdk 31 | 32 | To compile go proxy *in amd64 architecture* for docker: 33 | 34 | ``` 35 | ./gradlew build 36 | ``` 37 | 38 | To build the docker images, after compiling go proxy: 39 | 40 | ``` 41 | ./gradlew distDocker 42 | ``` 43 | 44 | This will build the images: 45 | 46 | * `action-golang-v1.21`: an image supporting Go 1.21 sources (does expect an ack) 47 | * `action-golang-v1.22`: an image supporting Go 1.22 sources (does expect an ack) 48 | * `action-golang-v1.23`: an image supporting Go 1.23 sources (does expect an ack) 49 | * `actionloop-base`: the base image, supporting generic executables ans shell script (does not expect an ack) 50 | 51 | The `actionloop-base` image can be used for supporting other compiled programming languages as long as they implement a `compile` script and the *action loop* protocol described below. Please check [ENVVARS.md](ENVVARS.md) for configuration options 52 | 53 | To run tests: 54 | 55 | ``` 56 | ./gradlew test --info 57 | ``` 58 | 59 | 60 | # Local Development 61 | 62 | If you want to develop the proxy and run tests natively, you can do it on Linux or OSX. Development has been tested on Ubuntu Linux (14.04) and OSX 10.13. Probably other distributions work, maybe even Windows with WSL, but since it is not tested YMMMV. 63 | 64 | You need to install, of course [go 1.14.x](https://golang.org/doc/install) 65 | 66 | Then you need a set of utilities used in tests: 67 | 68 | - bc 69 | - zip 70 | 71 | Linux: `apt-get install bc zip` 72 | OSX: `brew install zip` 73 | 74 | **NOTE**: Because tests build and cache some binary files, perform a `git clean -fx` and **do not share folders between linux and osx** because binaries are in different format... 75 | 76 | You can also run the tests in go, without using `gradle` with 77 | 78 | ``` 79 | cd openwhisk 80 | go test 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/DEPLOY.md: -------------------------------------------------------------------------------- 1 | 19 | 20 | # Deployment options 21 | 22 | There are a few images provided: the `actionloop-base` and the `action-golang-v1.` are available. Each image accepts different input in the deployment. 23 | 24 | 25 | 26 | ## Actionloop runtime 27 | 28 | The runtime `actionlooop-base` accepts: 29 | 30 | - single file executable 31 | - a zip file containing an executables 32 | 33 | If the input is a single file, it can be either a in ELF format for architecture AMD64 implementing the ActionLoop protocol. 34 | 35 | It can also be a script, identified by the `#!` hash-bang path at the beginning. The default `actionloop-base` can execute `bash` shell scripts and can use the `jq` command to parse JSON files and the `curl` command to invoke other actions. 36 | 37 | If the file is a zipped file, it must contain in the top level (*not* in a subdirectory) an file named `exec`. This file must be in the same format as a single binary, either a binary or a script. 38 | 39 | 40 | 41 | ## Golang runtime 42 | 43 | The runtime `action-golang-v1.N` accepts: 44 | 45 | - executable binaries implementing the ActionLoop protocol as Linux ELF executable compiled for the AMD64 architecture (as the `actionloop-base` runtime) 46 | - zip files containing a binary executable named `exec` in the top level, and it must be again a Linux ELF executable compiled for the AMD64 architecture 47 | - a single file action that is not an executable binary will be interpreted as source code and it will be compiled in a binary as described in the document about [actions](ACTION.md) 48 | - a zip file not containing in the top level a binary file `exec` will be interpreted as a collection of zip files, and it will be compiled in a binary as described in the document about [actions](ACTION.md) 49 | 50 | Please note in the separate the rules about the name of the main function (that defaults to `main.Main`), and the rules about how to overwrite the `main.main`. 51 | 52 | ## Using packages and modules 53 | 54 | When you deploy a zip file, you can: 55 | 56 | - have all your functions in the `main` package 57 | - have some functions placed in some packages, like `hello` 58 | - have some third party dependencies you want to include in your sources 59 | 60 | You can manage those dependencies using appropriate `go.mod` files using relative and absolute references. 61 | 62 | For example you can use a local package `hello` with: 63 | 64 | ``` 65 | replace hello => ./hello 66 | ``` 67 | 68 | Check the example: `package-main` and `module-main` and look for the format of the `go.mod` files. 69 | 70 | 71 | 72 | ## Precompiling Go Sources Offline 73 | 74 | Compiling sources on the image can take some time when the images is initialized. You can speed up precompiling the sources using the image `action-golang-v1.N` as an offline compiler. You need `docker` for doing that. 75 | 76 | The images accepts a `-compile
` flag, and expects you provide sources in standard input. It will then compile them, emit the binary in standard output and errors in stderr. The output is always a zip file containing an executable. 77 | 78 | If you have docker, you can do it this way: 79 | 80 | If you have a single source maybe in file `main.go`, with a function named `Main` just do this: 81 | 82 | `docker run openwhisk/action-golang-v1.N -compile main main.zip` 83 | 84 | If you have multiple sources in current directory, even with a subfolder with sources, you can compile it all with: 85 | 86 | `zip -r - * | docker run openwhisk/action-golang-v1.N -compile main >main.zip` 87 | 88 | You can then execute the code. Note you have to use the same runtime you used to build the image. 89 | 90 | Note that the output is always a zip file in Linux AMD64 format so the executable can be run only inside a Docker Linux container. 91 | -------------------------------------------------------------------------------- /docs/ENVVARS.md: -------------------------------------------------------------------------------- 1 | 19 | 20 | # Environment Variables 21 | 22 | ## Environment variables that control the behavior of the proxy 23 | 24 | The following variables are usually set in the Dockerfile 25 | 26 | `OW_COMPILER` points to the compiler script to use to compile actions. 27 | 28 | `OW_SAVE_JAR` enables checking that an uploaded file is a jar (that is itself a zip file) and it will not expand it if there is a subdirectory named "META-INF" (so it is a jar file). Used to support uploading of Java jars. 29 | 30 | `OW_WAIT_FOR_ACK` enables waiting for an acknowledgment in the action loop protocol. It should be enabled in all the newer runtimes. Do not enable in existing runtimes as it would break existing actions built for that runtime. 31 | 32 | `OW_EXECUTION_ENV` enables detection and verification of the compilation environment. The compiler is expected to create a file named `exec.env` in the same folder as the `exec` file to be run. If this variable is set, before starting an action, the initialization will check that the content of the `exec.env`, trimmed of spaces and new lines, is the same, to ensure an action is executed in the right execution environment. 33 | 34 | `OW_LOG_INIT_ERROR` enables logging of compilation error; the default behavior is to return errors in the result from initialization. 35 | 36 | ## Environment variables propagated to actions and to the compilation script 37 | 38 | The proxy itself sets the following environment variables: 39 | 40 | `__OW_EXECUTION_ENV` is the same value that the proxy receives as `OW_EXECUTION_ENV` 41 | 42 | `__OW_WAIT_FOR_ACK` is set if the proxy has the variable `OW_WAIT_FOR_ACK` set. 43 | 44 | Any other environment variables set in the Dockerfile that start with `__OW_` are propagated to the proxy and can override the values set by the proxy. 45 | 46 | Furthermore, actions receive their own environment variables and such values override the variables set from the proxy and in the environment. 47 | -------------------------------------------------------------------------------- /examples/EXAMPLES.md: -------------------------------------------------------------------------------- 1 | 19 | # Examples 20 | 21 | 22 | This is a collection of examples. 23 | Tested on: 24 | 25 | - Go version 1.14.6 26 | - GNU Make 3.81 27 | - Linux Ubuntu 18.04 28 | - Mac OSX 10.15.6 29 | - Windows 10 with WSL 2 30 | 31 | Each examples has a Makefile with 4 targets: 32 | 33 | - `make deploy` (or just make) deploys the action, precompiling it 34 | - `make devel` deploys the action in source format, leaving the compilation to the runtime 35 | - `make test` runs a simple test on the action; it should be already deployed 36 | - `clean` removes intermediate files 37 | 38 | Available examples: 39 | 40 | - [Simple Golang action](single-main) main is `main.Main` 41 | - [Simple Golang action](single-hello) main is `main.Hello` 42 | - [Golang action with a package](package-main) main is `main.Main` invoking a `hello.Hello` and a test 43 | - [Golang action with a module](module-main) main is `main.Main` using a dependency `github.com/rs/zerolog` 44 | - [Standalone Golang Action](standalone) implements the ActionLoop directly in go 45 | - [Simple Bash action](bash) action implementing the ActionLoop directly 46 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # prefix 19 | OW_USER?=openwhisk 20 | OW_VER?=v1.16:nightly 21 | 22 | .PHONY: test 23 | test: all 24 | cat */test.out | grep 'Hello' | sort >test.out 25 | diff test.out test.expected 26 | 27 | .PHONY: all 28 | all: bash standalone single-main single-hello package-main module-main 29 | 30 | .PHONY: bash 31 | bash: 32 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean deploy test 33 | 34 | .PHONY: standalone 35 | standalone: 36 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean devel test 37 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean deploy test 38 | 39 | .PHONY: single-main 40 | single-main: 41 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean devel test 42 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean deploy test 43 | 44 | .PHONY: single-hello 45 | single-hello: 46 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean devel test 47 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean deploy test 48 | 49 | .PHONY: package-main 50 | package-main: 51 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean devel test 52 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean deploy test 53 | 54 | .PHONY: module-main 55 | module-main: 56 | # this exceeds 3 seconds for initialization 57 | #cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean devel test 58 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean deploy test 59 | 60 | .PHONY: aws-main 61 | aws-main: 62 | # this exceeds 3 seconds for initialization 63 | #cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean devel test 64 | cd $@ && OW_USER=$(OW_USER) OW_VER=$(OW_VER) make clean deploy test 65 | -------------------------------------------------------------------------------- /examples/aws-main/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | OW_USER?=openwhisk 19 | OW_VER?=v1.16:nightly 20 | OW_RUNTIME?=$(OW_USER)/action-golang-$(OW_VER) 21 | OW_COMPILER?=$(OW_USER)/action-golang-$(OW_VER) 22 | WSK?=wsk 23 | MAIN=main 24 | PACKAGE=test 25 | SRCS=main.go go.mod go.sum 26 | NAME=aws-main 27 | BINZIP=$(MAIN)-bin.zip 28 | SRCZIP=$(MAIN)-src.zip 29 | 30 | deploy: package.done $(BINZIP) 31 | $(WSK) action update $(PACKAGE)/$(NAME) $(BINZIP) --main $(MAIN) --docker $(OW_RUNTIME) 32 | 33 | devel: package.done $(SRCZIP) 34 | $(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_COMPILER) 35 | 36 | $(BINZIP): $(SRCS) $(VENDORS) $(SRCZIP) 37 | docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRCZIP) >$(BINZIP) 38 | 39 | $(SRCZIP): $(SRCS) 40 | zip $@ -qr $^ 41 | 42 | clean: 43 | -$(WSK) action delete $(PACKAGE)/$(NAME) 44 | -rm $(BINZIP) $(SRCZIP) package.done test.json 45 | -rm test.out 46 | 47 | test: test.json 48 | $(WSK) action invoke test/$(NAME) -r | tee -a test.out 49 | $(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out 50 | 51 | test.json: 52 | echo '{}' >test.json 53 | 54 | package.done: 55 | $(WSK) package update $(PACKAGE) 56 | touch package.done 57 | 58 | .PHONY: deploy devel test clean 59 | -------------------------------------------------------------------------------- /examples/aws-main/go.mod: -------------------------------------------------------------------------------- 1 | module action 2 | 3 | go 1.16 4 | 5 | require github.com/aws/aws-sdk-go v1.40.8 6 | -------------------------------------------------------------------------------- /examples/aws-main/go.sum: -------------------------------------------------------------------------------- 1 | github.com/aws/aws-sdk-go v1.40.8 h1:LBeBOKdgxaR1tknlENTBhcN8CjutpofbMJPtl/6Yug4= 2 | github.com/aws/aws-sdk-go v1.40.8/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 5 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 6 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 7 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 11 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 12 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 13 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 14 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 15 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 16 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 17 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 18 | -------------------------------------------------------------------------------- /examples/aws-main/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package main 18 | 19 | import ( 20 | "github.com/aws/aws-sdk-go/aws" 21 | "github.com/aws/aws-sdk-go/aws/credentials" 22 | "github.com/aws/aws-sdk-go/aws/session" 23 | "github.com/aws/aws-sdk-go/service/ec2" 24 | ) 25 | 26 | // Main function for the action 27 | func Main(obj map[string]interface{}) map[string]interface{} { 28 | msg := make(map[string]interface{}) 29 | 30 | id, ok1 := obj["id"].(string) 31 | key, ok2 := obj["key"].(string) 32 | region, ok3 := obj["region"].(string) 33 | if ok1 && ok2 && ok3 { 34 | sess := session.Must(session.NewSession(&aws.Config{ 35 | Region: aws.String(region), 36 | Credentials: credentials.NewStaticCredentials(id, key, ""), 37 | })) 38 | service := ec2.New(sess) 39 | res, err := service.DescribeInstances(&ec2.DescribeInstancesInput{}) 40 | if err != nil { 41 | msg["error"] = err.Error() 42 | } else { 43 | instances := []string{} 44 | for _, resv := range res.Reservations { 45 | for _, inst := range resv.Instances { 46 | instances = append(instances, *inst.InstanceId) 47 | } 48 | } 49 | msg["instances"] = instances 50 | } 51 | } else { 52 | msg["help"] = "required id, key and region" 53 | } 54 | return msg 55 | } 56 | -------------------------------------------------------------------------------- /examples/bash/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | WSK?=wsk 18 | OW_USER?=openwhisk 19 | OW_RUNTIME?=$(OW_USER)/actionloop-base:nightly 20 | NAME=bash 21 | PACKAGE=test 22 | SRC=hello.sh 23 | 24 | deploy: package.done 25 | $(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --docker $(OW_RUNTIME) 26 | 27 | devel: deploy 28 | 29 | test: test.json 30 | $(WSK) action invoke $(PACKAGE)/$(NAME) -r | tee -a test.out 31 | $(WSK) action invoke $(PACKAGE)/$(NAME) -P test.json -r | tee -a test.out 32 | 33 | clean: 34 | -$(WSK) action delete $(PACKAGE)/$(NAME) 35 | -rm package.done test.json 36 | -rm test.out 37 | 38 | package.done: 39 | $(WSK) package update $(PACKAGE) 40 | touch package.done 41 | 42 | test.json: 43 | echo '{ "name": "Mike" }' >test.json 44 | 45 | .PHONY: test devel deploy clean 46 | -------------------------------------------------------------------------------- /examples/bash/hello.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # NOTE by default actionloop classic does not use an ack 19 | # if enabled with OW_REQUIRES_ACK you need 20 | # echo '{"ok": true}' 21 | while read line 22 | do 23 | name="$(echo $line | jq -r .value.name)" 24 | test "$name" == "null" && name="world" 25 | echo msg="hello $name" 26 | echo '{"bash": "Hello, '$name'"}' >&3 27 | done 28 | -------------------------------------------------------------------------------- /examples/module-main/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | OW_USER?=openwhisk 19 | OW_VER?=v1.16:nightly 20 | OW_RUNTIME?=$(OW_USER)/action-golang-$(OW_VER) 21 | OW_COMPILER?=$(OW_USER)/action-golang-$(OW_VER) 22 | WSK?=wsk 23 | MAIN=main 24 | PACKAGE=test 25 | SRCS=main.go go.mod go.sum 26 | NAME=module-main 27 | BINZIP=$(MAIN)-bin.zip 28 | SRCZIP=$(MAIN)-src.zip 29 | 30 | deploy: package.done $(BINZIP) 31 | $(WSK) action update $(PACKAGE)/$(NAME) $(BINZIP) --main $(MAIN) --docker $(OW_RUNTIME) 32 | 33 | devel: package.done $(SRCZIP) 34 | $(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_COMPILER) 35 | 36 | $(BINZIP): $(SRCS) $(VENDORS) $(SRCZIP) 37 | docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRCZIP) >$(BINZIP) 38 | 39 | $(SRCZIP): $(SRCS) 40 | zip $@ -qr $^ 41 | 42 | clean: 43 | -$(WSK) action delete $(PACKAGE)/$(NAME) 44 | -rm $(BINZIP) $(SRCZIP) package.done test.json 45 | -rm test.out 46 | 47 | test: test.json 48 | $(WSK) action invoke test/$(NAME) -r | tee -a test.out 49 | $(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out 50 | 51 | test.json: 52 | echo '{ "name": "Mike" }' >test.json 53 | 54 | package.done: 55 | $(WSK) package update $(PACKAGE) 56 | touch package.done 57 | 58 | .PHONY: deploy devel test clean 59 | -------------------------------------------------------------------------------- /examples/module-main/go.mod: -------------------------------------------------------------------------------- 1 | module action 2 | 3 | go 1.20 4 | 5 | require github.com/rs/zerolog v1.19.0 6 | -------------------------------------------------------------------------------- /examples/module-main/go.sum: -------------------------------------------------------------------------------- 1 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 2 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 3 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 4 | github.com/rs/zerolog v1.19.0 h1:hYz4ZVdUgjXTBUmrkrw55j1nHx68LfOKIQk5IYtyScg= 5 | github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= 6 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 7 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 8 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 9 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 10 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 11 | golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 12 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 13 | -------------------------------------------------------------------------------- /examples/module-main/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package main 18 | 19 | import ( 20 | "github.com/rs/zerolog" 21 | "github.com/rs/zerolog/log" 22 | ) 23 | 24 | func init() { 25 | zerolog.TimeFieldFormat = "" 26 | } 27 | 28 | // Main function for the action 29 | func Main(obj map[string]interface{}) map[string]interface{} { 30 | name, ok := obj["name"].(string) 31 | if !ok { 32 | name = "world" 33 | } 34 | log.Debug().Str("name", name).Msg("Hello") 35 | msg := make(map[string]interface{}) 36 | msg["module-main"] = "Hello, " + name + "!" 37 | return msg 38 | } 39 | -------------------------------------------------------------------------------- /examples/package-main/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | OW_USER?=openwhisk 19 | OW_VER?=v1.16:nightly 20 | OW_RUNTIME?=$(OW_USER)/action-golang-$(OW_VER) 21 | OW_COMPILER?=$(OW_USER)/action-golang-$(OW_VER) 22 | WSK?=wsk 23 | MAIN=main 24 | PACKAGE=test 25 | SRCS=$(MAIN).go go.mod hello/hello.go hello/go.mod 26 | NAME=package-main 27 | BINZIP=$(MAIN)-bin.zip 28 | SRCZIP=$(MAIN)-src.zip 29 | 30 | deploy: package.done $(BINZIP) 31 | $(WSK) action update $(PACKAGE)/$(NAME) $(BINZIP) --main $(MAIN) --docker $(OW_RUNTIME) 32 | 33 | devel: package.done $(SRCZIP) 34 | $(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_COMPILER) 35 | 36 | $(BINZIP): $(SRCS) 37 | zip - -qr $(SRCS) | docker run -i $(OW_COMPILER) -compile $(MAIN) >$(BINZIP) 38 | 39 | $(SRCZIP): $(SRCS) 40 | zip $@ -r $^ 41 | 42 | clean: 43 | -$(WSK) action delete $(PACKAGE)/$(NAME) 44 | -rm $(BINZIP) $(SRCZIP) package.done test.json 2>/dev/null 45 | -rm test.out 46 | 47 | test: test.json 48 | $(WSK) action invoke test/$(NAME) -r | tee -a test.out 49 | $(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out 50 | 51 | test.json: 52 | echo '{ "name": "Mike" }' >test.json 53 | 54 | package.done: 55 | $(WSK) package update $(PACKAGE) 56 | touch package.done 57 | 58 | .PHONY: deploy devel test clean 59 | -------------------------------------------------------------------------------- /examples/package-main/go.mod: -------------------------------------------------------------------------------- 1 | module action 2 | 3 | go 1.14 4 | 5 | replace hello => ./hello 6 | 7 | require hello v0.0.0-00010101000000-000000000000 8 | -------------------------------------------------------------------------------- /examples/package-main/hello/go.mod: -------------------------------------------------------------------------------- 1 | module hello 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /examples/package-main/hello/hello.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package hello 19 | 20 | import ( 21 | "fmt" 22 | ) 23 | 24 | // Hello receive an event in format 25 | // { "name": "Mike"} 26 | // and returns a greeting in format 27 | // { "greetings": "Hello, Mike"} 28 | func Hello(args map[string]interface{}) map[string]interface{} { 29 | res := make(map[string]interface{}) 30 | greetings := "world" 31 | name, ok := args["name"].(string) 32 | if ok { 33 | greetings = name 34 | } 35 | res["package-main"] = "Hello, " + greetings 36 | fmt.Printf("Hello, %s\n", greetings) 37 | return res 38 | } 39 | -------------------------------------------------------------------------------- /examples/package-main/hello/hello_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package hello 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | ) 23 | 24 | func ExampleHello() { 25 | var input = make(map[string]interface{}) 26 | input["name"] = "Mike" 27 | output := Hello(input) 28 | json, _ := json.Marshal(output) 29 | fmt.Printf("%s", json) 30 | // Output: 31 | // Hello, Mike 32 | // {"package-main":"Hello, Mike"} 33 | } 34 | 35 | func ExampleHello_noName() { 36 | var input = make(map[string]interface{}) 37 | output := Hello(input) 38 | json, _ := json.Marshal(output) 39 | fmt.Printf("%s", json) 40 | // Output: 41 | // Hello, world 42 | // {"golang-main-package":"Hello, world"} 43 | } 44 | -------------------------------------------------------------------------------- /examples/package-main/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "hello" 23 | ) 24 | 25 | // Main forwarding to Hello 26 | func Main(args map[string]interface{}) map[string]interface{} { 27 | fmt.Println("Main") 28 | return hello.Hello(args) 29 | } 30 | -------------------------------------------------------------------------------- /examples/single-hello/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | OW_USER?=openwhisk 19 | OW_VER?=v1.16:nightly 20 | OW_RUNTIME?=$(OW_USER)/action-golang-$(OW_VER) 21 | OW_COMPILER?=$(OW_USER)/action-golang-$(OW_VER) 22 | WSK?=wsk 23 | MAIN=hello 24 | PACKAGE=test 25 | SRC=$(MAIN).go 26 | NAME=single-hello 27 | ZIP=$(MAIN).zip 28 | 29 | deploy: package.done $(ZIP) 30 | $(WSK) action update $(PACKAGE)/$(NAME) $(ZIP) --main $(MAIN) --docker $(OW_RUNTIME) 31 | 32 | devel: package.done $(SRC) 33 | $(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --main $(MAIN) --docker $(OW_COMPILER) 34 | 35 | $(ZIP): $(SRC) 36 | docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRC) >$(ZIP) 37 | 38 | clean: 39 | -$(WSK) action delete $(PACKAGE)/$(NAME) 40 | -rm $(ZIP) package.done test.json 2>/dev/null 41 | -rm test.out 42 | 43 | test: test.json 44 | $(WSK) action invoke test/$(NAME) -r | tee -a test.out 45 | $(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out 46 | 47 | test.json: 48 | echo '{ "name": "Mike" }' >test.json 49 | 50 | package.done: 51 | $(WSK) package update $(PACKAGE) 52 | touch package.done 53 | 54 | .PHONY: deploy devel test clean 55 | -------------------------------------------------------------------------------- /examples/single-hello/hello.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package main 18 | 19 | import "fmt" 20 | 21 | // Hello function for the action 22 | func Hello(obj map[string]interface{}) map[string]interface{} { 23 | name, ok := obj["name"].(string) 24 | if !ok { 25 | name = "world" 26 | } 27 | fmt.Printf("name=%s\n", name) 28 | msg := make(map[string]interface{}) 29 | msg["single-hello"] = "Hello, " + name + "!" 30 | return msg 31 | } 32 | -------------------------------------------------------------------------------- /examples/single-main/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | OW_USER?=openwhisk 19 | OW_VER?=v1.16:nightly 20 | OW_RUNTIME?=$(OW_USER)/action-golang-$(OW_VER) 21 | OW_COMPILER?=$(OW_USER)/action-golang-$(OW_VER) 22 | WSK?=wsk 23 | MAIN=main 24 | PACKAGE=test 25 | SRC=$(MAIN).go 26 | NAME=single-main 27 | ZIP=$(MAIN).zip 28 | 29 | deploy: package.done $(ZIP) 30 | $(WSK) action update $(PACKAGE)/$(NAME) $(ZIP) --main $(MAIN) --docker $(OW_RUNTIME) 31 | 32 | devel: package.done $(SRC) 33 | $(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --main $(MAIN) --docker $(OW_COMPILER) 34 | 35 | $(ZIP): $(SRC) 36 | docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRC) >$(ZIP) 37 | 38 | clean: 39 | -$(WSK) action delete $(PACKAGE)/$(NAME) 40 | -rm $(ZIP) package.done test.json 2>/dev/null 41 | -rm test.out 42 | 43 | test: test.json 44 | $(WSK) action invoke test/$(NAME) -r | tee -a test.out 45 | $(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out 46 | 47 | test.json: 48 | echo '{ "name": "Mike" }' >test.json 49 | 50 | package.done: 51 | $(WSK) package update $(PACKAGE) 52 | touch package.done 53 | 54 | .PHONY: deploy devel test clean 55 | -------------------------------------------------------------------------------- /examples/single-main/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package main 18 | 19 | import "fmt" 20 | 21 | // Main function for the action 22 | func Main(obj map[string]interface{}) map[string]interface{} { 23 | name, ok := obj["name"].(string) 24 | if !ok { 25 | name = "world" 26 | } 27 | fmt.Printf("name=%s\n", name) 28 | msg := make(map[string]interface{}) 29 | msg["single-main"] = "Hello, " + name + "!" 30 | return msg 31 | } 32 | -------------------------------------------------------------------------------- /examples/standalone/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | OW_USER?=openwhisk 19 | OW_VER?=v1.16:nightly 20 | OW_RUNTIME?=$(OW_USER)/action-golang-$(OW_VER) 21 | OW_COMPILER?=$(OW_USER)/action-golang-$(OW_VER) 22 | WSK?=wsk 23 | MAIN=main 24 | PACKAGE=test 25 | SRC=exec.go 26 | NAME=standalone 27 | ZIP=$(MAIN).zip 28 | 29 | deploy: package.done $(ZIP) 30 | $(WSK) action update $(PACKAGE)/$(NAME) $(ZIP) --main $(MAIN) --docker $(OW_RUNTIME) 31 | 32 | devel: package.done $(SRC) 33 | $(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --main $(MAIN) --docker $(OW_COMPILER) 34 | 35 | $(ZIP): $(SRC) 36 | docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRC) >$(ZIP) 37 | 38 | clean: 39 | -$(WSK) action delete $(PACKAGE)/$(NAME) 40 | -rm $(ZIP) package.done test.json 41 | -rm test.out 42 | 43 | test: test.json 44 | $(WSK) action invoke test/$(NAME) -r 45 | $(WSK) action invoke test/$(NAME) -P test.json -r 46 | 47 | test.json: 48 | echo '{ "name": "Mike" }' >test.json 49 | 50 | package.done: 51 | $(WSK) package update $(PACKAGE) 52 | touch package.done 53 | 54 | .PHONY: deploy test clean 55 | -------------------------------------------------------------------------------- /examples/standalone/exec.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "bufio" 22 | "bytes" 23 | "encoding/json" 24 | "fmt" 25 | "io" 26 | "log" 27 | "os" 28 | "strings" 29 | ) 30 | 31 | func main() { 32 | // debugging 33 | var debug = os.Getenv("OW_DEBUG") != "" 34 | 35 | if debug { 36 | filename := os.Getenv("OW_DEBUG") 37 | f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 38 | if err == nil { 39 | log.SetOutput(f) 40 | defer f.Close() 41 | } 42 | log.Printf("ACTION ENV: %v", os.Environ()) 43 | } 44 | 45 | // assign the main function 46 | type Action func(event map[string]interface{}) map[string]interface{} 47 | var action Action 48 | action = Main 49 | 50 | // input 51 | out := os.NewFile(3, "pipe") 52 | defer out.Close() 53 | reader := bufio.NewReader(os.Stdin) 54 | 55 | // read-eval-print loop 56 | if debug { 57 | log.Println("started") 58 | } 59 | // send ack 60 | // note that it depends on the runtime, 61 | // go 1.13+ requires an ack, past versions does not 62 | fmt.Fprintf(out, `{ "ok": true}%s`, "\n") 63 | for { 64 | // read one line 65 | inbuf, err := reader.ReadBytes('\n') 66 | if err != nil { 67 | if err != io.EOF { 68 | log.Println(err) 69 | } 70 | break 71 | } 72 | if debug { 73 | log.Printf(">>>'%s'>>>", inbuf) 74 | } 75 | // parse one line 76 | var input map[string]interface{} 77 | err = json.Unmarshal(inbuf, &input) 78 | if err != nil { 79 | log.Println(err.Error()) 80 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 81 | continue 82 | } 83 | if debug { 84 | log.Printf("%v\n", input) 85 | } 86 | // set environment variables 87 | err = json.Unmarshal(inbuf, &input) 88 | for k, v := range input { 89 | if k == "value" { 90 | continue 91 | } 92 | if s, ok := v.(string); ok { 93 | os.Setenv("__OW_"+strings.ToUpper(k), s) 94 | } 95 | } 96 | // get payload if not empty 97 | var payload map[string]interface{} 98 | if value, ok := input["value"].(map[string]interface{}); ok { 99 | payload = value 100 | } 101 | // process the request 102 | result := action(payload) 103 | // encode the answer 104 | output, err := json.Marshal(&result) 105 | if err != nil { 106 | log.Println(err.Error()) 107 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 108 | continue 109 | } 110 | output = bytes.Replace(output, []byte("\n"), []byte(""), -1) 111 | if debug { 112 | log.Printf("'<<<%s'<<<", output) 113 | } 114 | fmt.Fprintf(out, "%s\n", output) 115 | } 116 | } 117 | 118 | // Main function for the action 119 | func Main(obj map[string]interface{}) map[string]interface{} { 120 | name, ok := obj["name"].(string) 121 | if !ok { 122 | name = "world" 123 | } 124 | fmt.Printf("name=%s\n", name) 125 | msg := make(map[string]interface{}) 126 | msg["standalone"] = "Hello, " + name + "!" 127 | return msg 128 | } 129 | -------------------------------------------------------------------------------- /examples/test.expected: -------------------------------------------------------------------------------- 1 | "bash": "Hello, Mike" 2 | "bash": "Hello, world" 3 | "module-main": "Hello, Mike!" 4 | "module-main": "Hello, world!" 5 | "package-main": "Hello, Mike" 6 | "package-main": "Hello, world" 7 | "single-hello": "Hello, Mike!" 8 | "single-hello": "Hello, world!" 9 | "single-main": "Hello, Mike!" 10 | "single-main": "Hello, world!" 11 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/apache/openwhisk-runtime-go 2 | 3 | go 1.21 4 | 5 | require github.com/stretchr/testify v1.3.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 5 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 6 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 7 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 8 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 9 | -------------------------------------------------------------------------------- /golang1.21/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # Do not fix the patch level for golang:1.21 to automatically get security fixes. 19 | FROM golang:1.21-bookworm 20 | 21 | RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections &&\ 22 | apt-get update &&\ 23 | # Upgrade installed packages to get latest security fixes if the base image does not contain them already. 24 | apt-get upgrade -y --no-install-recommends &&\ 25 | apt-get install -y apt-utils &&\ 26 | apt-get install -y \ 27 | curl \ 28 | jq \ 29 | git \ 30 | zip \ 31 | vim && \ 32 | apt-get -y install \ 33 | librdkafka1 \ 34 | librdkafka++1 &&\ 35 | apt-get -y install \ 36 | librdkafka-dev &&\ 37 | # Cleanup apt data, we do not need them later on. 38 | apt-get clean && rm -rf /var/lib/apt/lists/* &&\ 39 | go install github.com/go-delve/delve/cmd/dlv@latest &&\ 40 | mkdir /action 41 | #make python 3 react as python 42 | RUN ln -s /usr/bin/python3 /usr/bin/python 43 | 44 | WORKDIR /action 45 | ADD proxy /bin/proxy 46 | ADD bin/compile /bin/compile 47 | ADD lib/launcher.go /lib/launcher.go 48 | ENV OW_COMPILER=/bin/compile 49 | ENV OW_LOG_INIT_ERROR=1 50 | ENV OW_WAIT_FOR_ACK=1 51 | ENV OW_EXECUTION_ENV=openwhisk/action-golang-v1.21 52 | ENTRYPOINT [ "/bin/proxy" ] 53 | -------------------------------------------------------------------------------- /golang1.21/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | IMG=action-golang-v1.21 18 | 19 | build: 20 | ../gradlew distDocker 21 | 22 | localbuild: 23 | GOOS=linux GOARCH=amd64 go build -o proxy -a -ldflags '-extldflags "-static"' ../main/proxy.go 24 | docker build -t $(IMG) . 25 | docker tag $(IMG) whisk/$(IMG) 26 | 27 | push: build 28 | docker tag $(IMG) actionloop/$(IMG) 29 | docker push actionloop/$(IMG):nightly 30 | 31 | clean: 32 | docker rmi -f whisk/$(IMG) actionloop/$(IMG) 33 | 34 | debug: build 35 | docker run -p 8080:8080 \ 36 | --name go-action --rm -ti --entrypoint=/bin/bash \ 37 | -e OW_COMPILER=/mnt/bin/compile \ 38 | -v $(PWD):/mnt whisk/$(IMG) 39 | 40 | enter: 41 | docker exec -ti go-action bash 42 | 43 | 44 | .PHONY: build push clean debug enter 45 | -------------------------------------------------------------------------------- /golang1.21/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | ext.dockerImageName = 'action-golang-v1.21' 19 | apply from: '../gradle/docker.gradle' 20 | 21 | distDocker.dependsOn 'staticBuildProxy' 22 | distDocker.finalizedBy('cleanup') 23 | 24 | task staticBuildProxy(type: Exec) { 25 | environment CGO_ENABLED: "0" 26 | environment GOOS: "linux" 27 | environment GOARCH: "amd64" 28 | environment GO111MODULE: "on" 29 | 30 | commandLine 'go', 'build', 31 | '-o', 'proxy', '-a', 32 | '-ldflags', '-extldflags "-static"', 33 | '../main/proxy.go' 34 | } 35 | 36 | task cleanup(type: Delete) { 37 | delete 'proxy' 38 | } 39 | -------------------------------------------------------------------------------- /golang1.21/lib/launcher.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "bufio" 22 | "bytes" 23 | "encoding/json" 24 | "fmt" 25 | "io" 26 | "log" 27 | "os" 28 | "reflect" 29 | "strings" 30 | ) 31 | 32 | // OwExecutionEnv is the execution environment set at compile time 33 | var OwExecutionEnv = "" 34 | 35 | func main() { 36 | // check if the execution environment is correct 37 | if OwExecutionEnv != "" && OwExecutionEnv != os.Getenv("__OW_EXECUTION_ENV") { 38 | fmt.Println("Execution Environment Mismatch") 39 | fmt.Println("Expected: ", OwExecutionEnv) 40 | fmt.Println("Actual: ", os.Getenv("__OW_EXECUTION_ENV")) 41 | os.Exit(1) 42 | } 43 | 44 | // debugging 45 | var debug = os.Getenv("OW_DEBUG") != "" 46 | if debug { 47 | f, err := os.OpenFile("/tmp/action.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 48 | if err == nil { 49 | log.SetOutput(f) 50 | } 51 | log.Printf("Environment: %v", os.Environ()) 52 | } 53 | 54 | resultKind := reflect.TypeOf(Main).Out(0).Kind() 55 | if resultKind != reflect.Map && resultKind != reflect.Slice && resultKind != reflect.Array { 56 | fmt.Println("Support map and slice and array only") 57 | os.Exit(1) 58 | } 59 | 60 | // input 61 | out := os.NewFile(3, "pipe") 62 | defer out.Close() 63 | reader := bufio.NewReader(os.Stdin) 64 | 65 | // acknowledgement of started action 66 | fmt.Fprintf(out, `{ "ok": true}%s`, "\n") 67 | if debug { 68 | log.Println("action started") 69 | } 70 | 71 | // read-eval-print loop 72 | for { 73 | // read one line 74 | inbuf, err := reader.ReadBytes('\n') 75 | if err != nil { 76 | if err != io.EOF { 77 | log.Println(err) 78 | } 79 | break 80 | } 81 | if debug { 82 | log.Printf(">>>'%s'>>>", inbuf) 83 | } 84 | // parse one line 85 | var input map[string]interface{} 86 | err = json.Unmarshal(inbuf, &input) 87 | if err != nil { 88 | log.Println(err.Error()) 89 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 90 | continue 91 | } 92 | if debug { 93 | log.Printf("%v\n", input) 94 | } 95 | // set environment variables 96 | for k, v := range input { 97 | if k == "value" { 98 | continue 99 | } 100 | if s, ok := v.(string); ok { 101 | os.Setenv("__OW_"+strings.ToUpper(k), s) 102 | } 103 | } 104 | // get payload if not empty 105 | isJsonObjectParam := true 106 | var payloadForJsonObject map[string]interface{} 107 | var payloadForJsonArray []interface{} 108 | if value, ok := input["value"].(map[string]interface{}); ok { 109 | payloadForJsonObject = value 110 | } else { 111 | if value, ok := input["value"].([]interface{}); ok { 112 | payloadForJsonArray = value 113 | isJsonObjectParam = false 114 | } 115 | } 116 | // process the request 117 | var result interface{} 118 | funcMain := reflect.ValueOf(Main) 119 | if isJsonObjectParam { 120 | param := []reflect.Value{reflect.ValueOf(payloadForJsonObject)} 121 | reflectResult := funcMain.Call(param) 122 | result = reflectResult[0].Interface() 123 | } else { 124 | param := []reflect.Value{reflect.ValueOf(payloadForJsonArray)} 125 | reflectResult := funcMain.Call(param) 126 | result = reflectResult[0].Interface() 127 | } 128 | // encode the answer 129 | output, err := json.Marshal(&result) 130 | if err != nil { 131 | log.Println(err.Error()) 132 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 133 | continue 134 | } 135 | output = bytes.Replace(output, []byte("\n"), []byte(""), -1) 136 | if debug { 137 | log.Printf("<<<'%s'<<<", output) 138 | } 139 | fmt.Fprintf(out, "%s\n", output) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /golang1.22/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # Do not fix the patch level for golang:1.22 to automatically get security fixes. 19 | FROM golang:1.22-bookworm 20 | 21 | RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections &&\ 22 | apt-get update &&\ 23 | # Upgrade installed packages to get latest security fixes if the base image does not contain them already. 24 | apt-get upgrade -y --no-install-recommends &&\ 25 | apt-get install -y apt-utils &&\ 26 | apt-get install -y \ 27 | curl \ 28 | jq \ 29 | git \ 30 | zip \ 31 | vim && \ 32 | apt-get -y install \ 33 | librdkafka1 \ 34 | librdkafka++1 &&\ 35 | apt-get -y install \ 36 | librdkafka-dev &&\ 37 | # Cleanup apt data, we do not need them later on. 38 | apt-get clean && rm -rf /var/lib/apt/lists/* &&\ 39 | go install github.com/go-delve/delve/cmd/dlv@latest &&\ 40 | mkdir /action 41 | #make python 3 react as python 42 | RUN ln -s /usr/bin/python3 /usr/bin/python 43 | 44 | WORKDIR /action 45 | ADD proxy /bin/proxy 46 | ADD bin/compile /bin/compile 47 | ADD lib/launcher.go /lib/launcher.go 48 | ENV OW_COMPILER=/bin/compile 49 | ENV OW_LOG_INIT_ERROR=1 50 | ENV OW_WAIT_FOR_ACK=1 51 | ENV OW_EXECUTION_ENV=openwhisk/action-golang-v1.22 52 | ENTRYPOINT [ "/bin/proxy" ] 53 | -------------------------------------------------------------------------------- /golang1.22/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | IMG=action-golang-v1.22 18 | 19 | build: 20 | ../gradlew distDocker 21 | 22 | localbuild: 23 | GOOS=linux GOARCH=amd64 go build -o proxy -a -ldflags '-extldflags "-static"' ../main/proxy.go 24 | docker build -t $(IMG) . 25 | docker tag $(IMG) whisk/$(IMG) 26 | 27 | push: build 28 | docker tag $(IMG) actionloop/$(IMG) 29 | docker push actionloop/$(IMG):nightly 30 | 31 | clean: 32 | docker rmi -f whisk/$(IMG) actionloop/$(IMG) 33 | 34 | debug: build 35 | docker run -p 8080:8080 \ 36 | --name go-action --rm -ti --entrypoint=/bin/bash \ 37 | -e OW_COMPILER=/mnt/bin/compile \ 38 | -v $(PWD):/mnt whisk/$(IMG) 39 | 40 | enter: 41 | docker exec -ti go-action bash 42 | 43 | 44 | .PHONY: build push clean debug enter 45 | -------------------------------------------------------------------------------- /golang1.22/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | ext.dockerImageName = 'action-golang-v1.22' 19 | apply from: '../gradle/docker.gradle' 20 | 21 | distDocker.dependsOn 'staticBuildProxy' 22 | distDocker.finalizedBy('cleanup') 23 | 24 | task staticBuildProxy(type: Exec) { 25 | environment CGO_ENABLED: "0" 26 | environment GOOS: "linux" 27 | environment GOARCH: "amd64" 28 | environment GO111MODULE: "on" 29 | 30 | commandLine 'go', 'build', 31 | '-o', 'proxy', '-a', 32 | '-ldflags', '-extldflags "-static"', 33 | '../main/proxy.go' 34 | } 35 | 36 | task cleanup(type: Delete) { 37 | delete 'proxy' 38 | } 39 | -------------------------------------------------------------------------------- /golang1.22/lib/launcher.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "bufio" 22 | "bytes" 23 | "encoding/json" 24 | "fmt" 25 | "io" 26 | "log" 27 | "os" 28 | "reflect" 29 | "strings" 30 | ) 31 | 32 | // OwExecutionEnv is the execution environment set at compile time 33 | var OwExecutionEnv = "" 34 | 35 | func main() { 36 | // check if the execution environment is correct 37 | if OwExecutionEnv != "" && OwExecutionEnv != os.Getenv("__OW_EXECUTION_ENV") { 38 | fmt.Println("Execution Environment Mismatch") 39 | fmt.Println("Expected: ", OwExecutionEnv) 40 | fmt.Println("Actual: ", os.Getenv("__OW_EXECUTION_ENV")) 41 | os.Exit(1) 42 | } 43 | 44 | // debugging 45 | var debug = os.Getenv("OW_DEBUG") != "" 46 | if debug { 47 | f, err := os.OpenFile("/tmp/action.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 48 | if err == nil { 49 | log.SetOutput(f) 50 | } 51 | log.Printf("Environment: %v", os.Environ()) 52 | } 53 | 54 | resultKind := reflect.TypeOf(Main).Out(0).Kind() 55 | if resultKind != reflect.Map && resultKind != reflect.Slice && resultKind != reflect.Array { 56 | fmt.Println("Support map and slice and array only") 57 | os.Exit(1) 58 | } 59 | 60 | // input 61 | out := os.NewFile(3, "pipe") 62 | defer out.Close() 63 | reader := bufio.NewReader(os.Stdin) 64 | 65 | // acknowledgement of started action 66 | fmt.Fprintf(out, `{ "ok": true}%s`, "\n") 67 | if debug { 68 | log.Println("action started") 69 | } 70 | 71 | // read-eval-print loop 72 | for { 73 | // read one line 74 | inbuf, err := reader.ReadBytes('\n') 75 | if err != nil { 76 | if err != io.EOF { 77 | log.Println(err) 78 | } 79 | break 80 | } 81 | if debug { 82 | log.Printf(">>>'%s'>>>", inbuf) 83 | } 84 | // parse one line 85 | var input map[string]interface{} 86 | err = json.Unmarshal(inbuf, &input) 87 | if err != nil { 88 | log.Println(err.Error()) 89 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 90 | continue 91 | } 92 | if debug { 93 | log.Printf("%v\n", input) 94 | } 95 | // set environment variables 96 | for k, v := range input { 97 | if k == "value" { 98 | continue 99 | } 100 | if s, ok := v.(string); ok { 101 | os.Setenv("__OW_"+strings.ToUpper(k), s) 102 | } 103 | } 104 | // get payload if not empty 105 | isJsonObjectParam := true 106 | var payloadForJsonObject map[string]interface{} 107 | var payloadForJsonArray []interface{} 108 | if value, ok := input["value"].(map[string]interface{}); ok { 109 | payloadForJsonObject = value 110 | } else { 111 | if value, ok := input["value"].([]interface{}); ok { 112 | payloadForJsonArray = value 113 | isJsonObjectParam = false 114 | } 115 | } 116 | // process the request 117 | var result interface{} 118 | funcMain := reflect.ValueOf(Main) 119 | if isJsonObjectParam { 120 | param := []reflect.Value{reflect.ValueOf(payloadForJsonObject)} 121 | reflectResult := funcMain.Call(param) 122 | result = reflectResult[0].Interface() 123 | } else { 124 | param := []reflect.Value{reflect.ValueOf(payloadForJsonArray)} 125 | reflectResult := funcMain.Call(param) 126 | result = reflectResult[0].Interface() 127 | } 128 | // encode the answer 129 | output, err := json.Marshal(&result) 130 | if err != nil { 131 | log.Println(err.Error()) 132 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 133 | continue 134 | } 135 | output = bytes.Replace(output, []byte("\n"), []byte(""), -1) 136 | if debug { 137 | log.Printf("<<<'%s'<<<", output) 138 | } 139 | fmt.Fprintf(out, "%s\n", output) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /golang1.23/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # Do not fix the patch level for golang:1.22 to automatically get security fixes. 19 | FROM golang:1.23-bookworm 20 | 21 | RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections &&\ 22 | apt-get update &&\ 23 | # Upgrade installed packages to get latest security fixes if the base image does not contain them already. 24 | apt-get upgrade -y --no-install-recommends &&\ 25 | apt-get install -y apt-utils &&\ 26 | apt-get install -y \ 27 | curl \ 28 | jq \ 29 | git \ 30 | zip \ 31 | vim && \ 32 | apt-get -y install \ 33 | librdkafka1 \ 34 | librdkafka++1 &&\ 35 | apt-get -y install \ 36 | librdkafka-dev &&\ 37 | # Cleanup apt data, we do not need them later on. 38 | apt-get clean && rm -rf /var/lib/apt/lists/* &&\ 39 | go install github.com/go-delve/delve/cmd/dlv@latest &&\ 40 | mkdir /action 41 | #make python 3 react as python 42 | RUN ln -s /usr/bin/python3 /usr/bin/python 43 | 44 | WORKDIR /action 45 | ADD proxy /bin/proxy 46 | ADD bin/compile /bin/compile 47 | ADD lib/launcher.go /lib/launcher.go 48 | ENV OW_COMPILER=/bin/compile 49 | ENV OW_LOG_INIT_ERROR=1 50 | ENV OW_WAIT_FOR_ACK=1 51 | ENV OW_EXECUTION_ENV=openwhisk/action-golang-v1.23 52 | ENTRYPOINT [ "/bin/proxy" ] 53 | -------------------------------------------------------------------------------- /golang1.23/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | IMG=action-golang-v1.23 18 | 19 | build: 20 | ../gradlew distDocker 21 | 22 | localbuild: 23 | GOOS=linux GOARCH=amd64 go build -o proxy -a -ldflags '-extldflags "-static"' ../main/proxy.go 24 | docker build -t $(IMG) . 25 | docker tag $(IMG) whisk/$(IMG) 26 | 27 | push: build 28 | docker tag $(IMG) actionloop/$(IMG) 29 | docker push actionloop/$(IMG):nightly 30 | 31 | clean: 32 | docker rmi -f whisk/$(IMG) actionloop/$(IMG) 33 | 34 | debug: build 35 | docker run -p 8080:8080 \ 36 | --name go-action --rm -ti --entrypoint=/bin/bash \ 37 | -e OW_COMPILER=/mnt/bin/compile \ 38 | -v $(PWD):/mnt whisk/$(IMG) 39 | 40 | enter: 41 | docker exec -ti go-action bash 42 | 43 | 44 | .PHONY: build push clean debug enter 45 | -------------------------------------------------------------------------------- /golang1.23/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | ext.dockerImageName = 'action-golang-v1.23' 19 | apply from: '../gradle/docker.gradle' 20 | 21 | distDocker.dependsOn 'staticBuildProxy' 22 | distDocker.finalizedBy('cleanup') 23 | 24 | task staticBuildProxy(type: Exec) { 25 | environment CGO_ENABLED: "0" 26 | environment GOOS: "linux" 27 | environment GOARCH: "amd64" 28 | environment GO111MODULE: "on" 29 | 30 | commandLine 'go', 'build', 31 | '-o', 'proxy', '-a', 32 | '-ldflags', '-extldflags "-static"', 33 | '../main/proxy.go' 34 | } 35 | 36 | task cleanup(type: Delete) { 37 | delete 'proxy' 38 | } 39 | -------------------------------------------------------------------------------- /golang1.23/lib/launcher.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "bufio" 22 | "bytes" 23 | "encoding/json" 24 | "fmt" 25 | "io" 26 | "log" 27 | "os" 28 | "reflect" 29 | "strings" 30 | ) 31 | 32 | // OwExecutionEnv is the execution environment set at compile time 33 | var OwExecutionEnv = "" 34 | 35 | func main() { 36 | // check if the execution environment is correct 37 | if OwExecutionEnv != "" && OwExecutionEnv != os.Getenv("__OW_EXECUTION_ENV") { 38 | fmt.Println("Execution Environment Mismatch") 39 | fmt.Println("Expected: ", OwExecutionEnv) 40 | fmt.Println("Actual: ", os.Getenv("__OW_EXECUTION_ENV")) 41 | os.Exit(1) 42 | } 43 | 44 | // debugging 45 | var debug = os.Getenv("OW_DEBUG") != "" 46 | if debug { 47 | f, err := os.OpenFile("/tmp/action.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 48 | if err == nil { 49 | log.SetOutput(f) 50 | } 51 | log.Printf("Environment: %v", os.Environ()) 52 | } 53 | 54 | resultKind := reflect.TypeOf(Main).Out(0).Kind() 55 | if resultKind != reflect.Map && resultKind != reflect.Slice && resultKind != reflect.Array { 56 | fmt.Println("Support map and slice and array only") 57 | os.Exit(1) 58 | } 59 | 60 | // input 61 | out := os.NewFile(3, "pipe") 62 | defer out.Close() 63 | reader := bufio.NewReader(os.Stdin) 64 | 65 | // acknowledgement of started action 66 | fmt.Fprintf(out, `{ "ok": true}%s`, "\n") 67 | if debug { 68 | log.Println("action started") 69 | } 70 | 71 | // read-eval-print loop 72 | for { 73 | // read one line 74 | inbuf, err := reader.ReadBytes('\n') 75 | if err != nil { 76 | if err != io.EOF { 77 | log.Println(err) 78 | } 79 | break 80 | } 81 | if debug { 82 | log.Printf(">>>'%s'>>>", inbuf) 83 | } 84 | // parse one line 85 | var input map[string]interface{} 86 | err = json.Unmarshal(inbuf, &input) 87 | if err != nil { 88 | log.Println(err.Error()) 89 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 90 | continue 91 | } 92 | if debug { 93 | log.Printf("%v\n", input) 94 | } 95 | // set environment variables 96 | for k, v := range input { 97 | if k == "value" { 98 | continue 99 | } 100 | if s, ok := v.(string); ok { 101 | os.Setenv("__OW_"+strings.ToUpper(k), s) 102 | } 103 | } 104 | // get payload if not empty 105 | isJsonObjectParam := true 106 | var payloadForJsonObject map[string]interface{} 107 | var payloadForJsonArray []interface{} 108 | if value, ok := input["value"].(map[string]interface{}); ok { 109 | payloadForJsonObject = value 110 | } else { 111 | if value, ok := input["value"].([]interface{}); ok { 112 | payloadForJsonArray = value 113 | isJsonObjectParam = false 114 | } 115 | } 116 | // process the request 117 | var result interface{} 118 | funcMain := reflect.ValueOf(Main) 119 | if isJsonObjectParam { 120 | param := []reflect.Value{reflect.ValueOf(payloadForJsonObject)} 121 | reflectResult := funcMain.Call(param) 122 | result = reflectResult[0].Interface() 123 | } else { 124 | param := []reflect.Value{reflect.ValueOf(payloadForJsonArray)} 125 | reflectResult := funcMain.Call(param) 126 | result = reflectResult[0].Interface() 127 | } 128 | // encode the answer 129 | output, err := json.Marshal(&result) 130 | if err != nil { 131 | log.Println(err.Error()) 132 | fmt.Fprintf(out, "{ error: %q}\n", err.Error()) 133 | continue 134 | } 135 | output = bytes.Replace(output, []byte("\n"), []byte(""), -1) 136 | if debug { 137 | log.Printf("<<<'%s'<<<", output) 138 | } 139 | fmt.Fprintf(out, "%s\n", output) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /gradle/README.md: -------------------------------------------------------------------------------- 1 | 19 | 20 | # Gradle 21 | 22 | Gradle is used to build OpenWhisk. It does not need to be pre-installed as it installs itself using the [Gradle Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html). To use it without installing, simply invoke the `gradlew` command at the root of the repository. You can also install `gradle` via [`apt`](http://linuxg.net/how-to-install-gradle-2-1-on-ubuntu-14-10-ubuntu-14-04-ubuntu-12-04-and-derivatives/) on Ubuntu or [`brew`](http://www.brewformulas.org/Gradle) on Mac. In the following we use `gradle` and `gradlew` as synonymous. 23 | 24 | ## Usage 25 | 26 | In general, project level properties are set via `-P{propertyName}={propertyValue}`. A task is called via `gradle {taskName}` and a subproject task is called via `gradle :path:to:subproject:{taskName}`. To run tasks in parallel, use the `--parallel` flag (**Note:** It's an incubating feature and might break stuff). 27 | 28 | ### Build 29 | 30 | To build all Docker images use `gradle distDocker` at the top level project, to build a specific component use `gradle :core:controller:distDocker`. 31 | 32 | Project level options that can be used on `distDocker`: 33 | 34 | - `dockerImageName` (*required*): The name of the image to build (e.g. whisk/controller) 35 | - `dockerHost` (*optional*): The docker host to run commands on, default behaviour is docker's own `DOCKER_HOST` environment variable 36 | - `dockerRegistry` (*optional*): The registry to push to 37 | - `dockerImageTag` (*optional*, default 'latest'): The tag for the image 38 | - `dockerTimeout` (*optional*, default 240): Timeout for docker operations in seconds 39 | - `dockerRetries` (*optional*, default 3): How many times to retry docker operations 40 | - `dockerBinary` (*optional*, default `docker`): The binary to execute docker commands 41 | 42 | ### Test 43 | 44 | To run tests one uses the `test` task. OpenWhisk consolidates tests into a single `tests` project. Hence the command to run all tests is `gradle :tests:test`. 45 | 46 | It is possible to run specific tests using [Gradle testfilters](https://docs.gradle.org/current/userguide/java_plugin.html#test_filtering). For example `gradle :tests:test --tests "your.package.name.TestClass.evenMethodName"`. Wildcard `*` may be used anywhere. 47 | 48 | ## Build your own `build.gradle` 49 | In Gradle, most of the tasks we use are default tasks provided by plugins in Gradle. The [`scala` Plugin](https://docs.gradle.org/current/userguide/scala_plugin.html) for example includes tasks, that are needed to build Scala projects. Moreover, Gradle is aware of *Applications*. The [`application` Plugin](https://docs.gradle.org/current/userguide/application_plugin.html) provides tasks that are required to distribute a self-contained application. When `application` and `scala` are used in conjunction, they hook into each other and provide the tasks needed to distribute a Scala application. `distTar` for example compiles the Scala code, creates a jar containing the compiled classes and resources and creates a Tarball including that jar and all of its dependencies (defined in the dependencies section of `build.gradle`). It also creates a start-script which correctly sets the classpath for all those dependencies and starts the app. 50 | 51 | In OpenWhisk, we want to distribute our application via Docker images. Hence we wrote a "plugin" that creates the task `distDocker`. That task will build an image from the `Dockerfile` that is located next to the `build.gradle` it is called from, for example Controller's `Dockerfile` and `build.gradle` are both located at `core/controller`. 52 | 53 | If you want to create a new `build.gradle` for your component, simply put the `Dockerfile` right next to it and include `docker.gradle` by using 54 | 55 | ``` 56 | ext.dockerImageName = 'openwwhisk/{IMAGENAME}' 57 | apply from: 'path/to/docker.gradle' 58 | ``` 59 | 60 | If your component needs to be build before you can build the image, make `distDocker` depend on any task needed to run before it, for example: 61 | 62 | ``` 63 | distDocker.dependsOn ':common:scala:distDocker', 'distTar' 64 | ``` 65 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/openwhisk-runtime-go/8290d162250635ceb7af136c880833e869400eaa/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | distributionBase=GRADLE_USER_HOME 18 | distributionPath=wrapper/dists 19 | zipStoreBase=GRADLE_USER_HOME 20 | zipStorePath=wrapper/dists 21 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.3-bin.zip 22 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /licenses/LICENSE-testify.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /main/proxy.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package main 18 | 19 | import ( 20 | "flag" 21 | "fmt" 22 | "log" 23 | "os" 24 | "runtime" 25 | 26 | "github.com/apache/openwhisk-runtime-go/openwhisk" 27 | ) 28 | 29 | // flag to show version 30 | var version = flag.Bool("version", false, "show version") 31 | 32 | // flag to enable debug 33 | var debug = flag.Bool("debug", false, "enable debug output") 34 | 35 | // flag to require on-the-fly compilation 36 | var compile = flag.String("compile", "", "compile, reading in standard input the specified function, and producing the result in stdout") 37 | 38 | // flag to pass an environment as a json string 39 | var env = flag.String("env", "", "pass an environment as a json string") 40 | 41 | // fatal if error 42 | func fatalIf(err error) { 43 | if err != nil { 44 | log.Fatal(err) 45 | } 46 | } 47 | 48 | func main() { 49 | flag.Parse() 50 | 51 | // show version number 52 | if *version { 53 | fmt.Printf("OpenWhisk ActionLoop Proxy v%s, built with %s\n", openwhisk.Version, runtime.Version()) 54 | return 55 | } 56 | 57 | // debugging 58 | if *debug { 59 | // set debugging flag, propagated to the actions 60 | openwhisk.Debugging = true 61 | os.Setenv("OW_DEBUG", "1") 62 | } 63 | 64 | // create the action proxy 65 | ap := openwhisk.NewActionProxy("./action", os.Getenv("OW_COMPILER"), os.Stdout, os.Stderr) 66 | 67 | // compile on the fly upon request 68 | if *compile != "" { 69 | ap.ExtractAndCompileIO(os.Stdin, os.Stdout, *compile, *env) 70 | return 71 | } 72 | 73 | // start the balls rolling 74 | openwhisk.Debug("OpenWhisk ActionLoop Proxy %s: starting", openwhisk.Version) 75 | ap.Start(8080) 76 | 77 | } 78 | -------------------------------------------------------------------------------- /openwhisk/_test/action/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | Package.resolved 6 | *.json 7 | .*_history 8 | .viminfo 9 | -------------------------------------------------------------------------------- /openwhisk/_test/action/hello.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package action 19 | 20 | import ( 21 | "encoding/json" 22 | "fmt" 23 | //"log" 24 | ) 25 | 26 | // Hello receive an event in format 27 | // { "name": "Mike"} 28 | // and returns a greeting in format 29 | // { "greetings": "Hello, Mike"} 30 | func Hello(event json.RawMessage) (json.RawMessage, error) { 31 | // input and output 32 | var input struct { 33 | Name string 34 | } 35 | var output struct { 36 | Greetings string `json:"greetings"` 37 | } 38 | // read the input event 39 | json.Unmarshal(event, &input) 40 | if input.Name != "" { 41 | // handle the event 42 | output.Greetings = "Hello, " + input.Name 43 | fmt.Println(output.Greetings) 44 | return json.Marshal(output) 45 | } 46 | return nil, fmt.Errorf("no name specified") 47 | } 48 | -------------------------------------------------------------------------------- /openwhisk/_test/action/hello_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package action 18 | 19 | import ( 20 | "fmt" 21 | ) 22 | 23 | func ExampleHello() { 24 | name := []byte(`{ "name": "Mike"}`) 25 | data, _ := Hello(name) 26 | fmt.Printf("%s", data) 27 | // Output: 28 | // Hello, Mike 29 | // {"greetings":"Hello, Mike"} 30 | } 31 | 32 | func ExampleHello_noName() { 33 | name := []byte(`{ "noname": "Mike"}`) 34 | _, err := Hello(name) 35 | fmt.Print(err) 36 | // Output: 37 | // no name specified 38 | } 39 | func ExampleHello_badJson() { 40 | name := []byte(`{{`) 41 | _, err := Hello(name) 42 | fmt.Print(err) 43 | // Output: 44 | // no name specified 45 | } 46 | -------------------------------------------------------------------------------- /openwhisk/_test/action/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package action 19 | 20 | import ( 21 | "encoding/json" 22 | "fmt" 23 | ) 24 | 25 | // Main forwarding to Hello 26 | func Main(event json.RawMessage) (json.RawMessage, error) { 27 | fmt.Println("Main:") 28 | return Hello(event) 29 | } 30 | -------------------------------------------------------------------------------- /openwhisk/_test/badack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | echo "bad ack" >&3 19 | read 20 | -------------------------------------------------------------------------------- /openwhisk/_test/badack2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | echo "{}" >&3 19 | read 20 | -------------------------------------------------------------------------------- /openwhisk/_test/badcompile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | echo "error in stdout" 19 | echo "error in stderr" >&2 20 | -------------------------------------------------------------------------------- /openwhisk/_test/bc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | bc -q >&3 19 | 20 | -------------------------------------------------------------------------------- /openwhisk/_test/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | cd "$(dirname $0)" 20 | 21 | function build { 22 | test -e exec && rm exec 23 | cp $1.src $1.go 24 | GOPATH=$PWD go build -a -o exec $1.go 25 | rm $1.go 26 | } 27 | 28 | function build_main { 29 | test -e exec && rm exec 30 | cp ../../common/gobuild.py.launcher.go $1.go 31 | cat $1.src >>$1.go 32 | go build -a -o exec $1.go 33 | rm $1.go 34 | } 35 | 36 | 37 | build hi 38 | zip -q hi.zip exec 39 | cp exec hi 40 | 41 | build_main hello_message 42 | zip -q hello_message.zip exec 43 | cp exec hello_message 44 | 45 | build_main hello_greeting 46 | zip -q hello_greeting.zip exec 47 | cp exec hello_greeting 48 | 49 | test -e hello.zip && rm hello.zip 50 | cd src 51 | zip -q -r ../hello.zip main.go hello 52 | cd .. 53 | 54 | test -e sample.jar && rm sample.jar 55 | cd jar ; zip -q -r ../sample.jar * ; cd .. 56 | 57 | build exec 58 | test -e exec.zip && rm exec.zip 59 | zip -q -r exec.zip exec etc dir 60 | echo exec/env >helloack/exec.env 61 | zip -j helloack.zip helloack/* 62 | 63 | python3 -m venv venv 64 | -------------------------------------------------------------------------------- /openwhisk/_test/compile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | import os 20 | import sys 21 | 22 | os.rename(sys.argv[2], sys.argv[3] + "/action") 23 | 24 | with open(sys.argv[3] + "/exec", "w") as f: 25 | f.write("""#!/bin/bash 26 | cd "$(dirname $0)" 27 | export PYTHONPATH=$PWD/action 28 | python action/exec.py 29 | """) 30 | -------------------------------------------------------------------------------- /openwhisk/_test/dir/etc: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /openwhisk/_test/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | while read line 20 | do echo '{ "env": "'$(env | grep TEST_ | sort)'"}' >&3 21 | done 22 | 23 | 24 | -------------------------------------------------------------------------------- /openwhisk/_test/error.src: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | func Main() { 21 | syntax error 22 | } 23 | -------------------------------------------------------------------------------- /openwhisk/_test/etc: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /openwhisk/_test/exec.src: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | func main() {} 21 | -------------------------------------------------------------------------------- /openwhisk/_test/find.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | find "$1" | sort 19 | -------------------------------------------------------------------------------- /openwhisk/_test/first/3/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /openwhisk/_test/hello.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | while read line 19 | do 20 | name="$(echo $line | jq -r .value.name)" 21 | echo msg="hello $name" 22 | echo '{"hello": "'$name'"}' >&3 23 | done 24 | -------------------------------------------------------------------------------- /openwhisk/_test/hello.src: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import "fmt" 21 | 22 | func Main(obj map[string]interface{}) map[string]interface{} { 23 | name, ok := obj["name"].(string) 24 | if !ok { 25 | name = "Stranger" 26 | } 27 | fmt.Printf("name=%s\n", name) 28 | msg := make(map[string]interface{}) 29 | msg["message"] = "Hello, " + name + "!" 30 | return msg 31 | } 32 | -------------------------------------------------------------------------------- /openwhisk/_test/hello/hello.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package hello 19 | 20 | import ( 21 | "fmt" 22 | ) 23 | 24 | // Hello receive an event in format 25 | // { "name": "Mike"} 26 | // and returns a greeting in format 27 | // { "greetings": "Hello, Mike"} 28 | func Hello(args map[string]interface{}) map[string]interface{} { 29 | res := make(map[string]interface{}) 30 | greetings := "Stranger" 31 | name, ok := args["name"].(string) 32 | if ok { 33 | greetings = name 34 | } 35 | res["greetings"] = "Hello, " + greetings 36 | fmt.Printf("Hello, %s\n", greetings) 37 | return res 38 | } 39 | -------------------------------------------------------------------------------- /openwhisk/_test/hello1.src: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | ) 23 | 24 | func Hello(obj map[string]interface{}) map[string]interface{} { 25 | name, ok := obj["name"].(string) 26 | if !ok { 27 | name = "Stranger" 28 | } 29 | fmt.Printf("name=%s\n", name) 30 | msg := make(map[string]interface{}) 31 | msg["hello"] = "Hello, " + name + "!" 32 | return msg 33 | } 34 | -------------------------------------------------------------------------------- /openwhisk/_test/hello2.src: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "hello" 23 | ) 24 | 25 | // Main forwarding to Hello 26 | func Main(args map[string]interface{}) map[string]interface{} { 27 | fmt.Println("Main") 28 | return hello.Hello(args) 29 | } 30 | -------------------------------------------------------------------------------- /openwhisk/_test/hello_greeting.src: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | func Main(obj map[string]interface{}) map[string]interface{} { 19 | return Hello(obj) 20 | } 21 | 22 | // Hello receive an event in format 23 | // { "name": "Mike"} 24 | // and returns a greeting in format 25 | // { "greetings": "Hello, Mike"} 26 | func Hello(args map[string]interface{}) map[string]interface{} { 27 | res := make(map[string]interface{}) 28 | greetings := "Stranger" 29 | name, ok := args["name"].(string) 30 | if ok { 31 | greetings = name 32 | } 33 | res["greetings"] = "Hello, " + greetings 34 | fmt.Printf("Hello, %s\n", greetings) 35 | return res 36 | } 37 | -------------------------------------------------------------------------------- /openwhisk/_test/hello_message.src: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | func Main(obj map[string]interface{}) map[string]interface{} { 19 | name, ok := obj["name"].(string) 20 | if !ok { 21 | name = "Stranger" 22 | } 23 | fmt.Printf("name=%s\n", name) 24 | msg := make(map[string]interface{}) 25 | msg["message"] = "Hello, " + name + "!" 26 | return msg 27 | } 28 | 29 | -------------------------------------------------------------------------------- /openwhisk/_test/helloack/exec: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | echo '{"ok":true}' >&3 19 | while read line 20 | do 21 | name="$(echo $line | jq -r .value.name)" 22 | echo msg="hello $name" 23 | echo '{"hello": "'$name'"}' >&3 24 | done 25 | -------------------------------------------------------------------------------- /openwhisk/_test/hi.src: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "bufio" 22 | "os" 23 | ) 24 | 25 | func main() { 26 | f := bufio.NewWriter(os.Stdout) 27 | defer f.Flush() 28 | f.Write([]byte("hi\n")) 29 | } 30 | -------------------------------------------------------------------------------- /openwhisk/_test/jar/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | Manifest-Version: 1.0 18 | Created-By: 1.8.0_191 (Oracle Corporation) 19 | -------------------------------------------------------------------------------- /openwhisk/_test/jar/hello.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | -------------------------------------------------------------------------------- /openwhisk/_test/postcompile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | FILE=${1:?compiled file} 19 | file --mime-type "$FILE" | sed -e 's/x-mach-binary/x-executable/' 20 | echo '{"value":{"name":"Mike"}}' | $FILE 3>/tmp/$$ 21 | cat /tmp/$$ 22 | rm /tmp/$$ 23 | -------------------------------------------------------------------------------- /openwhisk/_test/precompile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | cd "$(dirname $0)" 19 | SRC=${1:?source file or dir} 20 | ID=${2:?target dir} 21 | TGT=${3:-exec} 22 | ETC=${4:-} 23 | rm -Rvf compile/$ID >/dev/null 24 | mkdir -p compile/$ID/src compile/$ID/bin 25 | cp $SRC compile/$ID/src/$TGT 26 | if test -d "$ETC" 27 | then cp -r "$ETC" compile/$ID/src 28 | fi 29 | 30 | -------------------------------------------------------------------------------- /openwhisk/_test/pysample/exec: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | cd "$(dirname $0)" 19 | export PYTHONPATH=$PWD/lib 20 | python lib/exec.py 21 | -------------------------------------------------------------------------------- /openwhisk/_test/pysample/lib/action/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | -------------------------------------------------------------------------------- /openwhisk/_test/pysample/lib/action/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | 20 | def main(args): 21 | name = "world" 22 | if "name" in args: 23 | name = args["name"] 24 | return {"python": "Hello, %s" % name} 25 | -------------------------------------------------------------------------------- /openwhisk/_test/pysample/lib/exec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | from __future__ import print_function 20 | 21 | import os 22 | import json 23 | 24 | from action.main import main 25 | inp = os.fdopen(0, "rb") 26 | out = os.fdopen(3, "wb") 27 | while True: 28 | while True: 29 | line = inp.readline() 30 | args = json.loads(line) 31 | payload = {} 32 | if "value" in args: 33 | payload = args["value"] 34 | res = main(payload) 35 | out.write(json.dumps(res, ensure_ascii=False).encode('utf-8')) 36 | out.write(b"\n") 37 | out.flush() 38 | -------------------------------------------------------------------------------- /openwhisk/_test/second/17/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /openwhisk/_test/second/3/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /openwhisk/_test/second/8/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /openwhisk/_test/src/hello/hello.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package hello 19 | 20 | import ( 21 | "fmt" 22 | ) 23 | 24 | // Hello receive an event in format 25 | // { "name": "Mike"} 26 | // and returns a greeting in format 27 | // { "greetings": "Hello, Mike"} 28 | func Hello(args map[string]interface{}) map[string]interface{} { 29 | res := make(map[string]interface{}) 30 | greetings := "Stranger" 31 | name, ok := args["name"].(string) 32 | if ok { 33 | greetings = name 34 | } 35 | res["greetings"] = "Hello, " + greetings 36 | fmt.Printf("Hello, %s\n", greetings) 37 | return res 38 | } 39 | -------------------------------------------------------------------------------- /openwhisk/_test/src/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "hello" 23 | ) 24 | 25 | // Main forwarding to Hello 26 | func Main(args map[string]interface{}) map[string]interface{} { 27 | fmt.Println("Main") 28 | return hello.Hello(args) 29 | } 30 | -------------------------------------------------------------------------------- /openwhisk/_test/zips.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | cd "$(dirname $0)" 19 | rm action.zip 2>/dev/null 20 | zip -r -q action.zip action 21 | -------------------------------------------------------------------------------- /openwhisk/compiler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package openwhisk 19 | 20 | import ( 21 | "fmt" 22 | "io/ioutil" 23 | "os" 24 | "os/exec" 25 | "runtime" 26 | ) 27 | 28 | // check if the file exists and it is already compiled 29 | func isCompiled(file string) bool { 30 | Debug("IsCompiled? %s", file) 31 | _, err := os.Stat(file) 32 | if err != nil { 33 | return false 34 | } 35 | 36 | buf, err := ioutil.ReadFile(file) 37 | if err != nil { 38 | Debug(err.Error()) 39 | return false 40 | } 41 | 42 | // check if it is an executable 43 | return IsExecutable(buf, runtime.GOOS) 44 | } 45 | 46 | // CompileAction will compile an anction in source format invoking a compiler 47 | func (ap *ActionProxy) CompileAction(main string, srcDir string, binDir string) error { 48 | if ap.compiler == "" { 49 | return fmt.Errorf("No compiler defined") 50 | } 51 | 52 | Debug("compiling: %s %s %s %s", ap.compiler, main, srcDir, binDir) 53 | 54 | var cmd *exec.Cmd 55 | cmd = exec.Command(ap.compiler, main, srcDir, binDir) 56 | cmd.Env = []string{"PATH=" + os.Getenv("PATH")} 57 | for k, v := range ap.env { 58 | cmd.Env = append(cmd.Env, k+"="+v) 59 | } 60 | 61 | // gather stdout and stderr 62 | out, err := cmd.CombinedOutput() 63 | Debug("compiler out: %s, %v", out, err) 64 | if len(out) > 0 { 65 | return fmt.Errorf("%s", out) 66 | } 67 | if err != nil { 68 | return err 69 | } 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /openwhisk/compiler_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package openwhisk 19 | 20 | import ( 21 | "fmt" 22 | "os" 23 | ) 24 | 25 | /** 26 | Notes to understand tests: 27 | - tests are run from the "openwhisk" folder, as the current directory 28 | - precompile.sh prepare a compilation environment: 29 | _test/precompile.sh hello.src aaa main 30 | produces 31 | - _test/compile/src/aaa/src/main 32 | - _test/compile/src/aaa/bin/ 33 | ready for the compiler 34 | - compiler (../../common/gobuild.py) takes 3 arguments: 35 |
36 | - it will look for a /
file 37 | - will generate some files in 38 | - compiler output is in /
39 | - postcompile.sh will 40 | - execute the binary with 3>&1 41 | - feed it with the json '{"name":"Mike"} 42 | - will print the type of the executable and its output and log 43 | */ 44 | 45 | const ( 46 | PREP = "_test/precompile.sh" 47 | CHECK = "_test/postcompile.sh" 48 | TMP = "_test/compile/" 49 | COMP = "../common/gobuild.py" 50 | ) 51 | 52 | // compile a main 53 | func Example_cli_compiler() { 54 | sys(PREP, "hello.src", "0", "exec") 55 | ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr) 56 | fmt.Println(isCompiled(TMP + "0/src/exec")) 57 | ap.CompileAction("main", TMP+"0/src", TMP+"0/bin") 58 | sys(CHECK, TMP+"0/bin/exec") 59 | fmt.Println(isCompiled(TMP + "0/bin/exec")) 60 | // errors 61 | fmt.Println(isCompiled(TMP + "0/bin/exec1")) 62 | // Output: 63 | // false 64 | // _test/compile/0/bin/exec: application/x-executable 65 | // name=Mike 66 | // {"message":"Hello, Mike!"} 67 | // true 68 | // false 69 | } 70 | 71 | // compile a not-main (hello) function 72 | func Example_hello() { 73 | N := "1" 74 | sys(PREP, "hello1.src", N, "exec") 75 | ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr) 76 | env := map[string]interface{}{"GOROOT": TMP + N} 77 | ap.SetEnv(env) 78 | ap.CompileAction("hello", TMP+N+"/src", TMP+N+"/bin") 79 | sys(CHECK, TMP+N+"/bin/exec") 80 | // Output: 81 | // _test/compile/1/bin/exec: application/x-executable 82 | // name=Mike 83 | // {"hello":"Hello, Mike!"} 84 | } 85 | 86 | // compile a function including a package 87 | func Example_package() { 88 | N := "2" 89 | sys(PREP, "hello2.src", N, "exec", "hello") 90 | ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr) 91 | env := map[string]interface{}{"GOROOT": TMP + N} 92 | ap.SetEnv(env) 93 | ap.CompileAction("main", TMP+N+"/src", TMP+N+"/bin") 94 | sys(CHECK, TMP+N+"/bin/exec") 95 | // Output: 96 | // _test/compile/2/bin/exec: application/x-executable 97 | // Main 98 | // Hello, Mike 99 | // {"greetings":"Hello, Mike"} 100 | } 101 | 102 | func Example_compileError() { 103 | N := "6" 104 | sys(PREP, "error.src", N) 105 | ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr) 106 | err := ap.CompileAction("main", TMP+N+"/src", TMP+N+"/bin") 107 | fmt.Printf("%v", removeLineNr(err.Error())) 108 | // Unordered output: 109 | // ./exec__.go::: syntax error: unexpected error at end of statement 110 | } 111 | 112 | func Example_withMain() { 113 | N := "7" 114 | sys(PREP, "hi.src", N, "exec") 115 | ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr) 116 | err := ap.CompileAction("main", TMP+N+"/src", TMP+N+"/bin") 117 | fmt.Println(err) 118 | sys(TMP + N + "/bin/exec") 119 | // Output: 120 | // 121 | // hi 122 | } 123 | -------------------------------------------------------------------------------- /openwhisk/debug.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package openwhisk 18 | 19 | import "log" 20 | 21 | // Debugging flag 22 | var Debugging = false 23 | 24 | // Debug emits a debug message 25 | func Debug(format string, args ...interface{}) { 26 | if Debugging { 27 | log.Printf(format, args...) 28 | } 29 | } 30 | 31 | // DebugLimit emits a debug message with a limit in length 32 | func DebugLimit(msg string, in []byte, limit int) { 33 | if len(in) < limit { 34 | Debug("%s:%s", msg, in) 35 | } else { 36 | Debug("%s:%s...", msg, in[0:limit]) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /openwhisk/executor_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package openwhisk 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | ) 23 | 24 | var m = map[string]string{} 25 | 26 | func ExampleNewExecutor_failed() { 27 | log, _ := ioutil.TempFile("", "log") 28 | proc := NewExecutor(log, log, "true", m) 29 | err := proc.Start(false) 30 | fmt.Println(err) 31 | proc.Stop() 32 | proc = NewExecutor(log, log, "/bin/pwd", m) 33 | err = proc.Start(false) 34 | fmt.Println(err) 35 | proc.Stop() 36 | proc = NewExecutor(log, log, "donotexist", m) 37 | err = proc.Start(false) 38 | fmt.Println(err) 39 | proc.Stop() 40 | proc = NewExecutor(log, log, "/etc/passwd", m) 41 | err = proc.Start(false) 42 | fmt.Println(err) 43 | proc.Stop() 44 | // Output: 45 | // command exited 46 | // command exited 47 | // command exited 48 | // command exited 49 | } 50 | 51 | func ExampleNewExecutor_bc() { 52 | log, _ := ioutil.TempFile("", "log") 53 | proc := NewExecutor(log, log, "_test/bc.sh", m) 54 | err := proc.Start(false) 55 | fmt.Println(err) 56 | res, _ := proc.Interact([]byte("2+2")) 57 | fmt.Printf("%s", res) 58 | proc.Stop() 59 | dump(log) 60 | // Output: 61 | // 62 | // 4 63 | // XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX 64 | // XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX 65 | } 66 | 67 | func ExampleNewExecutor_hello() { 68 | log, _ := ioutil.TempFile("", "log") 69 | proc := NewExecutor(log, log, "_test/hello.sh", m) 70 | err := proc.Start(false) 71 | fmt.Println(err) 72 | res, _ := proc.Interact([]byte(`{"value":{"name":"Mike"}}`)) 73 | fmt.Printf("%s", res) 74 | proc.Stop() 75 | dump(log) 76 | // Output: 77 | // 78 | // {"hello": "Mike"} 79 | // msg=hello Mike 80 | // XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX 81 | // XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX 82 | } 83 | 84 | func ExampleNewExecutor_env() { 85 | log, _ := ioutil.TempFile("", "log") 86 | proc := NewExecutor(log, log, "_test/env.sh", map[string]string{"TEST_HELLO": "WORLD", "TEST_HI": "ALL"}) 87 | err := proc.Start(false) 88 | fmt.Println(err) 89 | res, _ := proc.Interact([]byte(`{"value":{"name":"Mike"}}`)) 90 | fmt.Printf("%s", res) 91 | proc.Stop() 92 | dump(log) 93 | // Output: 94 | // 95 | // { "env": "TEST_HELLO=WORLD TEST_HI=ALL"} 96 | // XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX 97 | // XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX 98 | } 99 | 100 | func ExampleNewExecutor_ack() { 101 | log, _ := ioutil.TempFile("", "log") 102 | proc := NewExecutor(log, log, "_test/hi", m) 103 | err := proc.Start(true) 104 | fmt.Println(err) 105 | proc.Stop() 106 | dump(log) 107 | // Output: 108 | // Command exited abruptly during initialization. 109 | // hi 110 | } 111 | 112 | func ExampleNewExecutor_badack() { 113 | log, _ := ioutil.TempFile("", "log") 114 | proc := NewExecutor(log, log, "_test/badack.sh", m) 115 | err := proc.Start(true) 116 | fmt.Println(err) 117 | proc.Stop() 118 | dump(log) 119 | // Output: 120 | // invalid character 'b' looking for beginning of value 121 | } 122 | 123 | func ExampleNewExecutor_badack2() { 124 | log, _ := ioutil.TempFile("", "log") 125 | proc := NewExecutor(log, log, "_test/badack2.sh", m) 126 | err := proc.Start(true) 127 | fmt.Println(err) 128 | proc.Stop() 129 | dump(log) 130 | // Output: 131 | // The action did not initialize properly. 132 | } 133 | 134 | func ExampleNewExecutor_helloack() { 135 | log, _ := ioutil.TempFile("", "log") 136 | proc := NewExecutor(log, log, "_test/helloack/exec", m) 137 | err := proc.Start(true) 138 | fmt.Println(err) 139 | res, _ := proc.Interact([]byte(`{"value":{"name":"Mike"}}`)) 140 | fmt.Printf("%s", res) 141 | proc.Stop() 142 | dump(log) 143 | // Output: 144 | // 145 | // {"hello": "Mike"} 146 | // msg=hello Mike 147 | // XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX 148 | // XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX 149 | } 150 | -------------------------------------------------------------------------------- /openwhisk/extractor.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package openwhisk 19 | 20 | import ( 21 | "fmt" 22 | "io/ioutil" 23 | "os" 24 | "strconv" 25 | ) 26 | 27 | // higherDir will find the highest numeric name a sub directory has 28 | // 0 if no numeric dir names found 29 | func highestDir(dir string) int { 30 | files, err := ioutil.ReadDir(dir) 31 | if err != nil { 32 | return 0 33 | } 34 | max := 0 35 | for _, file := range files { 36 | n, err := strconv.Atoi(file.Name()) 37 | if err == nil { 38 | if n > max { 39 | max = n 40 | } 41 | } 42 | } 43 | return max 44 | } 45 | 46 | // ExtractAction accept a byte array and write it to a file 47 | // it handles zip files extracting the content 48 | // it stores in a new directory under ./action/XXX/suffix where x is incremented every time 49 | // it returns the file if a file or the directory if it was a zip file 50 | func (ap *ActionProxy) ExtractAction(buf *[]byte, suffix string) (string, error) { 51 | if buf == nil || len(*buf) == 0 { 52 | return "", fmt.Errorf("no file") 53 | } 54 | ap.currentDir++ 55 | newDir := fmt.Sprintf("%s/%d/%s", ap.baseDir, ap.currentDir, suffix) 56 | os.MkdirAll(newDir, 0755) 57 | file := newDir + "/exec" 58 | if IsZip(*buf) { 59 | jar := os.Getenv("OW_SAVE_JAR") 60 | if jar != "" { 61 | jarFile := newDir + "/" + jar 62 | Debug("Extract Action, checking if it is a jar first") 63 | return jarFile, UnzipOrSaveJar(*buf, newDir, jarFile) 64 | } 65 | Debug("Extract Action, assuming a zip") 66 | return file, Unzip(*buf, newDir) 67 | 68 | } else if IsGz(*buf) { 69 | Debug("Extract Action, assuming a tar.gz") 70 | return file, UnTar(*buf, newDir) 71 | } 72 | return file, ioutil.WriteFile(file, *buf, 0755) 73 | } 74 | -------------------------------------------------------------------------------- /openwhisk/filetype.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package openwhisk 19 | 20 | // IsElf checks for a Linux executable 21 | func IsElf(buf []byte) bool { 22 | return len(buf) > 52 && 23 | buf[0] == 0x7F && buf[1] == 0x45 && 24 | buf[2] == 0x4C && buf[3] == 0x46 25 | } 26 | 27 | // IsExe checks for a Windows executable 28 | func IsExe(buf []byte) bool { 29 | return len(buf) > 1 && 30 | buf[0] == 0x4D && buf[1] == 0x5A 31 | } 32 | 33 | // IsMach64 checks for OSX executable 34 | func IsMach64(buf []byte) bool { 35 | return len(buf) > 4 && 36 | buf[0] == 0xcf && buf[1] == 0xfa && 37 | buf[2] == 0xed && buf[3] == 0xfe 38 | } 39 | 40 | // IsBangPath checks for a shell executable 41 | func IsBangPath(buf []byte) bool { 42 | return len(buf) > 2 && 43 | buf[0] == '#' && buf[1] == '!' 44 | } 45 | 46 | // IsExecutable check if it is an executable, according the current runtime 47 | func IsExecutable(buf []byte, runtime string) bool { 48 | Debug("checking executable for %s", runtime) 49 | switch runtime { 50 | case "darwin": 51 | return IsMach64(buf) || IsBangPath(buf) 52 | case "linux": 53 | return IsElf(buf) || IsBangPath(buf) 54 | case "windows": 55 | return IsExe(buf) 56 | default: 57 | return false 58 | } 59 | } 60 | 61 | // IsZip checks if it is a zip file 62 | func IsZip(buf []byte) bool { 63 | return len(buf) > 3 && 64 | buf[0] == 0x50 && buf[1] == 0x4B && 65 | (buf[2] == 0x3 || buf[2] == 0x5 || buf[2] == 0x7) && 66 | (buf[3] == 0x4 || buf[3] == 0x6 || buf[3] == 0x8) 67 | } 68 | 69 | // IsGz checks if the given file is a valid tar.gz file 70 | func IsGz(buf []byte) bool { 71 | // Magic number: The first two bytes are fixed (0x1f and 0x8b), which represent the magic number of a gzip file. 72 | // Compression method: The third byte indicates the compression method used. For gzip files, this is always (deflate). 73 | return len(buf) > 3 && 74 | buf[0] == 0x1f && 75 | buf[1] == 0x8b && 76 | buf[2] == 0x08 77 | } 78 | -------------------------------------------------------------------------------- /openwhisk/filetype_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package openwhisk 18 | 19 | import "fmt" 20 | 21 | var zipFile = []byte{ 22 | 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x60, 0x83, 0x4d, 0x00, 0x00, 23 | } 24 | 25 | var linuxFile = []byte{ 26 | 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 28 | 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 | 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | } 31 | 32 | var darwinFile = []byte{ 33 | 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 34 | } 35 | 36 | var windowsFile = []byte{ 37 | 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 38 | } 39 | 40 | var shellFile = []byte("#!/bin/sh\necho hello\n") 41 | 42 | func Example_filetype() { 43 | fmt.Printf("%t\n%t\n", IsElf(linuxFile), IsElf(zipFile)) 44 | fmt.Printf("%t\n%t\n", IsMach64(darwinFile), IsMach64(zipFile)) 45 | fmt.Printf("%t\n%t\n", IsExe(windowsFile), IsExe(zipFile)) 46 | fmt.Printf("%t\n%t\n", IsZip(zipFile), IsExe(linuxFile)) 47 | fmt.Printf("%t\n%t\n", IsExecutable(linuxFile, "linux"), IsExecutable(zipFile, "linux")) 48 | fmt.Printf("%t\n%t\n", IsExecutable(windowsFile, "windows"), IsExecutable(zipFile, "windows")) 49 | fmt.Printf("%t\n%t\n", IsExecutable(darwinFile, "darwin"), IsExecutable(zipFile, "darwin")) 50 | fmt.Printf("%t\n%t\n%t\n", IsExecutable(shellFile, "darwin"), IsExecutable(shellFile, "linux"), IsExecutable(shellFile, "windows")) 51 | // Output: 52 | // true 53 | // false 54 | // true 55 | // false 56 | // true 57 | // false 58 | // true 59 | // false 60 | // true 61 | // false 62 | // true 63 | // false 64 | // true 65 | // false 66 | // true 67 | // true 68 | // false 69 | 70 | } 71 | -------------------------------------------------------------------------------- /openwhisk/runHandler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package openwhisk 19 | 20 | import ( 21 | "bytes" 22 | "encoding/json" 23 | "fmt" 24 | "io/ioutil" 25 | "net/http" 26 | ) 27 | 28 | // ErrResponse is the response when there are errors 29 | type ErrResponse struct { 30 | Error string `json:"error"` 31 | } 32 | 33 | func sendError(w http.ResponseWriter, code int, cause string) { 34 | errResponse := ErrResponse{Error: cause} 35 | b, err := json.Marshal(errResponse) 36 | if err != nil { 37 | b = []byte("error marshalling error response") 38 | Debug(err.Error()) 39 | } 40 | w.Header().Set("Content-Type", "application/json") 41 | w.WriteHeader(code) 42 | w.Write(b) 43 | w.Write([]byte("\n")) 44 | } 45 | 46 | func (ap *ActionProxy) runHandler(w http.ResponseWriter, r *http.Request) { 47 | 48 | // parse the request 49 | body, err := ioutil.ReadAll(r.Body) 50 | defer r.Body.Close() 51 | if err != nil { 52 | sendError(w, http.StatusBadRequest, fmt.Sprintf("Error reading request body: %v", err)) 53 | return 54 | } 55 | Debug("done reading %d bytes", len(body)) 56 | 57 | // check if you have an action 58 | if ap.theExecutor == nil { 59 | sendError(w, http.StatusInternalServerError, fmt.Sprintf("no action defined yet")) 60 | return 61 | } 62 | // check if the process exited 63 | if ap.theExecutor.Exited() { 64 | sendError(w, http.StatusInternalServerError, fmt.Sprintf("command exited")) 65 | return 66 | } 67 | 68 | // remove newlines 69 | body = bytes.Replace(body, []byte("\n"), []byte(""), -1) 70 | 71 | // execute the action 72 | response, err := ap.theExecutor.Interact(body) 73 | 74 | // check for early termination 75 | if err != nil { 76 | Debug("WARNING! Command exited") 77 | ap.theExecutor = nil 78 | sendError(w, http.StatusBadRequest, fmt.Sprintf("command exited")) 79 | return 80 | } 81 | DebugLimit("received:", response, 120) 82 | 83 | // check if the answer is an object map 84 | var objmap map[string]*json.RawMessage 85 | var objarray []interface{} 86 | err = json.Unmarshal(response, &objmap) 87 | if err != nil { 88 | err = json.Unmarshal(response, &objarray) 89 | if err != nil { 90 | sendError(w, http.StatusBadGateway, "The action did not return a dictionary or array.") 91 | return 92 | } 93 | } 94 | 95 | w.Header().Set("Content-Type", "application/json") 96 | w.Header().Set("Content-Length", fmt.Sprintf("%d", len(response))) 97 | numBytesWritten, err := w.Write(response) 98 | 99 | // flush output 100 | if f, ok := w.(http.Flusher); ok { 101 | f.Flush() 102 | } 103 | 104 | // diagnostic when you have writing problems 105 | if err != nil { 106 | sendError(w, http.StatusInternalServerError, fmt.Sprintf("Error writing response: %v", err)) 107 | return 108 | } 109 | if numBytesWritten != len(response) { 110 | sendError(w, http.StatusInternalServerError, fmt.Sprintf("Only wrote %d of %d bytes to response", numBytesWritten, len(response))) 111 | return 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /openwhisk/tar.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package openwhisk 18 | 19 | import ( 20 | "archive/tar" 21 | "bytes" 22 | "compress/gzip" 23 | "io" 24 | "os" 25 | "path/filepath" 26 | ) 27 | 28 | func openTar(src []byte) (*tar.Reader, error) { 29 | // Create a new bytes.Reader from the input byte slice 30 | reader := bytes.NewReader(src) 31 | 32 | // Create a new gzip.Reader from the bytes.Reader 33 | gzipReader, err := gzip.NewReader(reader) 34 | if err != nil { 35 | return nil, err 36 | } 37 | defer gzipReader.Close() 38 | 39 | // Create a new tar.Reader from the gzip.Reader 40 | tarReader := tar.NewReader(gzipReader) 41 | 42 | return tarReader, nil 43 | } 44 | 45 | func UnTar(src []byte, dest string) error { 46 | r, err := openTar(src) 47 | if err != nil { 48 | return err 49 | } 50 | Debug("open Tar") 51 | os.MkdirAll(dest, 0755) 52 | for { 53 | header, err := r.Next() 54 | switch { 55 | 56 | // if no more files are found return 57 | case err == io.EOF: 58 | return nil 59 | 60 | // return any other error 61 | case err != nil: 62 | return err 63 | 64 | // if the header is nil, just skip it (not sure how this happens) 65 | case header == nil: 66 | continue 67 | } 68 | 69 | // the target location where the dir/file should be created 70 | target := filepath.Join(dest, header.Name) 71 | // isLink := header.FileInfo().Mode()&os.ModeSymlink == os.ModeSymlink 72 | 73 | // the following switch could also be done using fi.Mode(), not sure if there 74 | // a benefit of using one vs. the other. 75 | // fi := header.FileInfo() 76 | 77 | // check the file type 78 | switch header.Typeflag { 79 | 80 | // if its a dir and it doesn't exist create it 81 | case tar.TypeDir: 82 | if _, err := os.Stat(target); err != nil { 83 | if err := os.MkdirAll(target, 0755); err != nil { 84 | return err 85 | } 86 | } 87 | 88 | // if it's a file create it 89 | case tar.TypeReg: 90 | f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)) 91 | if err != nil { 92 | return err 93 | } 94 | 95 | // copy over contents 96 | if _, err := io.Copy(f, r); err != nil { 97 | return err 98 | } 99 | 100 | // manually close here after each file operation; defering would cause each file close 101 | // to wait until all operations have completed. 102 | f.Close() 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /openwhisk/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package openwhisk 18 | 19 | // Version number - internal 20 | var Version = "1.17.1" 21 | -------------------------------------------------------------------------------- /openwhisk/zip.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package openwhisk 18 | 19 | import ( 20 | "archive/zip" 21 | "bytes" 22 | "fmt" 23 | "io" 24 | "io/ioutil" 25 | "log" 26 | "os" 27 | "path/filepath" 28 | "strings" 29 | ) 30 | 31 | func openZip(src []byte) *zip.Reader { 32 | reader := bytes.NewReader(src) 33 | r, err := zip.NewReader(reader, int64(len(src))) 34 | if err != nil { 35 | return nil 36 | } 37 | return r 38 | } 39 | 40 | // UnzipOrSaveJar checks if is is a jar file looking if there is a META-INF folder in it 41 | // if it is a jar file, save it as the file jarFile 42 | // Otherwise unzip the files in the destination dir 43 | func UnzipOrSaveJar(src []byte, dest string, jarFile string) error { 44 | r := openZip(src) 45 | if r == nil { 46 | return fmt.Errorf("not a zip file") 47 | } 48 | for _, f := range r.File { 49 | if f.Name == "META-INF/MANIFEST.MF" { 50 | ioutil.WriteFile(jarFile, src, 0644) 51 | return nil 52 | } 53 | } 54 | return Unzip(src, dest) 55 | } 56 | 57 | // Unzip extracts file and directories in the given destination folder 58 | func Unzip(src []byte, dest string) error { 59 | r := openZip(src) 60 | os.MkdirAll(dest, 0755) 61 | // Closure to address file descriptors issue with all the deferred .Close() methods 62 | extractAndWriteFile := func(f *zip.File) error { 63 | 64 | path := filepath.Join(dest, f.Name) 65 | isLink := f.FileInfo().Mode()&os.ModeSymlink == os.ModeSymlink 66 | 67 | // dir 68 | if f.FileInfo().IsDir() && !isLink { 69 | return os.MkdirAll(path, f.Mode()) 70 | } 71 | 72 | // open file 73 | rc, err := f.Open() 74 | if err != nil { 75 | return err 76 | } 77 | defer rc.Close() 78 | 79 | // link 80 | if isLink { 81 | buf, err := ioutil.ReadAll(rc) 82 | if err != nil { 83 | return err 84 | } 85 | return os.Symlink(string(buf), path) 86 | } 87 | 88 | // file 89 | // eventually create a missing ddir 90 | err = os.MkdirAll(filepath.Dir(path), 0755) 91 | if err != nil { 92 | return err 93 | } 94 | file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) 95 | if err != nil { 96 | return err 97 | } 98 | defer file.Close() 99 | _, err = io.Copy(file, rc) 100 | return err 101 | } 102 | for _, f := range r.File { 103 | err := extractAndWriteFile(f) 104 | if err != nil { 105 | log.Println(err) 106 | } 107 | } 108 | return nil 109 | } 110 | 111 | // Zip a directory 112 | func Zip(dir string) ([]byte, error) { 113 | buf := new(bytes.Buffer) 114 | zwr := zip.NewWriter(buf) 115 | dir = filepath.Clean(dir) 116 | err := filepath.Walk(dir, func(filePath string, info os.FileInfo, err error) error { 117 | 118 | // trim the relevant part of the path 119 | relPath := strings.TrimPrefix(filePath, dir) 120 | if relPath == "" { 121 | return nil 122 | } 123 | relPath = relPath[1:] 124 | if err != nil { 125 | return err 126 | } 127 | 128 | // create a proper entry 129 | isLink := (info.Mode() & os.ModeSymlink) == os.ModeSymlink 130 | header := &zip.FileHeader{ 131 | Name: relPath, 132 | Method: zip.Deflate, 133 | } 134 | if isLink { 135 | header.SetMode(0755 | os.ModeSymlink) 136 | w, err := zwr.CreateHeader(header) 137 | if err != nil { 138 | return err 139 | } 140 | ln, err := os.Readlink(filePath) 141 | if err != nil { 142 | return err 143 | } 144 | w.Write([]byte(ln)) 145 | } else if info.IsDir() { 146 | header.Name = relPath + "/" 147 | header.SetMode(0755) 148 | _, err := zwr.CreateHeader(header) 149 | if err != nil { 150 | return err 151 | } 152 | } else if info.Mode().IsRegular() { 153 | header.SetMode(0755) 154 | w, err := zwr.CreateHeader(header) 155 | if err != nil { 156 | return err 157 | } 158 | fsFile, err := os.Open(filePath) 159 | if err != nil { 160 | return err 161 | } 162 | defer fsFile.Close() 163 | _, err = io.Copy(w, fsFile) 164 | if err != nil { 165 | return err 166 | } 167 | } 168 | return nil 169 | }) 170 | if err != nil { 171 | return nil, err 172 | } 173 | err = zwr.Close() 174 | if err != nil { 175 | return nil, err 176 | } 177 | return buf.Bytes(), nil 178 | } 179 | -------------------------------------------------------------------------------- /openwhisk/zip_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package openwhisk 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "os" 23 | ) 24 | 25 | func Example_zip() { 26 | os.RemoveAll("./action/unzip") 27 | os.Mkdir("./action/unzip", 0755) 28 | buf, err := Zip("_test/pysample") 29 | fmt.Println(err) 30 | err = UnzipOrSaveJar(buf, "./action/unzip", "./action/unzip/exec.jar") 31 | sys("_test/find.sh", "./action/unzip") 32 | fmt.Println(err) 33 | // Output: 34 | // 35 | // ./action/unzip 36 | // ./action/unzip/exec 37 | // ./action/unzip/lib 38 | // ./action/unzip/lib/action 39 | // ./action/unzip/lib/action/__init__.py 40 | // ./action/unzip/lib/action/main.py 41 | // ./action/unzip/lib/exec.py 42 | // 43 | } 44 | func Example_jar() { 45 | os.RemoveAll("./action/unzip") 46 | os.Mkdir("./action/unzip", 0755) 47 | buf, err := Zip("_test/jar") 48 | fmt.Println(err) 49 | err = UnzipOrSaveJar(buf, "./action/unzip", "./action/unzip/exec.jar") 50 | sys("_test/find.sh", "./action/unzip") 51 | fmt.Println(err) 52 | // Output: 53 | // 54 | // ./action/unzip 55 | // ./action/unzip/exec.jar 56 | // 57 | } 58 | 59 | func Example_venv() { 60 | os.RemoveAll("./action/unzip") 61 | os.Mkdir("./action/unzip", 0755) 62 | buf, err := Zip("_test/venv") 63 | fmt.Println(1, err) 64 | err = ioutil.WriteFile("/tmp/appo.zip", buf, 0644) 65 | fmt.Println(2, err) 66 | err = UnzipOrSaveJar(buf, "./action/unzip", "./action/unzip/exec.jar") 67 | sys("bash", "-c", "cd action/unzip/bin && find . -type l -name python && rm ./python") 68 | sys2("bash", "-c", "diff -qr _test/venv action/unzip 2>/dev/null") 69 | fmt.Println(3, err) 70 | // Output: 71 | // 1 72 | // 2 73 | // ./python 74 | // Only in _test/venv/bin: python 75 | // 3 76 | 77 | } 78 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | include 'tests' 19 | 20 | include 'actionloop' 21 | include 'golang1.21' 22 | include 'golang1.22' 23 | include 'golang1.23' 24 | 25 | rootProject.name = 'runtime-golang' 26 | 27 | gradle.ext.openwhisk = [ 28 | version: '1.0.1-SNAPSHOT' 29 | ] 30 | 31 | gradle.ext.scala = [ 32 | version: '2.12.7', 33 | depVersion : '2.12', 34 | compileFlags: ['-feature', '-unchecked', '-deprecation', '-Xfatal-warnings', '-Ywarn-unused-import'] 35 | ] 36 | 37 | gradle.ext.scalafmt = [ 38 | version: '1.5.1', 39 | config: new File(rootProject.projectDir, '.scalafmt.conf') 40 | ] 41 | 42 | gradle.ext.akka = [version : '2.6.12'] 43 | gradle.ext.akka_http = [version : '10.2.4'] 44 | -------------------------------------------------------------------------------- /tests/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | apply plugin: 'scala' 19 | apply plugin: 'eclipse' 20 | compileTestScala.options.encoding = 'UTF-8' 21 | 22 | repositories { 23 | mavenCentral() 24 | mavenLocal() 25 | } 26 | 27 | tasks.withType(Test) { 28 | testLogging { 29 | events "passed", "skipped", "failed" 30 | showStandardStreams = true 31 | exceptionFormat = 'full' 32 | } 33 | outputs.upToDateWhen { false } // force tests to run every time 34 | } 35 | 36 | dependencies { 37 | implementation "junit:junit:4.11" 38 | implementation "org.scala-lang:scala-library:${gradle.scala.version}" 39 | implementation "org.scalatest:scalatest_${gradle.scala.depVersion}:3.0.8" 40 | implementation "org.apache.openwhisk:openwhisk-common:${gradle.openwhisk.version}" 41 | implementation "org.apache.openwhisk:openwhisk-tests:${gradle.openwhisk.version}:tests" 42 | implementation "org.apache.openwhisk:openwhisk-tests:${gradle.openwhisk.version}:test-sources" 43 | implementation group: 'com.typesafe.akka', name: "akka-http2-support_${gradle.scala.depVersion}", version: "${gradle.akka_http.version}" 44 | implementation group: 'com.typesafe.akka', name: "akka-http-xml_${gradle.scala.depVersion}", version: "${gradle.akka_http.version}" 45 | implementation group: 'com.typesafe.akka', name: "akka-discovery_${gradle.scala.depVersion}", version: "${gradle.akka.version}" 46 | implementation group: 'com.typesafe.akka', name: "akka-protobuf_${gradle.scala.depVersion}", version: "${gradle.akka.version}" 47 | implementation group: 'com.typesafe.akka', name: "akka-remote_${gradle.scala.depVersion}", version: "${gradle.akka.version}" 48 | implementation group: 'com.typesafe.akka', name: "akka-cluster_${gradle.scala.depVersion}", version: "${gradle.akka.version}" 49 | } 50 | 51 | tasks.withType(ScalaCompile) { 52 | scalaCompileOptions.additionalParameters = gradle.scala.compileFlags 53 | } 54 | -------------------------------------------------------------------------------- /tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo21Tests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package runtime.actionContainers 18 | 19 | import common.WskActorSystem 20 | import org.junit.runner.RunWith 21 | import org.scalatest.junit.JUnitRunner 22 | 23 | @RunWith(classOf[JUnitRunner]) 24 | class ActionLoopBasicGo21Tests 25 | extends ActionLoopBasicGoTests 26 | with WskActorSystem { 27 | 28 | override lazy val goCompiler = "action-golang-v1.21" 29 | override lazy val image = goCompiler 30 | override lazy val requireAck = true 31 | } 32 | -------------------------------------------------------------------------------- /tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo22Tests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package runtime.actionContainers 18 | 19 | import common.WskActorSystem 20 | import org.junit.runner.RunWith 21 | import org.scalatest.junit.JUnitRunner 22 | 23 | @RunWith(classOf[JUnitRunner]) 24 | class ActionLoopBasicGo22Tests 25 | extends ActionLoopBasicGoTests 26 | with WskActorSystem { 27 | 28 | override lazy val goCompiler = "action-golang-v1.22" 29 | override lazy val image = goCompiler 30 | override lazy val requireAck = true 31 | } 32 | -------------------------------------------------------------------------------- /tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo23Tests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package runtime.actionContainers 18 | 19 | import common.WskActorSystem 20 | import org.junit.runner.RunWith 21 | import org.scalatest.junit.JUnitRunner 22 | 23 | @RunWith(classOf[JUnitRunner]) 24 | class ActionLoopBasicGo23Tests 25 | extends ActionLoopBasicGoTests 26 | with WskActorSystem { 27 | 28 | override lazy val goCompiler = "action-golang-v1.23" 29 | override lazy val image = goCompiler 30 | override lazy val requireAck = true 31 | } 32 | -------------------------------------------------------------------------------- /tests/src/test/scala/runtime/actionContainers/ActionLoopBasicTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package runtime.actionContainers 18 | 19 | import actionContainers.ActionContainer.withContainer 20 | import actionContainers.{ActionContainer, BasicActionRunnerTests} 21 | import common.WskActorSystem 22 | import org.junit.runner.RunWith 23 | import org.scalatest.junit.JUnitRunner 24 | 25 | @RunWith(classOf[JUnitRunner]) 26 | class ActionLoopBasicTests extends BasicActionRunnerTests with WskActorSystem { 27 | 28 | val image = "actionloop-base" 29 | 30 | override def withActionContainer(env: Map[String, String] = Map.empty)( 31 | code: ActionContainer => Unit) = { 32 | withContainer(image, env)(code) 33 | } 34 | 35 | def withActionLoopContainer(code: ActionContainer => Unit) = 36 | withContainer(image)(code) 37 | 38 | behavior of image 39 | 40 | override val testNoSourceOrExec = TestConfig("") 41 | 42 | override val testNotReturningJson = TestConfig("""#!/bin/bash 43 | |read line 44 | |echo '"not json"' >&3 45 | |read line 46 | |""".stripMargin) 47 | 48 | override val testEcho = TestConfig("""|#!/bin/bash 49 | |while read line 50 | |do 51 | | echo "hello stdout" 52 | | echo "hello stderr" >&2 53 | | echo "$line" | jq -c .value >&3 54 | |done 55 | """.stripMargin) 56 | 57 | override val testUnicode = TestConfig( 58 | """|#!/bin/bash 59 | |while read line 60 | |do 61 | | delimiter="$(echo "$line" | jq -r ".value.delimiter")" 62 | | msg="$delimiter ☃ $delimiter" 63 | | echo "$msg" 64 | | echo "{\"winter\": \"$msg\"}" >&3 65 | |done 66 | """.stripMargin) 67 | 68 | // the __OW_API_HOST should already be in the environment 69 | // so it is not expected in/read from the input line 70 | override val testEnv = TestConfig( 71 | """#!/bin/bash 72 | |while read line 73 | |do 74 | | __OW_API_KEY="$(echo "$line" | jq -r .api_key)" 75 | | __OW_NAMESPACE="$(echo "$line" | jq -r .namespace)" 76 | | __OW_ACTIVATION_ID="$(echo "$line" | jq -r .activation_id)" 77 | | __OW_ACTION_NAME="$(echo "$line" | jq -r .action_name)" 78 | | __OW_ACTION_VERSION="$(echo "$line" | jq -r .action_version)" 79 | | __OW_DEADLINE="$(echo "$line" | jq -r .deadline)" 80 | | echo >&3 "{ \ 81 | | \"api_host\": \"$__OW_API_HOST\", \ 82 | | \"api_key\": \"$__OW_API_KEY\", \ 83 | | \"namespace\": \"$__OW_NAMESPACE\", \ 84 | | \"activation_id\": \"$__OW_ACTIVATION_ID\", \ 85 | | \"action_name\": \"$__OW_ACTION_NAME\", \ 86 | | \"action_version\": \"$__OW_ACTION_VERSION\", \ 87 | | \"deadline\": \"$__OW_DEADLINE\" }" 88 | | done 89 | """.stripMargin) 90 | 91 | val echoSh = 92 | """|#!/bin/bash 93 | |while read line 94 | |do echo "$line" | jq -c .value >&3 95 | |done 96 | """.stripMargin 97 | 98 | override val testInitCannotBeCalledMoreThanOnce = TestConfig(echoSh) 99 | 100 | override val testEntryPointOtherThanMain = TestConfig(echoSh, main = "niam") 101 | 102 | override val testLargeInput = TestConfig(echoSh) 103 | } 104 | -------------------------------------------------------------------------------- /tests/src/test/scala/runtime/actionContainers/ActionLoopContainerTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package runtime.actionContainers 19 | 20 | import actionContainers.{ActionContainer, ActionProxyContainerTestUtils} 21 | import actionContainers.ActionContainer.withContainer 22 | import common.WskActorSystem 23 | import org.junit.runner.RunWith 24 | import org.scalatest.junit.JUnitRunner 25 | 26 | import spray.json.{JsObject, JsString} 27 | 28 | @RunWith(classOf[JUnitRunner]) 29 | class ActionLoopContainerTests 30 | extends ActionProxyContainerTestUtils 31 | with WskActorSystem { 32 | 33 | import GoResourceHelpers._ 34 | 35 | val image = "actionloop-base" 36 | 37 | def withActionLoopContainer(code: ActionContainer => Unit) = 38 | withContainer(image)(code) 39 | 40 | behavior of image 41 | 42 | def shCodeHello(main: String) = Seq( 43 | Seq(main) -> 44 | s"""#!/bin/bash 45 | |while read line 46 | |do 47 | | name="$$(echo $$line | jq -r .value.name)" 48 | | if test "$$name" == "" 49 | | then exit 50 | | fi 51 | | echo "name=$$name" 52 | | hello="Hello, $$name" 53 | | echo '{"${main}":"'$$hello'"}' >&3 54 | |done 55 | |""".stripMargin 56 | ) 57 | 58 | private def helloMsg(name: String = "Demo") = 59 | runPayload(JsObject("name" -> JsString(name))) 60 | 61 | private def okMsg(key: String, value: String) = 62 | 200 -> Some(JsObject(key -> JsString(value))) 63 | 64 | it should "run sample with init that does nothing" in { 65 | val (out, err) = withActionLoopContainer { c => 66 | c.init(JsObject())._1 should be(403) 67 | c.run(JsObject())._1 should be(500) 68 | } 69 | } 70 | 71 | it should "deploy a shell script" in { 72 | val script = shCodeHello("main") 73 | val mesg = ExeBuilder.mkBase64Src(script) 74 | withActionLoopContainer { c => 75 | val payload = initPayload(mesg) 76 | c.init(payload)._1 should be(200) 77 | c.run(helloMsg()) should be(okMsg("main", "Hello, Demo")) 78 | } 79 | } 80 | 81 | it should "deploy a zip based script" in { 82 | val scr = ExeBuilder.mkBase64SrcZip(shCodeHello("exec")) 83 | withActionLoopContainer { c => 84 | c.init(initPayload(scr))._1 should be(200) 85 | c.run(helloMsg()) should be(okMsg("exec", "Hello, Demo")) 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/src/test/scala/runtime/actionContainers/ActionLoopGo21ContainerTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package runtime.actionContainers 19 | 20 | import common.WskActorSystem 21 | import org.junit.runner.RunWith 22 | import org.scalatest.junit.JUnitRunner 23 | @RunWith(classOf[JUnitRunner]) 24 | class ActionLoopGo21ContainerTests 25 | extends ActionLoopGoContainerTests 26 | with WskActorSystem { 27 | 28 | override lazy val goCompiler = "action-golang-v1.21" 29 | override lazy val image = goCompiler 30 | 31 | } 32 | -------------------------------------------------------------------------------- /tests/src/test/scala/runtime/actionContainers/ActionLoopGo22ContainerTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package runtime.actionContainers 19 | 20 | import common.WskActorSystem 21 | import org.junit.runner.RunWith 22 | import org.scalatest.junit.JUnitRunner 23 | @RunWith(classOf[JUnitRunner]) 24 | class ActionLoopGo22ContainerTests 25 | extends ActionLoopGoContainerTests 26 | with WskActorSystem { 27 | 28 | override lazy val goCompiler = "action-golang-v1.22" 29 | override lazy val image = goCompiler 30 | 31 | } 32 | -------------------------------------------------------------------------------- /tests/src/test/scala/runtime/actionContainers/ActionLoopGo23ContainerTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package runtime.actionContainers 19 | 20 | import common.WskActorSystem 21 | import org.junit.runner.RunWith 22 | import org.scalatest.junit.JUnitRunner 23 | @RunWith(classOf[JUnitRunner]) 24 | class ActionLoopGo23ContainerTests 25 | extends ActionLoopGoContainerTests 26 | with WskActorSystem { 27 | 28 | override lazy val goCompiler = "action-golang-v1.23" 29 | override lazy val image = goCompiler 30 | 31 | } 32 | --------------------------------------------------------------------------------