├── .asf.yaml ├── .gitattributes ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── .scalafmt.conf ├── CONTRIBUTING.md ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── build.gradle ├── core └── rust1.34 │ ├── CHANGELOG.md │ ├── Dockerfile │ ├── Makefile │ ├── build.gradle │ ├── compile.py │ └── src │ ├── Cargo.lock │ ├── Cargo.toml │ ├── action_loop │ ├── Cargo.toml │ └── src │ │ └── main.rs │ └── actions │ ├── .gitignore │ ├── Cargo.toml │ └── src │ └── lib.rs ├── example └── hello │ ├── .gitignore │ ├── Cargo.toml │ └── src │ └── lib.rs ├── gradle ├── README.md ├── docker.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── tests ├── build.gradle └── src │ └── test │ └── scala │ └── runtime │ └── actionContainers │ └── ActionLoopRustBasicTests.scala └── tools └── invoke.py /.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 Rust supports Apache OpenWhisk functions written in Rust" 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 | - rust 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 | # python files not having the .py extension 23 | tools/cli/wsk text eol=lf 24 | tools/cli/wskadmin text eol=lf 25 | 26 | # bash files not having the .sh extension 27 | tools/vagrant/simple/wsk text eol=lf 28 | gradlew text eol=lf 29 | core/javaAction/proxy/gradlew text eol=lf 30 | tools/vagrant/hello text eol=lf 31 | sdk/docker/client/action text eol=lf 32 | -------------------------------------------------------------------------------- /.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 :core:rust1.34:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=nightly 92 | ./gradlew :core:rust1.34:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT 93 | - name: Push Release Images 94 | if: ${{ env.PUSH_RELEASE == 'true' }} 95 | working-directory: runtime 96 | run: | 97 | RUNTIME=${GITHUB_REF_NAME%@*} 98 | IMAGE_TAG=${GITHUB_REF_NAME##*@} 99 | ./gradlew :core:$RUNTIME:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$IMAGE_TAG 100 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | action/ 2 | results/ 3 | logs/ 4 | out/ 5 | build/ 6 | *.retry 7 | 8 | # Linux 9 | *~ 10 | 11 | # Mac 12 | .DS_Store 13 | 14 | # Gradle 15 | .gradle 16 | !/tools/build/ 17 | 18 | # Python 19 | .ipynb_checkpoints/ 20 | *.pyc 21 | 22 | # NodeJS 23 | node_modules 24 | 25 | # Vagrant 26 | .vagrant* 27 | 28 | # Eclipse 29 | tests/bin/ 30 | **/.project 31 | .settings/ 32 | .classpath 33 | .cache-main 34 | .cache-tests 35 | 36 | # IntelliJ 37 | .idea 38 | *.class 39 | *.iml 40 | 41 | # .zip files must be explicited whitelisted 42 | *.zip 43 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 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 | style = intellij 19 | danglingParentheses = false 20 | maxColumn = 120 21 | docstrings = JavaDoc 22 | rewrite.rules = [SortImports] 23 | project.git = true 24 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 19 | [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0) 20 | 21 | # Contributing to Apache OpenWhisk 22 | 23 | Anyone can contribute to the OpenWhisk project, and we welcome your contributions. 24 | 25 | There are multiple ways to contribute: report bugs, improve the docs, and 26 | contribute code, but you must follow these prerequisites and guidelines: 27 | 28 | - [Contributor License Agreement](#contributor-license-agreement) 29 | - [Raising issues](#raising-issues) 30 | - [Coding Standards](#coding-standards) 31 | 32 | ### Contributor License Agreement 33 | 34 | All contributors must sign and submit an Apache CLA (Contributor License Agreement). 35 | 36 | Instructions on how to do this can be found here: 37 | [http://www.apache.org/licenses/#clas](http://www.apache.org/licenses/#clas) 38 | 39 | Once submitted, you will receive a confirmation email from the Apache Software Foundation (ASF) and be added to 40 | the following list: http://people.apache.org/unlistedclas.html. 41 | 42 | Project committers will use this list to verify pull requests (PRs) come from contributors that have signed a CLA. 43 | 44 | We look forward to your contributions! 45 | 46 | ## Raising issues 47 | 48 | Please raise any bug reports or enhancement requests on the respective project repository's GitHub issue tracker. Be sure to search the 49 | list to see if your issue has already been raised. 50 | 51 | A good bug report is one that make it easy for us to understand what you were trying to do and what went wrong. 52 | Provide as much context as possible, so we can try to recreate the issue. 53 | 54 | A good enhancement request comes with an explanation of what you are trying to do and how that enhancement would help you. 55 | 56 | ### Discussion 57 | 58 | Please use the project's developer email list to engage our community: 59 | [dev@openwhisk.apache.org](dev@openwhisk.apache.org) 60 | 61 | In addition, we provide a "dev" Slack team channel for conversations at: 62 | https://openwhisk-team.slack.com/messages/dev/ 63 | 64 | ### Coding standards 65 | 66 | Please ensure you follow the coding standards used throughout the existing 67 | code base. Some basic rules include: 68 | 69 | - all files must have the Apache license in the header. 70 | - all PRs must have passing builds for all operating systems. 71 | - 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. 72 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | ======================================================================== 205 | Apache License 2.0 206 | ======================================================================== 207 | 208 | This product bundles the files gradlew and gradlew.bat from Gradle v5.5 209 | which are distributed under the Apache License, Version 2.0. 210 | For details see ./gradlew and ./gradlew.bat. 211 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | Apache OpenWhisk Runtime Rust 2 | Copyright 2016-2021 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 Runtime for Rust 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-rust/actions/workflows/ci.yaml/badge.svg)](https://github.com/apache/openwhisk-runtime-rust/actions/workflows/ci.yaml) 23 | 24 | ### Give it a try today 25 | To use as a Docker action: 26 | 27 | ``` 28 | wsk action update myAction my_action.rs --docker openwhisk/action-rust-v1.34 29 | ``` 30 | 31 | The file `my_action.rs` looks like: 32 | 33 | ``` 34 | extern crate serde_json; 35 | 36 | use serde_derive::{Deserialize, Serialize}; 37 | use serde_json::{Error, Value}; 38 | 39 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 40 | struct Input { 41 | #[serde(default = "stranger")] 42 | name: String, 43 | } 44 | 45 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 46 | struct Output { 47 | body: String, 48 | } 49 | 50 | fn stranger() -> String { 51 | "stranger".to_string() 52 | } 53 | 54 | pub fn main(args: Value) -> Result { 55 | let input: Input = serde_json::from_value(args)?; 56 | let output = Output { 57 | body: format!("Hello, {}", input.name), 58 | }; 59 | serde_json::to_value(output) 60 | } 61 | ``` 62 | 63 | The action is mainly composed by a `main` function that accepts a JSON `serdes Value` as input and returns a `Result` including a JSON `serde Value`. 64 | 65 | For the return result, not only support `A JSON serde Value` but also support `Array serde Value` 66 | 67 | So a simple `hello array` funtion would be: 68 | 69 | ```rust 70 | extern crate serde_json; 71 | 72 | use serde_derive::{Deserialize, Serialize}; 73 | use serde_json::{Error, Value}; 74 | 75 | 76 | pub fn main(args: Value) -> Result { 77 | let output = ["a", "b"]; 78 | serde_json::to_value(output) 79 | } 80 | ``` 81 | 82 | And support array result for sequence action as well, the first action's array result can be used as next action's input parameter. 83 | 84 | So the function can be: 85 | 86 | ```rust 87 | extern crate serde_json; 88 | 89 | use serde_derive::{Deserialize, Serialize}; 90 | use serde_json::{Error, Value}; 91 | 92 | 93 | pub fn main(args: Value) -> Result { 94 | let inputParam = args.as_array(); 95 | let defaultOutput = ["c", "d"]; 96 | match inputParam { 97 | None => serde_json::to_value(defaultOutput), 98 | Some(x) => serde_json::to_value(x), 99 | } 100 | } 101 | ``` 102 | ### Managing dependencies 103 | 104 | If your action needs external dependencies, you need to provide a zip file including your source, and your cargo file with all your dependencies. The folder structure is the following: 105 | ``` 106 | |- Cargo.toml 107 | |- src 108 | |- lib.rs 109 | ``` 110 | Here is an example of a `Cargo.toml` file 111 | ``` 112 | [package] 113 | name = "actions" 114 | version = "0.1.0" 115 | authors = ["John Doe "] 116 | edition = "2018" 117 | 118 | [dependencies] 119 | serde_json = "1.0" 120 | serde = "1.0" 121 | serde_derive = "1.0" 122 | ``` 123 | Once you have all your code zipped in a file with the showed folder structure you can generate your action with the following command: 124 | ``` 125 | wsk action create yourAction /full_path_to/yourCode.zip --docker openwhisk/action-rust-v1.34 126 | ``` 127 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /core/rust1.34/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 19 | 20 | # Rust OpenWhisk Runtime Container 21 | 22 | ## 1.3.0 23 | - Build actionloop from 1.16@1.18.0 (#33) 24 | - Update Akka versions (#33) 25 | 26 | ## 1.2.0 27 | - Build proxy from openwhisk-runtime-go 1.17.0 release 28 | 29 | ## 1.1.0 30 | - Move from golang:1.12 to golang:1.15 to build the runtime proxy. 31 | - Build proxy from openwhisk-runtime-go 1.16.0 release 32 | 33 | ## 1.0.0 34 | - Initial release 35 | -------------------------------------------------------------------------------- /core/rust1.34/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 | # build go proxy from source 19 | FROM golang:1.22 AS builder_source 20 | ARG GO_PROXY_GITHUB_USER=apache 21 | ARG GO_PROXY_GITHUB_BRANCH=master 22 | RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} \ 23 | https://github.com/${GO_PROXY_GITHUB_USER}/openwhisk-runtime-go /src ;\ 24 | cd /src ; env GO111MODULE=on CGO_ENABLED=0 go build main/proxy.go && \ 25 | mv proxy /bin/proxy 26 | 27 | # or build it from a release 28 | FROM golang:1.23 AS builder_release 29 | ARG GO_PROXY_RELEASE_VERSION=1.23@1.25.0 30 | RUN curl -sL \ 31 | https://github.com/apache/openwhisk-runtime-go/archive/{$GO_PROXY_RELEASE_VERSION}.tar.gz\ 32 | | tar xzf -\ 33 | && cd openwhisk-runtime-go-*/main\ 34 | && GO111MODULE=on CGO_ENABLED=0 go build -o /bin/proxy 35 | 36 | FROM rust:1.34 37 | 38 | # select the builder to use 39 | ARG GO_PROXY_BUILD_FROM=release 40 | 41 | COPY --from=builder_source /bin/proxy /bin/proxy_source 42 | COPY --from=builder_release /bin/proxy /bin/proxy_release 43 | RUN mv /bin/proxy_${GO_PROXY_BUILD_FROM} /bin/proxy 44 | 45 | RUN mkdir -p /action 46 | ADD compile.py /bin/compile.py 47 | ADD src /usr/src 48 | RUN cd /usr/src ; cargo build 49 | ENV PYTHONIOENCODING=utf8 50 | ENV OW_COMPILER=/bin/compile.py 51 | WORKDIR /action 52 | ENTRYPOINT ["/bin/proxy"] 53 | -------------------------------------------------------------------------------- /core/rust1.34/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 | USER=docker.io/openwhisk 19 | IMAGE=action-rust-v1.34 20 | 21 | .PHONY: build 22 | 23 | build: 24 | docker build -t $(USER)/$(IMAGE) . 25 | 26 | devel: build 27 | docker run -ti -p 8080:8080 --entrypoint=bash \ 28 | -v $(PWD):/mnt -e OW_COMPILER=/mnt/compile.py \ 29 | $(USER)/$(IMAGE) 30 | 31 | push: build 32 | docker login 33 | docker push $(USER)/$(IMAGE) 34 | -------------------------------------------------------------------------------- /core/rust1.34/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-rust-v1.34' 19 | apply from: '../../gradle/docker.gradle' 20 | -------------------------------------------------------------------------------- /core/rust1.34/compile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Rust Action Builder 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 | from __future__ import print_function 22 | import os, sys, codecs, subprocess 23 | from os.path import abspath, exists, dirname 24 | import time 25 | import shutil 26 | 27 | ## utils 28 | # write a file creating intermediate directories 29 | def write_file(file, body): 30 | os.makedirs(dirname(file), mode=0o755, exist_ok=True) 31 | with open(file, mode="w", encoding="utf-8") as f: 32 | f.write(body) 33 | 34 | # copy a file eventually replacing a substring 35 | def copy_replace(src, dst, match=None, replacement=""): 36 | with codecs.open(src, 'r', 'utf-8') as s: 37 | body = s.read() 38 | if match: 39 | body = body.replace(match, replacement) 40 | write_file(dst, body) 41 | 42 | ## cargo 43 | cargo_action = """[package] 44 | name = "actions" 45 | version = "0.1.0" 46 | authors = ["Roberto Diaz "] 47 | edition = "2018" 48 | 49 | [dependencies] 50 | serde_json = "1.0" 51 | serde = "1.0" 52 | serde_derive = "1.0" 53 | """ 54 | 55 | def build(tgt_dir): 56 | # support RELEASE 57 | cmd = ["cargo", "build"] 58 | bin_dir = "debug" 59 | if "RELEASE" in os.environ: 60 | cmd += "--release" 61 | bin_dir = "release" 62 | env = { 63 | "CARGO_HOME": "/usr/local/cargo", 64 | "PATH": "/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 65 | "RUSTUP_HOME": "/usr/local/rustup" 66 | } 67 | p = subprocess.Popen(cmd, 68 | stdout=subprocess.PIPE, 69 | stderr=subprocess.PIPE, 70 | cwd="/usr/src", env=env) 71 | (o, e) = p.communicate() 72 | if isinstance(o, bytes): o = o.decode('utf-8') 73 | if isinstance(e, bytes): e = e.decode('utf-8') 74 | if p.returncode != 0: 75 | sys.stdout.write(o) 76 | sys.stdout.write(e) 77 | else: 78 | shutil.move( 79 | "/usr/src/target/%s/action_loop" % bin_dir, 80 | "%s/exec" % tgt_dir) 81 | 82 | def sources(main, src_dir): 83 | # move away the action dir and replace with the new 84 | tmpname = str(int(time.time())) 85 | shutil.move("/usr/src/actions", "/usr/src/src%s" % tmpname) 86 | shutil.move(src_dir, "/usr/src/actions") 87 | 88 | # move exec in the right place 89 | src_file = "/usr/src/actions/exec" 90 | if exists(src_file): 91 | os.makedirs("/usr/src/actions/src", mode=0o755, exist_ok=True) 92 | copy_replace(src_file, "/usr/src/actions/src/lib.rs") 93 | 94 | # add a cargo.toml if needed 95 | cargo_action_file = "/usr/src/actions/Cargo.toml" 96 | if not exists(cargo_action_file): 97 | write_file(cargo_action_file, cargo_action) 98 | 99 | # write the boilerplate in a temp dir 100 | launcher = "/usr/src/action_loop/tmp%s" % tmpname 101 | shutil.move("/usr/src/action_loop/src/main.rs", launcher) 102 | copy_replace(launcher, "/usr/src/action_loop/src/main.rs", 103 | "use actions::main as actionMain;", 104 | "use actions::%s as actionMain;" % main ) 105 | 106 | if __name__ == '__main__': 107 | if len(sys.argv) < 4: 108 | sys.stdout.write("usage: \n") 109 | sys.stdout.flush() 110 | sys.exit(1) 111 | sources(sys.argv[1], abspath(sys.argv[2])) 112 | build(abspath(sys.argv[3])) 113 | sys.stdout.flush() 114 | sys.stderr.flush() 115 | -------------------------------------------------------------------------------- /core/rust1.34/src/Cargo.lock: -------------------------------------------------------------------------------- 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]] 18 | name = "action_loop" 19 | version = "0.1.0" 20 | dependencies = [ 21 | "actions 0.1.0", 22 | "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "actions" 30 | version = "0.1.0" 31 | dependencies = [ 32 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 33 | ] 34 | 35 | [[package]] 36 | name = "itoa" 37 | version = "0.4.3" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | 40 | [[package]] 41 | name = "libc" 42 | version = "0.2.49" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | 45 | [[package]] 46 | name = "proc-macro2" 47 | version = "0.4.27" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | dependencies = [ 50 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 51 | ] 52 | 53 | [[package]] 54 | name = "quote" 55 | version = "0.6.11" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | dependencies = [ 58 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 59 | ] 60 | 61 | [[package]] 62 | name = "ryu" 63 | version = "0.2.7" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | 66 | [[package]] 67 | name = "serde" 68 | version = "1.0.89" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | 71 | [[package]] 72 | name = "serde_derive" 73 | version = "1.0.89" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | dependencies = [ 76 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 77 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 78 | "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", 79 | ] 80 | 81 | [[package]] 82 | name = "serde_json" 83 | version = "1.0.39" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | dependencies = [ 86 | "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 87 | "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 88 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 89 | ] 90 | 91 | [[package]] 92 | name = "syn" 93 | version = "0.15.27" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | dependencies = [ 96 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 97 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 98 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 99 | ] 100 | 101 | [[package]] 102 | name = "unicode-xid" 103 | version = "0.1.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | 106 | [metadata] 107 | "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 108 | "checksum libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)" = "413f3dfc802c5dc91dc570b05125b6cda9855edfaa9825c9849807876376e70e" 109 | "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" 110 | "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 111 | "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" 112 | "checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" 113 | "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" 114 | "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" 115 | "checksum syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)" = "525bd55255f03c816e5d7f615587bd13030c7103354fadb104993dcee6a788ec" 116 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 117 | -------------------------------------------------------------------------------- /core/rust1.34/src/Cargo.toml: -------------------------------------------------------------------------------- 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 | [workspace] 18 | 19 | members = [ 20 | "action_loop", 21 | "actions", 22 | ] 23 | -------------------------------------------------------------------------------- /core/rust1.34/src/action_loop/Cargo.toml: -------------------------------------------------------------------------------- 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] 18 | name = "action_loop" 19 | version = "0.1.0" 20 | authors = ["Roberto Diaz "] 21 | edition = "2018" 22 | 23 | [dependencies] 24 | serde = "1.0" 25 | serde_derive = "1.0" 26 | serde_json = "1.0" 27 | libc = "0.2.49" 28 | actions = { path = "../actions" } 29 | -------------------------------------------------------------------------------- /core/rust1.34/src/action_loop/src/main.rs: -------------------------------------------------------------------------------- 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 | use actions::main as actionMain; 19 | 20 | use serde_derive::Deserialize; 21 | use serde_json::{Error, Value}; 22 | use std::{ 23 | collections::HashMap, 24 | env, 25 | fs::File, 26 | io::{stderr, stdin, stdout, BufRead, Write}, 27 | os::unix::io::FromRawFd, 28 | }; 29 | 30 | #[derive(Debug, Clone, PartialEq, Deserialize)] 31 | struct Input { 32 | value: Value, 33 | #[serde(flatten)] 34 | environment: HashMap, 35 | } 36 | 37 | fn log_error(fd3: &mut File, error: Error) { 38 | writeln!(fd3, "{{\"error\":\"{}\"}}\n", error).expect("Error writing on fd3"); 39 | eprintln!("error: {}", error); 40 | } 41 | 42 | fn main() { 43 | let mut fd3 = unsafe { File::from_raw_fd(3) }; 44 | let stdin = stdin(); 45 | for line in stdin.lock().lines() { 46 | let buffer: String = line.expect("Error reading line"); 47 | let parsed_input: Result = serde_json::from_str(&buffer); 48 | match parsed_input { 49 | Ok(input) => { 50 | for (key, val) in input.environment { 51 | if let Some(string_value) = val.as_str() { 52 | env::set_var(format!("__OW_{}", key.to_uppercase()), string_value); 53 | } else { 54 | env::set_var(format!("__OW_{}", key.to_uppercase()), val.to_string()); 55 | }; 56 | } 57 | match actionMain(input.value) { 58 | Ok(action_result) => match serde_json::to_string(&action_result) { 59 | Ok(response) => { 60 | writeln!(&mut fd3, "{}", response).expect("Error writing on fd3") 61 | } 62 | Err(err) => log_error(&mut fd3, err), 63 | }, 64 | Err(err) => { 65 | log_error(&mut fd3, err); 66 | } 67 | } 68 | } 69 | Err(err) => { 70 | log_error(&mut fd3, err); 71 | } 72 | } 73 | stdout().flush().expect("Error flushing stdout"); 74 | stderr().flush().expect("Error flushing stderr"); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /core/rust1.34/src/actions/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /core/rust1.34/src/actions/Cargo.toml: -------------------------------------------------------------------------------- 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] 18 | name = "actions" 19 | version = "0.1.0" 20 | authors = ["Roberto Diaz "] 21 | edition = "2018" 22 | 23 | [dependencies] 24 | serde_json = "1.0" 25 | serde = "1.0" 26 | serde_derive = "1.0" 27 | 28 | 29 | -------------------------------------------------------------------------------- /core/rust1.34/src/actions/src/lib.rs: -------------------------------------------------------------------------------- 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 | extern crate serde_json; 19 | 20 | use serde_derive::{Deserialize, Serialize}; 21 | use serde_json::{Error, Value}; 22 | 23 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 24 | struct Input { 25 | #[serde(default = "stranger")] 26 | name: String, 27 | } 28 | 29 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 30 | struct Output { 31 | greeting: String, 32 | } 33 | 34 | fn stranger() -> String { 35 | "stranger".to_string() 36 | } 37 | 38 | pub fn main(args: Value) -> Result { 39 | let input: Input = serde_json::from_value(args)?; 40 | let output = Output { 41 | greeting: format!("Hello, {}", input.name), 42 | }; 43 | serde_json::to_value(output) 44 | } 45 | -------------------------------------------------------------------------------- /example/hello/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,rust 3 | # Edit at https://www.gitignore.io/?templates=osx,rust 4 | 5 | ### OSX ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | # Thumbnails 15 | ._* 16 | 17 | # Files that might appear in the root of a volume 18 | .DocumentRevisions-V100 19 | .fseventsd 20 | .Spotlight-V100 21 | .TemporaryItems 22 | .Trashes 23 | .VolumeIcon.icns 24 | .com.apple.timemachine.donotpresent 25 | 26 | # Directories potentially created on remote AFP share 27 | .AppleDB 28 | .AppleDesktop 29 | Network Trash Folder 30 | Temporary Items 31 | .apdisk 32 | 33 | ### Rust ### 34 | # Generated by Cargo 35 | # will have compiled files and executables 36 | /target/ 37 | 38 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 39 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 40 | Cargo.lock 41 | 42 | # These are backup files generated by rustfmt 43 | **/*.rs.bk 44 | 45 | # End of https://www.gitignore.io/api/osx,rust -------------------------------------------------------------------------------- /example/hello/Cargo.toml: -------------------------------------------------------------------------------- 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] 18 | name = "actions" 19 | version = "0.1.0" 20 | authors = ["Roberto Diaz "] 21 | edition = "2018" 22 | 23 | [dependencies] 24 | serde_json = "1.0" 25 | serde = "1.0" 26 | serde_derive = "1.0" 27 | -------------------------------------------------------------------------------- /example/hello/src/lib.rs: -------------------------------------------------------------------------------- 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 | extern crate serde_json; 19 | 20 | use serde_derive::{Deserialize, Serialize}; 21 | use serde_json::{Error, Value}; 22 | 23 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 24 | struct Input { 25 | #[serde(default = "stranger")] 26 | name: String, 27 | } 28 | 29 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 30 | struct Output { 31 | greeting: String, 32 | } 33 | 34 | fn stranger() -> String { 35 | "stranger".to_string() 36 | } 37 | 38 | pub fn main(args: Value) -> Result { 39 | let input: Input = serde_json::from_value(args)?; 40 | let output = Output { 41 | greeting: format!("Hello, {}", input.name), 42 | }; 43 | serde_json::to_value(output) 44 | } 45 | -------------------------------------------------------------------------------- /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/docker.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 | import groovy.time.* 19 | 20 | /** 21 | * Utility to build docker images based in gradle projects 22 | * 23 | * This extends gradle's 'application' plugin logic with a 'distDocker' task which builds 24 | * a docker image from the Dockerfile of the project that applies this file. The image 25 | * is automatically tagged and pushed if a tag and/or a registry is given. 26 | * 27 | * Parameters that can be set on project level: 28 | * - dockerImageName (required): The name of the image to build (e.g. controller) 29 | * - dockerRegistry (optional): The registry to push to 30 | * - dockerImageTag (optional, default 'latest'): The tag for the image 31 | * - dockerImagePrefix (optional, default 'whisk'): The prefix for the image, 32 | * 'controller' becomes 'whisk/controller' per default 33 | * - dockerTimeout (optional, default 840): Timeout for docker operations in seconds 34 | * - dockerRetries (optional, default 3): How many times to retry docker operations 35 | * - dockerBinary (optional, default 'docker'): The binary to execute docker commands 36 | * - dockerBuildArgs (options, default ''): Project specific custom docker build arguments 37 | * - dockerHost (optional): The docker host to run commands on, default behaviour is 38 | * docker's own DOCKER_HOST environment variable 39 | */ 40 | 41 | ext { 42 | dockerRegistry = project.hasProperty('dockerRegistry') ? dockerRegistry + '/' : '' 43 | dockerImageTag = project.hasProperty('dockerImageTag') ? dockerImageTag : 'latest' 44 | dockerImagePrefix = project.hasProperty('dockerImagePrefix') ? dockerImagePrefix : 'whisk' 45 | dockerTimeout = project.hasProperty('dockerTimeout') ? dockerTimeout.toInteger() : 840 46 | dockerRetries = project.hasProperty('dockerRetries') ? dockerRetries.toInteger() : 3 47 | dockerBinary = project.hasProperty('dockerBinary') ? [dockerBinary] : ['docker'] 48 | dockerBuildArg = ['build'] 49 | } 50 | ext.dockerTaggedImageName = dockerRegistry + dockerImagePrefix + '/' + dockerImageName + ':' + dockerImageTag 51 | 52 | if(project.hasProperty('dockerHost')) { 53 | dockerBinary += ['--host', project.dockerHost] 54 | } 55 | 56 | if(project.hasProperty('dockerBuildArgs')) { 57 | dockerBuildArgs.split(' ').each { arg -> 58 | dockerBuildArg += ['--build-arg', arg] 59 | } 60 | } 61 | 62 | task distDocker { 63 | doLast { 64 | def start = new Date() 65 | def cmd = dockerBinary + dockerBuildArg + ['-t', dockerImageName, project.buildscript.sourceFile.getParentFile().getAbsolutePath()] 66 | retry(cmd, dockerRetries, dockerTimeout) 67 | println("Building '${dockerImageName}' took ${TimeCategory.minus(new Date(), start)}") 68 | } 69 | } 70 | task tagImage { 71 | doLast { 72 | def versionString = (dockerBinary + ['-v']).execute().text 73 | def matched = (versionString =~ /(\d+)\.(\d+)\.(\d+)/) 74 | 75 | def major = matched[0][1] as int 76 | def minor = matched[0][2] as int 77 | 78 | def dockerCmd = ['tag'] 79 | if(major == 1 && minor < 12) { 80 | dockerCmd += ['-f'] 81 | } 82 | retry(dockerBinary + dockerCmd + [dockerImageName, dockerTaggedImageName], dockerRetries, dockerTimeout) 83 | } 84 | } 85 | 86 | task pushImage { 87 | doLast { 88 | def cmd = dockerBinary + ['push', dockerTaggedImageName] 89 | retry(cmd, dockerRetries, dockerTimeout) 90 | } 91 | } 92 | pushImage.dependsOn tagImage 93 | pushImage.onlyIf { dockerRegistry != '' } 94 | distDocker.finalizedBy pushImage 95 | 96 | def retry(cmd, retries, timeout) { 97 | println("${new Date()}: Executing '${cmd.join(" ")}'") 98 | def proc = cmd.execute() 99 | proc.consumeProcessOutput(System.out, System.err) 100 | proc.waitForOrKill(timeout * 1000) 101 | if(proc.exitValue() != 0) { 102 | def message = "${new Date()}: Command '${cmd.join(" ")}' failed with exitCode ${proc.exitValue()}" 103 | if(proc.exitValue() == 143) { // 143 means the process was killed (SIGTERM signal) 104 | message = "${new Date()}: Command '${cmd.join(" ")}' was killed after ${timeout} seconds" 105 | } 106 | 107 | if(retries > 1) { 108 | println("${message}, ${retries-1} retries left, retrying...") 109 | retry(cmd, retries-1, timeout) 110 | } 111 | else { 112 | println("${message}, no more retries left, aborting...") 113 | throw new GradleException(message) 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/openwhisk-runtime-rust/c21413d483dcb69f490de61e6c0a81993651df29/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 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip 20 | zipStoreBase=GRADLE_USER_HOME 21 | zipStorePath=wrapper/dists 22 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://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 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /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 Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /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 | include 'core:rust1.34' 20 | 21 | rootProject.name = 'runtime-rust' 22 | 23 | gradle.ext.openwhisk = [ 24 | version: '1.0.1-SNAPSHOT' 25 | ] 26 | 27 | gradle.ext.scala = [ 28 | version: '2.12.7', 29 | depVersion : '2.12', 30 | compileFlags: ['-feature', '-unchecked', '-deprecation', '-Xfatal-warnings', '-Ywarn-unused-import'] 31 | ] 32 | 33 | gradle.ext.scalafmt = [ 34 | version: '1.5.1', 35 | config: new File(rootProject.projectDir, '.scalafmt.conf') 36 | ] 37 | 38 | gradle.ext.akka = [version : '2.6.12'] 39 | gradle.ext.akka_http = [version : '10.2.4'] 40 | -------------------------------------------------------------------------------- /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/ActionLoopRustBasicTests.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 | import spray.json.{JsArray, JsObject, JsString} 25 | 26 | @RunWith(classOf[JUnitRunner]) 27 | class ActionLoopRustBasicTests extends BasicActionRunnerTests with WskActorSystem { 28 | 29 | val image = "action-rust-v1.34" 30 | 31 | override def withActionContainer(env: Map[String, String] = Map.empty)(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("", skipTest = true) 43 | 44 | override val testEcho = 45 | TestConfig("""|extern crate serde_json; 46 | |use serde_json::{Error, Value}; 47 | |pub fn main(args: Value) -> Result { 48 | | println!("hello stdout"); 49 | | eprintln!("hello stderr"); 50 | | Ok(args) 51 | |} 52 | """.stripMargin) 53 | val snowman = """\""" + """u{2603}""" 54 | val space = """\""" + """u{0020}""" 55 | override val testUnicode = 56 | TestConfig(raw"""|extern crate serde_json; 57 | |use serde_derive::{Deserialize, Serialize}; 58 | |use serde_json::{Error, Value}; 59 | |#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 60 | |struct Input { 61 | | delimiter: String, 62 | |} 63 | |#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 64 | |struct Output { 65 | | winter: String, 66 | |} 67 | |pub fn main(args: Value) -> Result { 68 | | let input: Input = serde_json::from_value(args)?; 69 | | let msg = format!("{} {} {}", input.delimiter,'☃',input.delimiter); 70 | | println!("{}", msg); 71 | | let output = Output { 72 | | winter: msg, 73 | | }; 74 | | serde_json::to_value(output) 75 | |} 76 | """.stripMargin) 77 | 78 | override val testEnv = 79 | TestConfig("""|extern crate serde_json; 80 | |use serde_derive::{Deserialize, Serialize}; 81 | |use serde_json::{Error, Value}; 82 | |use std::env; 83 | |use std::env::VarError; 84 | |#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 85 | |struct Output { 86 | | #[serde(skip_serializing_if = "Option::is_none")] 87 | | api_host:Option, 88 | | #[serde(skip_serializing_if = "Option::is_none")] 89 | | api_key: Option, 90 | | #[serde(skip_serializing_if = "Option::is_none")] 91 | | namespace: Option, 92 | | #[serde(skip_serializing_if = "Option::is_none")] 93 | | action_name: Option, 94 | | #[serde(skip_serializing_if = "Option::is_none")] 95 | | action_version: Option, 96 | | #[serde(skip_serializing_if = "Option::is_none")] 97 | | activation_id: Option, 98 | | #[serde(skip_serializing_if = "Option::is_none")] 99 | | deadline: Option, 100 | |} 101 | |pub fn main(_args: Value) -> Result { 102 | | let output = Output { 103 | | api_host: env::var("__OW_API_HOST").ok(), 104 | | api_key: env::var("__OW_API_KEY").ok(), 105 | | namespace: env::var("__OW_NAMESPACE").ok(), 106 | | action_name: env::var("__OW_ACTION_NAME").ok(), 107 | | action_version: env::var("__OW_ACTION_VERSION").ok(), 108 | | activation_id: env::var("__OW_ACTIVATION_ID").ok(), 109 | | deadline: env::var("__OW_DEADLINE").ok(), 110 | | }; 111 | | serde_json::to_value(output) 112 | |} 113 | """.stripMargin) 114 | 115 | override val testInitCannotBeCalledMoreThanOnce = 116 | TestConfig("""|extern crate serde_json; 117 | |use serde_json::{Error, Value}; 118 | |pub fn main(args: Value) -> Result { 119 | | Ok(args) 120 | |} 121 | """.stripMargin) 122 | 123 | override val testEntryPointOtherThanMain = 124 | TestConfig( 125 | """|extern crate serde_json; 126 | |use serde_json::{Error, Value}; 127 | |pub fn naim(args: Value) -> Result { 128 | | Ok(args) 129 | |} 130 | """.stripMargin, 131 | main = "naim") 132 | 133 | override val testLargeInput = 134 | TestConfig("""|extern crate serde_json; 135 | |use serde_json::{Error, Value}; 136 | |pub fn main(args: Value) -> Result { 137 | | Ok(args) 138 | |} 139 | """.stripMargin) 140 | 141 | it should "support return array result" in { 142 | val (out, err) = withActionLoopContainer { c => 143 | val code = """ 144 | |extern crate serde_json; 145 | | 146 | |use serde_derive::{Deserialize, Serialize}; 147 | |use serde_json::{Error, Value}; 148 | | 149 | | 150 | |pub fn main(args: Value) -> Result { 151 | | let output = ["a", "b"]; 152 | | serde_json::to_value(output) 153 | |} 154 | """.stripMargin 155 | 156 | val (initCode, _) = c.init(initPayload(code)) 157 | 158 | initCode should be(200) 159 | 160 | val (runCode, runRes) = c.runForJsArray(runPayload(JsObject())) 161 | runCode should be(200) 162 | runRes shouldBe Some(JsArray(JsString("a"), JsString("b"))) 163 | } 164 | } 165 | 166 | it should "support array as input param" in { 167 | val (out, err) = withActionLoopContainer { c => 168 | val code = """ 169 | |extern crate serde_json; 170 | | 171 | |use serde_derive::{Deserialize, Serialize}; 172 | |use serde_json::{Error, Value}; 173 | | 174 | | 175 | |pub fn main(args: Value) -> Result { 176 | | let inputParam = args.as_array(); 177 | | let defaultOutput = ["c", "d"]; 178 | | match inputParam { 179 | | None => serde_json::to_value(defaultOutput), 180 | | Some(x) => serde_json::to_value(x), 181 | | } 182 | |} 183 | """.stripMargin 184 | 185 | val (initCode, _) = c.init(initPayload(code)) 186 | 187 | initCode should be(200) 188 | 189 | val (runCode, runRes) = c.runForJsArray(runPayload(JsArray(JsString("a"), JsString("b")))) 190 | runCode should be(200) 191 | runRes shouldBe Some(JsArray(JsString("a"), JsString("b"))) 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /tools/invoke.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Executable Python script for testing the action proxy. 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 | This script is useful for testing the action proxy (or its derivatives) 21 | by simulating invoker interactions. Use it in combination with 22 | docker run which starts up the action proxy. 23 | Example: 24 | docker run -i -t -p 8080:8080 dockerskeleton # locally built images may be referenced without a tag 25 | ./invoke.py init 26 | ./invoke.py run '{"some":"json object as a string"}' 27 | 28 | For additional help, try ./invoke.py -h 29 | """ 30 | 31 | import os 32 | import re 33 | import sys 34 | import json 35 | import base64 36 | import requests 37 | import codecs 38 | import argparse 39 | try: 40 | import argcomplete 41 | except ImportError: 42 | argcomplete = False 43 | 44 | def main(): 45 | try: 46 | args = parseArgs() 47 | exitCode = { 48 | 'init' : init, 49 | 'run' : run 50 | }[args.cmd](args) 51 | except Exception as e: 52 | print(e) 53 | exitCode = 1 54 | sys.exit(exitCode) 55 | 56 | def dockerHost(): 57 | dockerHost = 'localhost' 58 | if 'DOCKER_HOST' in os.environ: 59 | try: 60 | dockerHost = re.compile('tcp://(.*):[\d]+').findall(os.environ['DOCKER_HOST'])[0] 61 | except Exception: 62 | print('cannot determine docker host from %s' % os.environ['DOCKER_HOST']) 63 | sys.exit(-1) 64 | return dockerHost 65 | 66 | def containerRoute(args, path): 67 | return 'http://%s:%s/%s' % (args.host, args.port, path) 68 | 69 | def parseArgs(): 70 | parser = argparse.ArgumentParser(description='initialize and run an OpenWhisk action container') 71 | parser.add_argument('-v', '--verbose', help='verbose output', action='store_true') 72 | parser.add_argument('--host', help='action container host', default=dockerHost()) 73 | parser.add_argument('-p', '--port', help='action container port number', default=8080, type=int) 74 | 75 | subparsers = parser.add_subparsers(title='available commands', dest='cmd') 76 | 77 | initmenu = subparsers.add_parser('init', help='initialize container with src or zip/tgz file') 78 | initmenu.add_argument('-b', '--binary', help='treat artifact as binary', action='store_true') 79 | initmenu.add_argument('main', nargs='?', default='main', help='name of the "main" entry method for the action') 80 | initmenu.add_argument('artifact', help='a source file or zip/tgz archive') 81 | 82 | runmenu = subparsers.add_parser('run', help='send arguments to container to run action') 83 | runmenu.add_argument('payload', nargs='?', help='the arguments to send to the action, either a reference to a file or an inline JSON object', default=None) 84 | 85 | if argcomplete: 86 | argcomplete.autocomplete(parser) 87 | return parser.parse_args() 88 | 89 | def init(args): 90 | main = args.main 91 | artifact = args.artifact 92 | 93 | if artifact and (args.binary or artifact.endswith('.zip') or artifact.endswith('tgz') or artifact.endswith('jar')): 94 | with open(artifact, 'rb') as fp: 95 | contents = fp.read() 96 | contents = base64.b64encode(contents) 97 | binary = True 98 | elif artifact is not '': 99 | with(codecs.open(artifact, 'r', 'utf-8')) as fp: 100 | contents = fp.read() 101 | binary = False 102 | else: 103 | contents = None 104 | binary = False 105 | 106 | r = requests.post( 107 | containerRoute(args, 'init'), 108 | json = {"value": {"code": contents, 109 | "binary": binary, 110 | "main": main}}) 111 | print(r.text) 112 | 113 | def run(args): 114 | value = processPayload(args.payload) 115 | if args.verbose: 116 | print('Sending value: %s...' % json.dumps(value)[0:40]) 117 | r = requests.post(containerRoute(args, 'run'), json = {"value": value}) 118 | print(r.text) 119 | 120 | def processPayload(payload): 121 | if payload and os.path.exists(payload): 122 | with open(payload) as fp: 123 | return json.load(fp) 124 | try: 125 | d = json.loads(payload if payload else '{}') 126 | if isinstance(d, dict): 127 | return d 128 | else: 129 | raise 130 | except: 131 | print('payload must be a JSON object.') 132 | sys.exit(-1) 133 | 134 | if __name__ == '__main__': 135 | main() 136 | --------------------------------------------------------------------------------