Giter VIP home page Giter VIP logo

apache / openwhisk-runtime-swift Goto Github PK

View Code? Open in Web Editor NEW
24.0 32.0 23.0 26.61 MB

Apache OpenWhisk Runtime Swift supports Apache OpenWhisk functions written in Swift

Home Page: https://openwhisk.apache.org/

License: Apache License 2.0

Python 8.17% Swift 54.74% Scala 28.26% Shell 3.16% Dockerfile 4.82% Makefile 0.86%
openwhisk apache serverless faas functions-as-a-service cloud serverless-architectures serverless-functions docker functions

openwhisk-runtime-swift's Introduction

Apache OpenWhisk runtimes for swift

License Continuous Integration

Changelogs

Quick Swift Action

Simple swift action hello.swift

The traditional support for the dictionary still works:

import Foundation

func main(args: Any) -> Any {
    let dict = args as! [String:Any]
    if let name = dict["name"] as? String {
        return [ "greeting" : "Hello \(name)!" ]
    } else {
        return [ "greeting" : "Hello stranger!" ]
    }
}

For the return result, not only support dictionary, but also support array

So a very simple hello array function would be:

func main(args: Any) -> Any {
    var arr = ["a", "b"]
    return arr
}

And support array result for sequence action as well, the first action's array result can be used as next action's input parameter.

So the function can be:

 func main(args: Any) -> Any {
     return args
 }

When invoking the above action, we can pass an array object as the input parameter.

Swift 5.x support

Some examples of using Codable In and Out

Codable style function signature

Create file helloCodableAsync.swift

import Foundation

// Domain model/entity
struct Employee: Codable {
  let id: Int?
  let name: String?
}
// codable main function
func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
    // For simplicity, just passing same Employee instance forward
    respondWith(input, nil)
}
wsk action update helloCodableAsync helloCodableAsync.swift swift:5.1
ok: updated action helloCodableAsync
wsk action invoke helloCodableAsync -r -p id 73 -p name Andrea
{
    "id": 73,
    "name": "Andrea"
}

Codable Error Handling

Create file helloCodableAsync.swift

import Foundation

struct Employee: Codable {
    let id: Int?
    let name: String?
}
enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}
func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
    // Return real error
    do {
        throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
    } catch {
        respondWith(nil, error)
    }
}
wsk action update helloCodableError helloCodableError.swift swift:5.1
ok: updated action helloCodableError
wsk action invoke helloCodableError -b -p id 51 -p name Carlos
{
  "name": "helloCodableError",
  "response": {
    "result": {
      "error": "insufficientFunds(5)"
    },
    "status": "application error",
    "success": false
  }
}

Packaging an action as a Swift executable using Swift 5.x

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.

Compiling Swift 5.x

Compiling Swift 5.x single file

Use the docker container and pass the single source file as stdin. Pass the name of the method to the flag -compile

docker run -i openwhisk/action-swift-v5.1 -compile main <main.swift >../action.zip

Compiling Swift 5.1 multiple files with dependencies

Use the docker container and pass a zip archive containing a Package.swift and source files a main source file in the location Sources/main.swift.

zip - -r * | docker run -i openwhisk/action-swift-v5.1 -compile main >../action.zip

For more build examples see here

Swift 5.7

In addition to previous ways of defining an action is now possible to use throwing async/await inside the action.

Async throwing Action with Any Input and Any Output

func action(args: Any) async throws -> Any {
    //async code sleep for 1 sec
    try await Task.sleep(nanoseconds: 1_000_000_000)

    let newArgs = args as! [String:Any]
    if let name = newArgs["name"] as? String {
        return [ "greeting" : "Hello \(name)!" ]
    } else {
        return [ "greeting" : "Hello stranger!" ]
    }
}

Async throwing Action with a Codable Input and a Codable Output

struct Input: Codable {
    let name: String?
}

struct Output: Codable {
    let count: Int
}

