Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ bin/
# Gradle
.gradle
build/
.build/
!/tools/build/

# Python
Expand All @@ -52,6 +53,11 @@ node_modules
*.iml
out/

# VSCode
.vscode/

*.xcodeproj/

# Ansible
ansible/environments/docker-machine/hosts
ansible/db_local.ini*
Expand All @@ -61,12 +67,7 @@ ansible/roles/nginx/files/*.csr
ansible/roles/nginx/files/*cert.pem

# .zip files must be explicited whitelisted
*.zip
!tests/dat/actions/blackbox.zip
!tests/dat/actions/helloSwift.zip
!tests/dat/actions/python.zip
!tests/dat/actions/python2_virtualenv.zip
!tests/dat/actions/python3_virtualenv.zip
!tests/dat/actions/python_virtualenv_dir.zip
!tests/dat/actions/python_virtualenv_name.zip
!tests/dat/actions/zippedaction.zip
!tests/dat/build/swift311/HelloSwift3.zip
!tests/dat/build/swift4/HelloSwift4.zip
!tests/dat/build/swift4/SwiftyRequest.zip

152 changes: 150 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,158 @@
[![Build Status](https://travis-ci.org/apache/incubator-openwhisk-runtime-swift.svg?branch=master)](https://travis-ci.org/apache/incubator-openwhisk-runtime-swift)


### Give it a try today
### Simple swift action hello.swift
The traditional support for dictionary still works:
```swift
func main(args: [String:Any]) -> [String:Any] {
if let name = args["name"] as? String {
return [ "greeting" : "Hello \(name)!" ]
} else {
return [ "greeting" : "Hello swif4!" ]
}
}
```

### Packaging an action as a Swift executable using Swift 4

When you create an OpenWhisk Swift action with a Swift source file, it has to be compiled into a binary before the action is run. Once done, subsequent calls to the action are much faster until the container holding your action is purged. This delay is known as the cold-start delay.

To avoid the cold-start delay, you can compile your Swift file into a binary and then upload to OpenWhisk in a zip file. As you need the OpenWhisk scaffolding, the easiest way to create the binary is to build it within the same environment as it will be run in. These are the steps:

- Run an interactive Swift action container.
```
docker run --rm -it -v "$(pwd):/owexec" openwhisk/action-swift-v4 bash
```
This puts you in a bash shell within the Docker container.

- Copy the source code and prepare to build it.
```
cp /owexec/hello.swift /swift4Action/spm-build/Sources/Action/main.swift
```
```
cat /swift4Action/epilogue.swift >> /swift4Action/spm-build/Sources/Action/main.swift
```
```
echo '_run_main(mainFunction:main)' >> /swift4Action/spm-build/Sources/Action/main.swift
```
Copy any additional source files to `/swift4Action/spm-build/Sources/Action/`


- (Optional) Create the `Package.swift` file to add dependencies.
```swift
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "Action",
products: [
.executable(
name: "Action",
targets: ["Action"]
)
],
dependencies: [
.package(url: "https://github.com/IBM-Swift/SwiftyRequest.git", .upToNextMajor(from: "1.0.0"))
],
targets: [
.target(
name: "Action",
dependencies: ["SwiftyRequest"],
path: "."
)

```
As you can see this example adds `SwiftyRequest` dependencies.

Notice that now with swift:4 is no longer required to include `CCurl`, `Kitura-net` and `SwiftyJSON` in your own `Package.swift`.
You are free now to use no dependencies, or add the combination that you want with the versions you want.

- Copy Package.swift to spm-build directory
```
cp /owexec/Package.swift /swift4Action/spm-build/Package.swift
```

- Change to the spm-build directory.
```
cd /swift4Action/spm-build
```

- Compile your Swift Action.
```
swift build -c release
```

- Create the zip archive.
```
zip /owexec/hello.zip .build/release/Action
```

- Exit the Docker container.
```
exit
```

This has created hello.zip in the same directory as hello.swift.

- Upload it to OpenWhisk with the action name helloSwifty:
```
wsk action update helloSwiftly hello.zip openwhisk/action-swift-v4
```

- To check how much faster it is, run
```
wsk action invoke helloSwiftly --blocking
```

### Migrating from Swift 3 to Swift 4

### Helper compile.sh helper script
When compiling and packaging your swift 4 now there are a couple of differences
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: couple of differences.

All your source code needs to be copy to `/swift4Action/spm-build/Sources/Action/` instead of `/swift3Action/spm-build/`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: needs to be copied

You Package.swift needs to have the first line with a comment indicating swift4 tooling and format
```
// swift-tools-version:4.0
```
For swift 4 you need specify additional information in Package.swift such as `products` with executable name `Action` and `targets`

You can take a look at the helper script [tools/build/compile.sh](tools/build/compile.sh) to compile and zip your Actions.
Having a project directory `Hello` under a directory `actions` like the following:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: Have a project

```
actions/Hello/Package.swift
actions/Hello/Sources/main.swift
```
Change to the parent directory then run the compile script specify the project directory, the kind `swift:3.1.1` or `swift:4` and any swiftc build flags like the following:
```
cd actions/
incubator-runtime-swift/tools/build/compile.sh Hello swift:4 -v
```
This will produce a zip `build/swift4/Hello.zip`

### SwiftyJSON using single source action file
If you have a swift:3.1.1 action not compile, just as source using the `SwiftyJSON` package, you need to precompile your action and specify the version of SwiftyJSON you wan to use for swift:4 kind action.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

version of SwiftyJSON you want

Take into account that tarting with Swift 4 there is better support to manage JSON data natively.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take into account that starting


Note: This is only applicable to the base image provided for the Swift 4 runtime, other downstream such as IBM Cloud Functions extending this image might provide additional SDK and packages including `SwiftyJSON` and IBM Watson SDK, check the vendor documentation for more specific information about packages and versions.

### Building the Swift4 Image
```
./gradlew core:swift4Action:distDocker
```
This will produce the image `whisk/action-swift-v4`

Build and Push image
```
docker login
./gradlew core:swift4Action:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io
```


### Using Swift 3.1.1
To use as a docker action
```
wsk action update myAction myAction.jar --docker openwhisk/action-swift-v3.1.1:1.0.0
wsk action update myAction myAction.swift --docker openwhisk/action-swift-v3.1.1:1.0.0
```
This works on any deployment of Apache OpenWhisk

Expand Down
7 changes: 6 additions & 1 deletion ansible/environments/local/group_vars/all
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,14 @@ runtimes_manifest:
name: "swift3action"
deprecated: true
- kind: "swift:3.1.1"
default: true
default: false
image:
name: "action-swift-v3.1.1"
deprecated: false
- kind: "swift:4"
default: true
image:
name: "action-swift-v4"
deprecated: false
blackboxes:
- name: "dockerskeleton"
5 changes: 3 additions & 2 deletions core/actionProxy/actionproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ class ActionRunner:
# @param source the path where the source code will be located (if any)
# @param binary the path where the binary will be located (may be the
# same as source code path)
def __init__(self, source=None, binary=None):
def __init__(self, source=None, binary=None, zipdest=None):
defaultBinary = '/action/exec'
self.source = source if source else defaultBinary
self.binary = binary if binary else defaultBinary
self.zipdest = zipdest if zipdest else os.path.dirname(self.source)

def preinit(self):
return
Expand Down Expand Up @@ -182,7 +183,7 @@ def initCodeFromZip(self, message):
bytes = base64.b64decode(message['code'])
bytes = io.BytesIO(bytes)
archive = zipfile.ZipFile(bytes)
archive.extractall(os.path.dirname(self.source))
archive.extractall(self.zipdest)
archive.close()
return True
except Exception as e:
Expand Down
10 changes: 10 additions & 0 deletions core/swift4Action/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Apache OpenWhisk Swift 4 Runtime Container

## 1.0.0
Initial swift 4 image

Swift 4 runtime version:
- [4.0.3](https://hub.docker.com/r/ibmcom/swift-ubuntu/tags/4.0.3/)

Packages included:
- No packages included, use Package.swift and pre-compile action.
31 changes: 31 additions & 0 deletions core/swift4Action/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Dockerfile for swift actions, overrides and extends ActionRunner from actionProxy
# This Dockerfile is partially based on: https://github.com/IBM-Swift/swift-ubuntu-docker/blob/master/swift-development/Dockerfile
FROM ibmcom/swift-ubuntu:4.0

# Set WORKDIR
WORKDIR /

# Upgrade and install basic Python dependencies
RUN apt-get -y update \
&& apt-get -y install --fix-missing python2.7 python-gevent python-flask zip

# Add the action proxy
RUN mkdir -p /actionProxy
ADD actionproxy.py /actionProxy

# Add files needed to build and run action
RUN mkdir -p /swift4Action/spm-build/Sources/Action
ADD epilogue.swift /swift4Action
ADD buildandrecord.py /swift4Action
ADD swift4runner.py /swift4Action
ADD spm-build/Package.swift /swift4Action/spm-build
ADD spm-build/_Whisk.swift /swift4Action/spm-build/Sources/Action

# Build
RUN touch /swift4Action/spm-build/Sources/Action/main.swift
RUN python /swift4Action/buildandrecord.py && rm /swift4Action/spm-build/.build/release/Action
#RUN cd /swift4Action/spm-build; swift build -v -c release; rm /swift4Action/spm-build/.build/release/Action
ENV FLASK_PROXY_PORT 8080
EXPOSE 8080

CMD ["/bin/bash", "-c", "cd /swift4Action && PYTHONIOENCODING='utf-8' python -u swift4runner.py"]
13 changes: 13 additions & 0 deletions core/swift4Action/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
ext.dockerImageName = 'action-swift-v4'
apply from: '../../gradle/docker.gradle'
distDocker.dependsOn 'copyProxy'
distDocker.finalizedBy('cleanup')

task copyProxy(type: Copy) {
from '../actionProxy/actionproxy.py'
into '.'
}

task cleanup(type: Delete) {
delete 'actionproxy.py'
}
77 changes: 77 additions & 0 deletions core/swift4Action/buildandrecord.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Python to generate build script.

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
"""
from __future__ import print_function
import os
import sys
from subprocess import check_output

# Settings
COMPILE_PREFIX = "/usr/bin/swiftc -module-name Action "
LINKER_PREFIX = "/usr/bin/swiftc -target 'x86_64-unknown-linux' -sdk / -L '/swift4Action/spm-build/.build/x86_64-unknown-linux/release' -o '/swift4Action/spm-build/.build/x86_64-unknown-linux/release/Action' -module-name Action -emit-executable -Xlinker '-rpath=$ORIGIN'"
GENERATED_BUILD_SCRIPT = "/swift4Action/spm-build/swiftbuildandlink.sh"
SPM_DIRECTORY = "/swift4Action/spm-build"
BUILD_COMMAND = ["swift", "build", "-v", "-c", "release"]

# Build Swift package and capture step trace
print("Building action")
out = check_output(BUILD_COMMAND, cwd=SPM_DIRECTORY)
print("action built. Decoding compile and link commands")

# Look for compile and link commands in step trace
compileCommand = None
linkCommand = None

buildInstructions = out.decode("utf-8").splitlines()

for instruction in buildInstructions:
if instruction.startswith(COMPILE_PREFIX):
compileCommand = instruction

# add flag to quiet warnings
compileCommand += " -suppress-warnings"

elif instruction.startswith(LINKER_PREFIX):
linkCommand = instruction

# if found, create build script, otherwise exit with error
if compileCommand is not None and linkCommand is not None:
print("Generated OpenWhisk Compile command: %s" % compileCommand)
print("=========")
print("Generated OpenWhisk Link command: %s" % linkCommand)

with open(GENERATED_BUILD_SCRIPT, "a") as buildScript:
buildScript.write("#!/bin/bash\n")
buildScript.write("echo \"Compiling\"\n")
buildScript.write("%s\n" % compileCommand)
buildScript.write("swiftStatus=$?\n")
buildScript.write("echo swiftc status is $swiftStatus\n")
buildScript.write("if [[ \"$swiftStatus\" -eq \"0\" ]]; then\n")
buildScript.write("echo \"Linking\"\n")
buildScript.write("%s\n" % linkCommand)
buildScript.write("else\n")
buildScript.write(">2& echo \"Action did not compile\"\n")
buildScript.write("exit 1\n")
buildScript.write("fi")

os.chmod(GENERATED_BUILD_SCRIPT, 0o777)
sys.exit(0)
else:
print("Cannot generate build script: compile or link command not found")
sys.exit(1)
Loading