apache / openwhisk-runtime-swift Goto Github PK
View Code? Open in Web Editor NEWApache OpenWhisk Runtime Swift supports Apache OpenWhisk functions written in Swift
Home Page: https://openwhisk.apache.org/
License: Apache License 2.0
Apache OpenWhisk Runtime Swift supports Apache OpenWhisk functions written in Swift
Home Page: https://openwhisk.apache.org/
License: Apache License 2.0
This may have been a typo/mix-up, but this repo. placed all referenced license files into a subdir named "license" singular; it should be plural or "licenses" to conform to what we do in all other repos.
Swift 4.2 is already announce as the next release https://swift.org/blog/4-2-release-process/
I propose we start Swift 4 support with 4.1, and remove Swift 4.0
I used below command to build swift41Action
./gradlew core:swift41Action:distDocker
Report below error log
gpg: requesting key 412B37AD from hkp server pool.sks-keyservers.net
gpg: requesting key 21A56D5F from hkp server pool.sks-keyservers.net
gpg: requesting key 91D306C6 from hkp server pool.sks-keyservers.net
gpg: requesting key 71E1B235 from hkp server pool.sks-keyservers.net
gpg: requesting key 2B2B08C4 from hkp server pool.sks-keyservers.net
?: pool.sks-keyservers.net: Network is unreachable
gpgkeys: HTTP fetch error 7: couldn't connect: Network is unreachable
?: pool.sks-keyservers.net: Network is unreachable
gpgkeys: HTTP fetch error 7: couldn't connect: Network is unreachable
?: pool.sks-keyservers.net: Network is unreachable
gpgkeys: HTTP fetch error 7: couldn't connect: Network is unreachable
?: pool.sks-keyservers.net: Network is unreachable
gpgkeys: HTTP fetch error 7: couldn't connect: Network is unreachable
gpg: no valid OpenPGP data found. 47s]
gpg: Total number processed: 0
?: pool.sks-keyservers.net: Network is unreachable
gpgkeys: HTTP fetch error 7: couldn't connect: Network is unreachable
The command '/bin/sh -c wget https://swift.org/builds/$SWIFT_SNAPSHOT_LOWERCASE/$UBUNTU_VERSION_NO_DOTS/$SWIFT_SNAPSHOT/$SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz https://swift.org/builds/$SWIFT_SNAPSHOT_LOWERCASE/$UBUNTU_VERSION_NO_DOTS/$SWIFT_SNAPSHOT/$SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz.sig && gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys '7463 A81A 4B2E EA1B 551F FBCF D441 C977 412B 37AD' '1BE1 E29A 084C B305 F397 D62A 9F59 7F4D 21A5 6D5F' 'A3BA FD35 56A5 9079 C068 94BD 63BC 1CFE 91D3 06C6' '5E4D F843 FB06 5D7F 7E24 FBA2 EF54 30F0 71E1 B235' '8513 444E 2DA3 6B7C 1659 AF4D 7638 F1FB 2B2B 08C4' && gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys && gpg --verify $SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz.sig && tar xzvf $SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz --strip-components=1 && rm $SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz && rm $SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz.sig && chmod -R go+r /usr/lib/swift && swift --version' returned a non-zero code: 2
Today we use python web server to execute the swift binary.
python will pass input JSON via stdin and expect executable to respond with the last line of stdout as the output JSON.
The problems is that the swift code needs to initialize everything on every invoke. if creates instances of a Class, or reads a file into an instance. this work needs to be done from scratch on every invoke.
Other runtimes like nodejs and python in OpenWhisk don't have this problem, since the web proxy server is in the same language and holds into memory.
It would be good to have a web proxy server to be implemented in swift, this way anything created on /init or /run can remain in memory as long the container lives.
One alternative is look into Kitura 2.0 to build a very small and fast web proxy that listens on port 8080 that handles the standard OW interface with /init and /run
@jberstler commented on Tue May 10 2016
At the current moment, the possibilities for Swift development experience on OpenWhisk are wide open. Let's use this issue to discuss the right approach to make developing OpenWhisk artifacts in Swift a good experience for our users.
Whatever specific decisions are made, I think we should keep in mind the following ideals:
It may not be possible to achieve all of these ideals in the final experience, and so compromise should be carefully considered.
@jberstler commented on Tue May 10 2016
Proposal: Actions must declare a global main
function
The obvious advantage of this approach is simplicity. The action developer gets to see exactly what is expected of them, and the OW runtime knows exactly what code to invoke to run the action:
func main(args: [String:Any]) -> [String:Any] {
// action implementation goes here
}
This advantage extends even to having the types of the args
object and the expected return type plainly visible to the action developer.
The disadvantage to this approach is that it violates our goals of using standard tools and developing multiple OW artifacts in the same Swift package or Xcode target. If you have multiple files declaring this global main
function, the swift compiler will complain that you are trying to redefine a global function.
@rabbah commented on Thu Nov 16 2017
@csantanapr @paulcastro @jberstler should we move this to the new swift repo?
Following Apache license header guideline, all human-readable Apache-developed files that are included within a distribution must include the header text with few exceptions. You can find few exceptions here: which files do not require a license header.
I used Apache Rat to check this repository after excluding a few files, and I got this report. We need to add Apache licensing header to those files.
Unapproved licenses:
openwhisk-runtime-swift/tools/build/compile.sh
openwhisk-runtime-swift/tools/travis/setup.sh
openwhisk-runtime-swift/tools/travis/publish.sh
openwhisk-runtime-swift/tools/travis/build.sh
openwhisk-runtime-swift/tools/travis/deploy.sh
openwhisk-runtime-swift/tools/travis/test.sh
openwhisk-runtime-swift/core/swift41Action/CHANGELOG.md
openwhisk-runtime-swift/core/swift41Action/Dockerfile
openwhisk-runtime-swift/core/swift40Action/epilogue.swift
openwhisk-runtime-swift/core/swift40Action/CHANGELOG.md
openwhisk-runtime-swift/core/swift40Action/Dockerfile
openwhisk-runtime-swift/core/swift3.1.1Action/CHANGELOG.md
openwhisk-runtime-swift/core/swift3.1.1Action/Dockerfile
openwhisk-runtime-swift/tests/dat/build.sh
openwhisk-runtime-swift/tests/dat/actions/HelloSwift4/Sources/main.swift
openwhisk-runtime-swift/tests/dat/actions/HelloSwift3/Sources/main.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift3/createTrigger.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift3/invoke.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift3/hello.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift3/trigger.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift3/createRule.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift3/invokeNonBlocking.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift4/createTrigger.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift4/invoke.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift4/hello.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift4/trigger.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift4/createRule.swift
openwhisk-runtime-swift/tests/dat/actions/sdk/swift4/invokeNonBlocking.swift
openwhisk-runtime-swift/tests/dat/actions/SwiftyRequest/Package.resolved
openwhisk-runtime-swift/tests/dat/actions/SwiftyRequest/Sources/main.swift
openwhisk-runtime-swift/tests/src/test/resources/application.conf
openwhisk-runtime-swift/README.md
openwhisk-runtime-swift/ansible/environments/local/group_vars/all
openwhisk-runtime-swift/ansible/environments/local/hosts
The excluded files are:
**/*.json
**/**.gradle
**/gradlew
**/gradle/**
**/.**
**/templates/**
**/*.j2.*
**/.github/**
**/auth.whisk.system
**/auth.guest
**/i18n_resources.go
Build should pass successfully.
:tests:compileTestScala FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Could not resolve all files for configuration ':tests:testCompileClasspath'.
> Could not find org.apache.openwhisk:openwhisk-admin-tools:1.0.0-SNAPSHOT.
Searched in the following locations:
https://repo1.maven.org/maven2/org/apache/openwhisk/openwhisk-admin-tools/1.0.0-SNAPSHOT/maven-metadata.xml
https://repo1.maven.org/maven2/org/apache/openwhisk/openwhisk-admin-tools/1.0.0-SNAPSHOT/openwhisk-admin-tools-1.0.0-SNAPSHOT.pom
https://repo1.maven.org/maven2/org/apache/openwhisk/openwhisk-admin-tools/1.0.0-SNAPSHOT/openwhisk-admin-tools-1.0.0-SNAPSHOT.jar
file:/home/travis/.m2/repository/org/apache/openwhisk/openwhisk-admin-tools/1.0.0-SNAPSHOT/maven-metadata.xml
file:/home/travis/.m2/repository/org/apache/openwhisk/openwhisk-admin-tools/1.0.0-SNAPSHOT/openwhisk-admin-tools-1.0.0-SNAPSHOT.pom
file:/home/travis/.m2/repository/org/apache/openwhisk/openwhisk-admin-tools/1.0.0-SNAPSHOT/openwhisk-admin-tools-1.0.0-SNAPSHOT.jar
Required by:
project :tests > org.apache.openwhisk:openwhisk-tests:1.0.0-SNAPSHOT
@JacopoMangiavacchi commented on Thu Apr 07 2016
Current Swift support is limited to synchronous action. It should be nice to support GCD queue capabilities and implement a Whisk Swift API based on Promise/Future pattern such as BrightFutures https://github.com/Thomvis/BrightFutures
We currently have our own copy of actionProxy/actionproxy.py
https://github.com/apache/incubator-openwhisk-runtime-swift/blob/master/core/actionProxy/actionproxy.py#L186
We should instead use the one from dockerSkeleton, but for swift4 we need to update dockerSkeleton to take a fourth parameter zipdest
to be able to override the destination of the zip when unzipping the action.
This snippet needs to be push upstream to runtime docker and then pull down from Dockerfile
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)
Once that's availabl we can update Dockerfile with
# Add the action proxy
RUN mkdir -p /actionProxy
ADD https://raw.githubusercontent.com/apache/incubator-openwhisk-runtime-docker/dockerskeleton%401.0.0/core/actionProxy/actionproxy.py /actionProxy/actionproxy.py
Things to look into:
When porting from TravisCI to GitHub Actions, I gave up on getting the Swift SDK tests to run.
If/when we get back to this again, be sure to look at https://github.com/apache/openwhisk-runtime-swift/blob/ac1234e92b27afc0708a44bbac3081ba74ca0420/tools/travis/deploy.sh to replicate the special way the entire OpenWhisk system was deployed to use the locally built Swift runtime images.
Need to be updated to use nightly
per the recent changes.
Refactor _Whisk.swift to use URLSession and Codable for JSON management.
Create copy and add into /core/swift4Action/spm-build/_Whisk.swift
With the recent release of swift 4.1 in Xcode Beta.
I think is close to done, having swift:4
it would be vague which version of swift is the runtime referring.
This issue to track the work to change the kind to swift:4.0
and the image name to action-swfit-v4.0
the Swift 4.0 runtime passes the large input test but not the 3.1.1 test.
@eweiter is this something you can help with?
Travis is failing to build swift 4 image
gpg: no ultimately trusted keys found
gpg: Total number processed: 3
gpg: imported: 3 (RSA: 3)
gpg: keyserver timed out
gpg: keyserver receive failed: keyserver error
The command '/bin/sh -c wget https://swift.org/builds/$SWIFT_SNAPSHOT_LOWERCASE/$UBUNTU_VERSION_NO_DOTS/$SWIFT_SNAPSHOT/$SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz https://swift.org/builds/$SWIFT_SNAPSHOT_LOWERCASE/$UBUNTU_VERSION_NO_DOTS/$SWIFT_SNAPSHOT/$SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz.sig && gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys '7463 A81A 4B2E EA1B 551F FBCF D441 C977 412B 37AD' '1BE1 E29A 084C B305 F397 D62A 9F59 7F4D 21A5 6D5F' 'A3BA FD35 56A5 9079 C068 94BD 63BC 1CFE 91D3 06C6' '5E4D F843 FB06 5D7F 7E24 FBA2 EF54 30F0 71E1 B235' '8513 444E 2DA3 6B7C 1659 AF4D 7638 F1FB 2B2B 08C4' && gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys && gpg --verify $SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz.sig && tar xzvf $SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz --strip-components=1 && rm $SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz && rm $SWIFT_SNAPSHOT-$UBUNTU_VERSION.tar.gz.sig && chmod -R go+r /usr/lib/swift && swift --version' returned a non-zero code: 2
�[0m
Wed Aug 15 15:22:42 UTC 2018: Command 'docker build -t action-swift-v4.1 /home/travis/build/apache/incubator-openwhisk-runtime-swift/core/swift41Action' failed with exitCode 2, no more retries left, aborting...
:core:swift41Action:distDocker FAILED
:core:swift41Action:tagImage
Wed Aug 15 15:22:42 UTC 2018: Executing 'docker tag action-swift-v4.1 testing/action-swift-v4.1:latest'
Error response from daemon: no such id: action-swift-v4.1
Wed Aug 15 15:22:42 UTC 2018: Command 'docker tag action-swift-v4.1 testing/action-swift-v4.1:latest' failed with exitCode 1, 2 retries left, retrying...
Wed Aug 15 15:22:42 UTC 2018: Executing 'docker tag action-swift-v4.1 testing/action-swift-v4.1:latest'
Error response from daemon: no such id: action-swift-v4.1
Wed Aug 15 15:22:42 UTC 2018: Command 'docker tag action-swift-v4.1 testing/action-swift-v4.1:latest' failed with exitCode 1, 1 retries left, retrying...
Wed Aug 15 15:22:42 UTC 2018: Executing 'docker tag action-swift-v4.1 testing/action-swift-v4.1:latest'
Error response from daemon: no such id: action-swift-v4.1
Wed Aug 15 15:22:42 UTC 2018: Command 'docker tag action-swift-v4.1 testing/action-swift-v4.1:latest' failed with exitCode 1, no more retries left, aborting...
:core:swift41Action:tagImage FAILED
FAILURE: Build completed with 2 failures.
1: Task failed with an exception.
-----------
* Where:
Script '/home/travis/build/apache/incubator-openwhisk-runtime-swift/gradle/docker.gradle' line: 113
The solution is to implement the TODO, to extend the official swift 4 image instead
https://github.com/apache/incubator-openwhisk-runtime-swift/blob/master/core/swift41Action/Dockerfile#L18
# TODO Replace this dockerfile and extend from official image when 4.1 is released
There is a beta builds available for swift 4.1, we should add early to start experimenting with it.
There could be a chance depending on timing of the swift 4.1 release, that we skip swift 4.0 and just for for swift 4.1
Step 11/13 : RUN python /swift3Action/buildandrecord.py && rm /swift3Action/spm-build/.build/release/Action
The build failed at this line, when the swift 3.1.1 image was being built. It always timed out, since there is no response.
The epilogue uses environment variable to take the input JSON
let inputStr: String = env["WHISK_INPUT"] ?? "{}"
We should modify this and pass the input as STDIN to allow larger input data (i.e. 1MB, 3MB, etc..) using swift readLine()
@eweiter commented on Fri May 11 2018
It was reported that the Swift 4.1 runtime was exhibiting a strange behavior. The behavior in question occurs when a Struct has multiple Strings and those Strings are being initialized directly from static Strings.
For instance, the following piece of code will work:
struct Output: Codable {
let greeting: String
let group: String
}
func main(completion: (Output?, Error?) -> Void) -> Void {
let name = "MyName"
let result = Output(greeting: "Hello \(name)", group: "Greetings")
print("Log greeting:\(result.greeting)")
completion(result, nil)
}
However the following code will not:
struct Output: Codable {
let greeting: String
let group: String
}
func main(completion: (Output?, Error?) -> Void) -> Void {
let result = Output(greeting: "Hello Name", group: "bummer")
print("Log greeting:\(result.greeting)")
completion(result, nil)
}
It appears to be a bug within Swift itself.
We have discovered that if the code is compiled with the compiler flag to turn off optimizations then the compiling will work. This compile flag is -Xswiftc -Onone
@eweiter commented on Sun May 13 2018
PR apache/openwhisk#3647 was merged as a temp fix until the issue is addressed in the Swift Docker image.
@eweiter commented on Mon May 14 2018
I believe I have narrowed down the reasoning for this issue as coming from the use of the "@escaping" syntax in here https://github.com/apache/incubator-openwhisk-runtime-swift/blob/master/core/swift41Action/epilogue.swift#L98
I have stripped down this code the mainly the essentials (non-whisk related) items and when the "@escaping" option is present the code will throw a compiler error, however when I remove the statement the code will compile fine and execute successfully.
I will be opening an issue against the Swift Docker image tomorrow and will link that here when I do.
@csantanapr commented on Mon May 14 2018
leaving open until we get a fix from swift team
Natively? No. However, libraries can be used.
Low level languages can be much more performant, and it would allow to share code with iOS/Android apps.
Maybe they should be included in almost all of the runtimes. Accessing a DB is part and parcel of micro-services work, and actions would benefit from that as well, to avoid passing huge JSON files across a sequence.
But it requires a different set of skills, plus pushing a container to DockerHub, etc... That's a lot of friction.
https://hub.docker.com/r/ibmcom/swift-ubuntu-runtime/
We use this image, but we are not sure of the license.
The tests currently use http
and pass in Travis.
The same tests can be use in production systems where https is available with valid certificates.
On this production systems the http port to the controller is not available.
This is feedback from @jthomas
#23 (comment)
Sync method style APIs should probably support throws. This enables uses to use normal error handling to surface issues.
Local instances of the platform use a self-signed SSL certificate. The Swift SDK (_Whisk.swift
) fails when invoked against platform endpoints without a valid SSL certificate.
The JavaScript SDK supports a constructor argument to turn off certificat checking to resolve this issue. Looking into implementing this behaviour for the Swift SDK, I have discovered a blocking issue due to the lack of support in the open-source Swift Foundation libraries.
In Swift, certificate checking can be turned off by creating a new URLSessionDelegate
with always trusts the server.
class SessionDelegate:NSObject, URLSessionDelegate
{
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, credential)
}
}
This can be used when creating the URLSession
to use based upon a method parameter.
let session = ignoreCerts ? URLSession(configuration: .default, delegate: SessionDelegate(), delegateQueue: nil) : URLSession(configuration: URLSessionConfiguration.default)
This works on OS X but compiling the code on Linux, I ran into the following issue.
_Whisky.swift:25:39: error: incorrect argument label in call (have 'trust:', expected 'coder:')
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
^~~~~~
coder
root@3a4fde570648:/source# swift -v
Swift version 4.0 (swift-4.0-RELEASE)
Target: x86_64-unknown-linux-gnu
Looking into the source code for the Swift foundation core libraries, I discovered this method has not been implemented.
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/URLCredential.swift#L155
// TODO: We have no implementation for Security.framework primitive types SecIdentity and SecTrust yet
Talking to the IBM@Swift team, support for this feature is being worked on but won't be available until Swift 5 at the earliest.
Until then, we will have to document the behaviour and wait for the foundation libraries to catch up. I've attached the completed _Whisk.swift
demonstrating the bug.
/*
* 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.
*/
import Foundation
import Dispatch
class SessionDelegate:NSObject, URLSessionDelegate
{
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, credential)
}
}
class Whisk {
static var baseUrl = ProcessInfo.processInfo.environment["__OW_API_HOST"]
static var apiKey = ProcessInfo.processInfo.environment["__OW_API_KEY"]
class func invoke(actionNamed action : String, withParameters params : [String:Any], ignoreCerts: Bool = false, blocking: Bool = true) -> [String:Any] {
let parsedAction = parseQualifiedName(name: action)
let strBlocking = blocking ? "true" : "false"
let path = "/api/v1/namespaces/\(parsedAction.namespace)/actions/\(parsedAction.name)?blocking=\(strBlocking)"
return sendWhiskRequestSyncronish(uriPath: path, params: params, method: "POST", ignoreCerts: ignoreCerts)
}
class func trigger(eventNamed event : String, ignoreCerts: Bool = false, withParameters params : [String:Any]) -> [String:Any] {
let parsedEvent = parseQualifiedName(name: event)
let path = "/api/v1/namespaces/\(parsedEvent.namespace)/triggers/\(parsedEvent.name)?blocking=true"
return sendWhiskRequestSyncronish(uriPath: path, params: params, method: "POST", ignoreCerts: ignoreCerts)
}
class func createTrigger(triggerNamed trigger: String, ignoreCerts: Bool = false, withParameters params : [String:Any]) -> [String:Any] {
let parsedTrigger = parseQualifiedName(name: trigger)
let path = "/api/v1/namespaces/\(parsedTrigger.namespace)/triggers/\(parsedTrigger.name)"
return sendWhiskRequestSyncronish(uriPath: path, params: params, method: "PUT", ignoreCerts: ignoreCerts)
}
class func createRule(ruleNamed ruleName: String, withTrigger triggerName: String, andAction actionName: String, ignoreCerts: Bool = false) -> [String:Any] {
let parsedRule = parseQualifiedName(name: ruleName)
let path = "/api/v1/namespaces/\(parsedRule.namespace)/rules/\(parsedRule.name)"
let params = ["trigger":triggerName, "action":actionName]
return sendWhiskRequestSyncronish(uriPath: path, params: params, method: "PUT", ignoreCerts: ignoreCerts)
}
// handle the GCD dance to make the post async, but then obtain/return
// the result from this function sync
private class func sendWhiskRequestSyncronish(uriPath path: String, params : [String:Any], method: String, ignoreCerts: Bool) -> [String:Any] {
var response : [String:Any]!
let queue = DispatchQueue.global()
let invokeGroup = DispatchGroup()
invokeGroup.enter()
queue.async {
postUrlSession(uriPath: path, ignoreCerts: ignoreCerts, params: params, method: method, group: invokeGroup) { result in
response = result
}
}
// On one hand, FOREVER seems like an awfully long time...
// But on the other hand, I think we can rely on the system to kill this
// if it exceeds a reasonable execution time.
switch invokeGroup.wait(timeout: DispatchTime.distantFuture) {
case DispatchTimeoutResult.success:
break
case DispatchTimeoutResult.timedOut:
break
}
return response
}
/**
* Using new UrlSession
*/
private class func postUrlSession(uriPath: String, ignoreCerts: Bool, params : [String:Any], method: String,group: DispatchGroup, callback : @escaping([String:Any]) -> Void) {
guard let encodedPath = uriPath.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else {
callback(["error": "Error encoding uri path to make openwhisk REST call."])
return
}
let urlStr = "\(baseUrl!)\(encodedPath)"
if let url = URL(string: urlStr) {
var request = URLRequest(url: url)
request.httpMethod = method
do {
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONSerialization.data(withJSONObject: params)
let loginData: Data = apiKey!.data(using: String.Encoding.utf8, allowLossyConversion: false)!
let base64EncodedAuthKey = loginData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
request.addValue("Basic \(base64EncodedAuthKey)", forHTTPHeaderField: "Authorization")
let session = ignoreCerts ? URLSession(configuration: .default, delegate: SessionDelegate(), delegateQueue: nil) : URLSession(configuration: URLSessionConfiguration.default)
let task = session.dataTask(with: request, completionHandler: {data, response, error -> Void in
// exit group after we are done
defer {
group.leave()
}
if let error = error {
callback(["error":error.localizedDescription])
} else {
if let data = data {
do {
//let outputStr = String(data: data, encoding: String.Encoding.utf8) as String!
//print(outputStr)
let respJson = try JSONSerialization.jsonObject(with: data)
if respJson is [String:Any] {
callback(respJson as! [String:Any])
} else {
callback(["error":" response from server is not a dictionary"])
}
} catch {
callback(["error":"Error creating json from response: \(error)"])
}
}
}
})
task.resume()
} catch {
callback(["error":"Got error creating params body: \(error)"])
}
}
}
// separate an OpenWhisk qualified name (e.g. "/whisk.system/samples/date")
// into namespace and name components
private class func parseQualifiedName(name qualifiedName : String) -> (namespace : String, name : String) {
let defaultNamespace = "_"
let delimiter = "/"
let segments :[String] = qualifiedName.components(separatedBy: delimiter)
if segments.count > 2 {
return (segments[1], Array(segments[2..<segments.count]).joined(separator: delimiter))
} else if segments.count == 2 {
// case "/action" or "package/action"
let name = qualifiedName.hasPrefix(delimiter) ? segments[1] : segments.joined(separator: delimiter)
return (defaultNamespace, name)
} else {
return (defaultNamespace, segments[0])
}
}
}
README refers to public image (openwhisk/action-swift-v4
) as the Swift 4 runtime.
$ wsk action update helloSwiftly hello.zip openwhisk/action-swift-v4
This image does not exist in Docker Hub.
Initial Support for Swift 4 using current python proxy
Same approach as 3.1.1 just using swift 4 runtime and new set of packages
Update the Travis build to push a tag "master" to Docker when a the master branch is updated.
This will make it easier to pull the image that aligns with the latest changes on the Master branch.
Reference can be taken from: apache/openwhisk-runtime-java#37
Currently this runtime does not support Swift 5.
The code will not compile if the main function calls another function that escapes.
For example the following code:
func main(param: Input, completion: @escaping (Output?, Error?) -> Void) -> Void {
print("debug3")
let languageTranslator = LanguageTranslator(username: param.username , password: param.password)
let failure = {(error: Error) in
print(" calling translate Error")
print(error)
completion(nil, error)
}
let _ = languageTranslator.translate(
_: "Hello",
from: "en",
to: "es",
failure: failure) {translation in
let result = Output(translation: translation.translations[0].translation as String)
print(result)
completion(result, nil)
}
}
I already fix this in the downstream, contributing here for benefits of others using this as common epilogue.
https://github.com/ibm-functions/runtime-swift/blob/master/swift4.0/epilogue.swift#L62
User asked about this recently...
Swift 4.2 has now been released.
https://www.hackingwithswift.com/articles/77/whats-new-in-swift-4-2
Doing a non blocking invoke using urlSession it fails with
Starting test Swift Whisk SDK tests using swift:4 should allow Swift actions to invoke other actions and not block at 2018-02-03 21:04:23.588
check failed for activation 9c418ab0f5424923818ab0f5420923ff:
{
"logs":[
"2018-02-04T02:04:26.134158018Z stdout: Compiling","2018-02-04T02:04:26.134202437Z stdout: swiftc status is 0",
"2018-02-04T02:04:26.13420729Z stdout: Linking",
"2018-02-04T02:04:26.65737652Z stdout: ",
"2018-02-04T02:04:26.658329845Z stderr: *** Error in `/swift4Action/spm-build/.build/release/Action': double free or corruption (fasttop): 0x00007f4960000910 ***"]
}
Exception occurred during test execution: java.util.NoSuchElementException: key not found: activationId
It looks like is a known issue and fixed in 4.0.1+
https://bugs.swift.org/browse/SR-5936
https://bugs.swift.org/browse/SR-5972
Seems fixed in the latest 4.0.1 snapshot.
We need to pick up the new image version ibmcom/swift-ubuntu:4.0.3
The current Swift files for implementing the OpenWhisk handler are included as raw source files. This leads to a complex and manual process for building Swift binaries locally, which doesn't feel very "Swifty".
docker run -it -v "$HOME:/owexec" openwhisk/swift3action bash
apt-get install -y zip
cp /owexec/hello.swift /swift3Action/spm-build/main.swift
cat /swift3Action/epilogue.swift >> /swift3Action/spm-build/main.swift
echo '_run_main(mainFunction:main)' >> /swift3Action/spm-build/main.swift
/swift3Action/spm-build/swiftbuildandlink.sh
cd /swift3Action/spm-build
zip /owexec/hello.zip .build/release/Action
exit
Publishing this code as an official Swift package would massively improve the developer experience. I've already experimented with doing this and have an unofficial package available here:
https://packagecatalog.com/package/jthomas/OpenWhiskAction
Developers include the package in their manifest
let package = Package(
name: "Action",
dependencies: [
.Package(url: "https://github.com/jthomas/OpenWhiskAction.git", majorVersion: 0)
]
)
... and then simply reference the library in their code.
import OpenWhiskAction
func hello(args: [String:Any]) -> [String:Any] {
if let name = args["name"] as? String {
return [ "greeting" : "Hello \(name)!" ]
} else {
return [ "greeting" : "Hello stranger!" ]
}
}
OpenWhiskAction(main: hello)
Compiling a binary for the platform them becomes a single command.
docker run --rm -it -v $(pwd):/swift-package openwhisk/swift3action bash -e -c "cd /swift-package && swift build -v -c release"
This is a huge improvements over the current process.
Creating this package no code changes, it's just bundling the existing handler files in the Swift package format.
https://github.com/jthomas/OpenWhiskAction
This package can also be used when dynamically compiling Swift actions rather than having the scripts also manually copy files about.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.