func action(input: Input) async throws -> Output? {
    try await Task.sleep(nanoseconds: 1_000_000_000)
    if let name = input.name {
        return Output(count: name.count)
    } else {
        return Output(count: 0)
    }
}

Async throwing Action with Codable Output

struct Input: Codable {
    let name: String?
}

struct Output: Codable {
    let count: Int
}

func action() async throws -> Output? {
    try await Task.sleep(nanoseconds: 1_000_000_000)
    return Output(count: 0)
}

Example of an async throwing Action with a Codable Input and a Codable Output

In the following example, the main action decodes the URL from AnInput, downloads the content from the URL, decodes the JSON and returns the response in AnOutput. In case of failure, the runtime will return an error.

import AsyncHTTPClient
import Foundation
import _Concurrency
import NIOCore
import NIOFoundationCompat

enum RequestError: Error {
    case requestError
}
struct AnInput: Codable {
    let url: String?
}

struct AnOutput: Codable {
    let args: [String: String]
    let headers: [String: String]
    let origin: String
    let url: String
}

let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
let decoder = JSONDecoder()

func main(param: AnInput) async throws -> AnOutput {

    let echoURL = param.url ?? "https://httpbin.org/get"
    let request = HTTPClientRequest(url: echoURL)
    let response = try await httpClient.execute(request, timeout: .seconds(3))
    if response.status == .ok {
        let bytes = try await response.body.collect(upTo: 1024 * 1024) // 1 MB Buffer
        let data = Data(buffer: bytes)
        return try decoder.decode(AnOutput.self, from: data)
    } else {
        throw RequestError.requestError
    }
}

The full swift package is here.

Note that the package of this action contains a dependency from AsynHTTPClient, in such case, it's preferred to build the action.

zip - -r * | docker run -i openwhisk/action-swift-v5.7 -compile main >../action.zip

openwhisk-runtime-swift's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

openwhisk-runtime-swift's Issues

Fix codable escaping for result handler

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

move swift:4 to swift:4.01

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

Do not use own copy of actionProxy.py use common one from dockerskeleton

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

Swift 4.1 issue discovered around Structs with two Strings

@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

Initial Support for swift 4

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

Some source files miss Apache license headers

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

Update swift4 to allow more than 128KB of input parameters

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()

Swift 4 web proxy in swift

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

travis failing to build swift 4 image

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

Error with urlSession double free or corruption (fasttop) upgrade to swift 4.0.3

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

Swift SDK does not support self-signed server certificates.

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])
        }
    }
}

Swift 3.1.1 image fails to build due to timeout

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.

build swift41Action failed in my local

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

Add swift 4.1 beta/experimental

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

Travis build failure openwhisk-admin-tools dependency not found

Environment details:

  • Travic-ci build

Steps to reproduce the issue:

  1. Trigger Travis-ci build for the runtime

Provide the expected results and outputs:

Build should pass successfully.

Provide the actual results and outputs:

: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

Additional information you deem important:

  • Issue is not occurred due to a direct commit to the repository rather a change occurred with apache/openwhisk#3722 where the openwhisk-admin-tools might not be building during the travis build.

Feature Request: Pg/MySQL/SQLite

Please include necessary libs in the image to use PostgreSQL/MySQL/SQLite/...

In other runtimes

  • PHP supports PDO (and many of its flavors)
  • Many other runtimes can just include it

But Swift doesn't handle pg/mysql/...

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.

Actually...

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.

I know... Docker

But it requires a different set of skills, plus pushing a container to DockerHub, etc... That's a lot of friction.

Publish OpenWhisk Swift handler library as package

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

usage

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.

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.

Define Swift development experience

@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:

  • Allow for use of standard development tools, including Xcode and the Swift CLI.
  • User code should compile cleanly on their development machine (not just in the OW Swift runtime).
  • Some amount of unit testing should be possible on the user's development machine.
  • User should be able to develop multiple OW artifacts (say, all artifacts within a OW package) in the same Swift package/Xcode target.
  • The development experience should be comparable regardless of the platform the developer is using to write their code.

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.