You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2018/02/07 21:05:27 UTC
[GitHub] pritidesai closed pull request #703: WIP: adding support for API Gateway - needs rebase
pritidesai closed pull request #703: WIP: adding support for API Gateway - needs rebase
URL: https://github.com/apache/incubator-openwhisk-wskdeploy/pull/703
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/deployers/manifestreader.go b/deployers/manifestreader.go
index a8df3851..55c2b145 100644
--- a/deployers/manifestreader.go
+++ b/deployers/manifestreader.go
@@ -93,7 +93,7 @@ func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, manifestP
return wskderrors.NewYAMLFileFormatError(manifestName, err)
}
- apis, err := manifestParser.ComposeApiRecordsFromAllPackages(manifest)
+ apis, err := manifestParser.ComposeApiRecordsFromAllPackages(deployer.serviceDeployer.ClientConfig, manifest)
if err != nil {
return wskderrors.NewYAMLFileFormatError(manifestName, err)
}
@@ -373,12 +373,11 @@ func (reader *ManifestReader) SetRules(rules []*whisk.Rule) error {
func (reader *ManifestReader) SetApis(ar []*whisk.ApiCreateRequest) error {
dep := reader.serviceDeployer
- var apis []*whisk.ApiCreateRequest = make([]*whisk.ApiCreateRequest, 0)
dep.mt.Lock()
defer dep.mt.Unlock()
- for _, api := range apis {
+ for _, api := range ar {
existApi, exist := dep.Deployment.Apis[api.ApiDoc.ApiName]
if exist {
existApi.ApiDoc.ApiName = api.ApiDoc.ApiName
diff --git a/deployers/servicedeployer.go b/deployers/servicedeployer.go
index 72f3540f..9784da41 100644
--- a/deployers/servicedeployer.go
+++ b/deployers/servicedeployer.go
@@ -932,9 +932,15 @@ func (deployer *ServiceDeployer) createApi(api *whisk.ApiCreateRequest) error {
var err error
var response *http.Response
+ apiCreateReqOptions := new(whisk.ApiCreateRequestOptions)
+ apiCreateReqOptions.SpaceGuid = strings.Split(deployer.Client.Config.AuthToken, ":")[0]
+ // TODO add APIGW_ACCESS_TOKEN
+ apiCreateReqOptions.AccessToken = deployer.Client.Config.ApigwAccessToken
+ apiCreateReqOptions.ResponseType = "json"
+
// TODO() Is there an api delete function? could not find it
err = retry(DEFAULT_ATTEMPTS, DEFAULT_INTERVAL, func() error {
- _, response, err = deployer.Client.Apis.Insert(api, nil, true)
+ _, response, err = deployer.Client.Apis.Insert(api, apiCreateReqOptions, true)
return err
})
diff --git a/deployers/whiskclient.go b/deployers/whiskclient.go
index 715750ce..c09a3398 100644
--- a/deployers/whiskclient.go
+++ b/deployers/whiskclient.go
@@ -63,8 +63,8 @@ var GetWskPropFromWhiskProperty = func(pi whisk.Properties) (*whisk.Wskprops, er
return whisk.GetWskPropFromWhiskProperty(pi)
}
-var GetCommandLineFlags = func() (string, string, string, string, string) {
- return utils.Flags.ApiHost, utils.Flags.Auth, utils.Flags.Namespace, utils.Flags.Key, utils.Flags.Cert
+var GetCommandLineFlags = func() (string, string, string, string, string, string) {
+ return utils.Flags.ApiHost, utils.Flags.Auth, utils.Flags.Namespace, utils.Flags.Key, utils.Flags.Cert, utils.Flags.ApigwAccessToken
}
var CreateNewClient = func(config_input *whisk.Config) (*whisk.Client, error) {
@@ -80,6 +80,8 @@ var CreateNewClient = func(config_input *whisk.Config) (*whisk.Client, error) {
// (3) manifest file
// (4) .wskprops
// (5) prompt for values in interactive mode if any of them are missing
+// we are following the same precedence order for APIGW_ACCESS_TOKEN
+// but in a separate thread as APIGW_ACCESS_TOKEN only needed for APIs
func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string, isInteractive bool) (*whisk.Config, error) {
// struct to store credential, namespace, and host with their respective source
credential := PropertyValue{}
@@ -87,14 +89,16 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
apiHost := PropertyValue{}
key := PropertyValue{}
cert := PropertyValue{}
+ apigwAccessToken := PropertyValue{}
// read credentials from command line
- apihost, auth, ns, keyfile, certfile := GetCommandLineFlags()
+ apihost, auth, ns, keyfile, certfile, accessToken := GetCommandLineFlags()
credential = GetPropertyValue(credential, auth, wski18n.COMMAND_LINE)
namespace = GetPropertyValue(namespace, ns, wski18n.COMMAND_LINE)
apiHost = GetPropertyValue(apiHost, apihost, wski18n.COMMAND_LINE)
key = GetPropertyValue(key, keyfile, wski18n.COMMAND_LINE)
cert = GetPropertyValue(cert, certfile, wski18n.COMMAND_LINE)
+ apigwAccessToken = GetPropertyValue(apigwAccessToken, accessToken, wski18n.COMMAND_LINE)
// TODO() i18n
// Print all flags / values if verbose
@@ -119,6 +123,15 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
}
}
+ // read APIGW_ACCESS_TOKEN if not found on command line
+ if len(apigwAccessToken.Value) == 0 {
+ mm := parsers.NewYAMLParser()
+ deployment, _ := mm.ParseDeployment(deploymentPath)
+ apigwAccessToken = GetPropertyValue(apigwAccessToken,
+ deployment.GetProject().ApigwAccessToken,
+ path.Base(deploymentPath))
+ }
+
// TODO() split this logic into its own function
// TODO() merge with the same logic used against deployment file (above)
// read credentials from manifest file as didn't find them on command line and in deployment file
@@ -154,6 +167,25 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
}
}
+ if len(apigwAccessToken.Value) == 0 {
+ if utils.FileExists(manifestPath) {
+ mm := parsers.NewYAMLParser()
+ manifest, _ := mm.ParseManifest(manifestPath)
+ if manifest.Package.Packagename != "" {
+ apigwAccessToken = GetPropertyValue(apigwAccessToken,
+ manifest.Package.ApigwAccessToken,
+ path.Base(manifestPath))
+ } else if manifest.Packages != nil {
+ if len(manifest.Packages) == 1 {
+ for _, pkg := range manifest.Packages {
+ apigwAccessToken = GetPropertyValue(apigwAccessToken,
+ pkg.ApigwAccessToken,
+ path.Base(manifestPath))
+ }
+ }
+ } }
+ }
+
// Third, we need to look up the variables in .wskprops file.
pi := whisk.PropertiesImp{
OsPackage: whisk.OSPackageImp{},
@@ -166,6 +198,7 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
apiHost = GetPropertyValue(apiHost, wskprops.APIHost, SOURCE_WSKPROPS)
key = GetPropertyValue(key, wskprops.Key, SOURCE_WSKPROPS)
cert = GetPropertyValue(cert, wskprops.Cert, SOURCE_WSKPROPS)
+ apigwAccessToken = GetPropertyValue(apigwAccessToken, wskprops.AuthAPIGWKey, SOURCE_WSKPROPS)
// TODO() see if we can split the following whisk prop logic into a separate function
// now, read credentials from whisk.properties but this is only acceptable within Travis
@@ -192,6 +225,12 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
map[string]interface{}{wski18n.KEY_KEY: wski18n.API_HOST})
wskprint.PrintlnOpenWhiskWarning(warnMsg)
}
+ apigwAccessToken = GetPropertyValue(apigwAccessToken, whiskproperty.AuthAPIGWKey, SOURCE_WHISK_PROPERTIES)
+ if apigwAccessToken.Source == SOURCE_WHISK_PROPERTIES {
+ warnMsg = wski18n.T(wski18n.ID_WARN_WHISK_PROPS_DEPRECATED,
+ map[string]interface{}{wski18n.KEY_KEY: wski18n.APIGW_ACCESS_TOKEN})
+ wskprint.PrintlnOpenWhiskWarning(warnMsg)
+ }
// set namespace to default namespace if not yet found
if len(apiHost.Value) != 0 && len(credential.Value) != 0 && len(namespace.Value) == 0 {
@@ -235,6 +274,12 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
}
}
+ if len(apigwAccessToken.Value) == 0 && isInteractive == true {
+ accessToken := promptForValue(wski18n.T(wski18n.APIGW_ACCESS_TOKEN))
+ apigwAccessToken.Value = accessToken
+ apigwAccessToken.Source = SOURCE_INTERACTIVE_INPUT
+ }
+
mode := true
if (len(cert.Value) != 0 && len(key.Value) != 0) {
mode = false
@@ -248,6 +293,7 @@ func NewWhiskConfig(proppath string, deploymentPath string, manifestPath string,
Cert: cert.Value,
Key: key.Value,
Insecure: mode, // true if you want to ignore certificate signing
+ ApigwAccessToken: apigwAccessToken.Value,
}
// validate we have credential, apihost and namespace
diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index 37d318e6..7aa88e11 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -4,162 +4,6 @@
* 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.
- */
-
-package parsers
-
-import (
- "errors"
- "io/ioutil"
- "os"
- "path"
- "strings"
- "encoding/base64"
- "fmt"
- "gopkg.in/yaml.v2"
-
- "github.com/apache/incubator-openwhisk-client-go/whisk"
- "github.com/apache/incubator-openwhisk-wskdeploy/utils"
- "github.com/apache/incubator-openwhisk-wskdeploy/wski18n"
- "github.com/apache/incubator-openwhisk-wskdeploy/wskderrors"
- "github.com/apache/incubator-openwhisk-wskdeploy/wskenv"
- "github.com/apache/incubator-openwhisk-wskdeploy/wskprint"
-)
-
-// Read existing manifest file or create new if none exists
-func ReadOrCreateManifest() (*YAML, error) {
- maniyaml := YAML{}
-
- if _, err := os.Stat(utils.ManifestFileNameYaml); err == nil {
- dat, _ := ioutil.ReadFile(utils.ManifestFileNameYaml)
- err := NewYAMLParser().Unmarshal(dat, &maniyaml)
- if err != nil {
- return &maniyaml, wskderrors.NewFileReadError(utils.ManifestFileNameYaml, err.Error())
- }
- }
- return &maniyaml, nil
-}
-
-// Serialize manifest to local file
-func Write(manifest *YAML, filename string) error {
- output, err := NewYAMLParser().marshal(manifest)
- if err != nil {
- return wskderrors.NewYAMLFileFormatError(filename, err.Error())
- }
-
- f, err := os.Create(filename)
- if err != nil {
- return wskderrors.NewFileReadError(filename, err.Error())
- }
- defer f.Close()
-
- f.Write(output)
- return nil
-}
-
-func (dm *YAMLParser) Unmarshal(input []byte, manifest *YAML) error {
- err := yaml.UnmarshalStrict(input, manifest)
- if err != nil {
- return err
- }
- return nil
-}
-
-func (dm *YAMLParser) marshal(manifest *YAML) (output []byte, err error) {
- data, err := yaml.Marshal(manifest)
- if err != nil {
- return nil, err
- }
- return data, nil
-}
-
-func (dm *YAMLParser) ParseManifest(manifestPath string) (*YAML, error) {
- mm := NewYAMLParser()
- maniyaml := YAML{}
-
- content, err := utils.Read(manifestPath)
- if err != nil {
- return &maniyaml, wskderrors.NewFileReadError(manifestPath, err.Error())
- }
-
- err = mm.Unmarshal(content, &maniyaml)
- if err != nil {
- return &maniyaml, wskderrors.NewYAMLParserErr(manifestPath, err)
- }
- maniyaml.Filepath = manifestPath
- manifest := ReadEnvVariable(&maniyaml)
-
- return manifest, nil
-}
-
-func (dm *YAMLParser) ComposeDependenciesFromAllPackages(manifest *YAML, projectPath string, filePath string) (map[string]utils.DependencyRecord, error) {
- dependencies := make(map[string]utils.DependencyRecord)
- packages := make(map[string]Package)
- if manifest.Package.Packagename != "" {
- return dm.ComposeDependencies(manifest.Package, projectPath, filePath, manifest.Package.Packagename)
- } else {
- if len(manifest.Packages) != 0 {
- packages = manifest.Packages
- } else {
- packages = manifest.GetProject().Packages
- }
- }
-
- for n, p := range packages {
- d, err := dm.ComposeDependencies(p, projectPath, filePath, n)
- if err == nil {
- for k, v := range d {
- dependencies[k] = v
- }
- } else {
- return nil, err
- }
- }
- return dependencies, nil
-}
-
-func (dm *YAMLParser) ComposeDependencies(pkg Package, projectPath string, filePath string, packageName string) (map[string]utils.DependencyRecord, error) {
-
- var errorParser error
- depMap := make(map[string]utils.DependencyRecord)
- for key, dependency := range pkg.Dependencies {
- version := dependency.Version
- if version == "" {
- // TODO() interactive ask for branch, AND consider YAML specification to allow key for branch
- version = YAML_VALUE_BRANCH_MASTER
- }
-
- location := dependency.Location
-
- isBinding := false
- if utils.LocationIsBinding(location) {
-
- if !strings.HasPrefix(location, "/") {
- location = "/" + dependency.Location
- }
-
- isBinding = true
- } else if utils.LocationIsGithub(location) {
-
- // TODO() define const for the protocol prefix, etc.
- if !strings.HasPrefix(location, "https://") && !strings.HasPrefix(location, "http://") {
- location = "https://" + dependency.Location
- }
-
- isBinding = false
- } else {
- // TODO() create new named error in wskerrors package
- return nil, errors.New(wski18n.T(wski18n.ID_ERR_DEPENDENCY_UNKNOWN_TYPE))
- }
keyValArrParams := make(whisk.KeyValueArr, 0)
for name, param := range dependency.Inputs {
@@ -856,12 +700,12 @@ func (dm *YAMLParser) ComposeRules(pkg Package, packageName string) ([]*whisk.Ru
return r1, nil
}
-func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(manifest *YAML) ([]*whisk.ApiCreateRequest, error) {
+func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(client *whisk.Config, manifest *YAML) ([]*whisk.ApiCreateRequest, error) {
var requests []*whisk.ApiCreateRequest = make([]*whisk.ApiCreateRequest, 0)
manifestPackages := make(map[string]Package)
if manifest.Package.Packagename != "" {
- return dm.ComposeApiRecords(manifest.Package)
+ return dm.ComposeApiRecords(client, manifest.Package.Packagename, manifest.Package, manifest.Filepath)
} else {
if len(manifest.Packages) != 0 {
manifestPackages = manifest.Packages
@@ -870,8 +714,8 @@ func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(manifest *YAML) ([]*whisk
}
}
- for _, p := range manifestPackages {
- r, err := dm.ComposeApiRecords(p)
+ for packageName, p := range manifestPackages {
+ r, err := dm.ComposeApiRecords(client, packageName, p, manifest.Filepath)
if err == nil {
requests = append(requests, r...)
} else {
@@ -881,14 +725,94 @@ func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(manifest *YAML) ([]*whisk
return requests, nil
}
-func (dm *YAMLParser) ComposeApiRecords(pkg Package) ([]*whisk.ApiCreateRequest, error) {
- var acq []*whisk.ApiCreateRequest = make([]*whisk.ApiCreateRequest, 0)
- apis := pkg.GetApis()
+/*
+ * read API section from manifest file:
+ * apis: # List of APIs
+ * hello-world: #API name
+ * /hello: #gateway base path
+ * /world: #gateway rel path
+ * greeting: get #action name: gateway method
+ *
+ * compose APIDoc structure from the manifest:
+ * {
+ * "apidoc":{
+ * "namespace":<namespace>,
+ * "gatewayBasePath":"/hello",
+ * "gatewayPath":"/world",
+ * "gatewayMethod":"GET",
+ * "action":{
+ * "name":"hello",
+ * "namespace":"guest",
+ * "backendMethod":"GET",
+ * "backendUrl":<url>,
+ * "authkey":<auth>
+ * }
+ * }
+ * }
+ */
+func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName string, pkg Package, manifestPath string) ([]*whisk.ApiCreateRequest, error) {
+ var requests []*whisk.ApiCreateRequest = make([]*whisk.ApiCreateRequest, 0)
+
+ for apiName, apiDoc := range pkg.Apis {
+ for gatewayBasePath, gatewayBasePathMap := range apiDoc {
+ // is gateway base path valid, it must begin with /
+ if !strings.HasPrefix(gatewayBasePath, "/") {
+ return nil, wskderrors.NewInvalidAPIPathError("Base path must begin with /", manifestPath, gatewayBasePath)
+ }
+ for gatewayRelPath, gatewayRelPathMap := range gatewayBasePathMap {
+ // is gateway relative path valid, it must begin with /
+ if !strings.HasPrefix(gatewayRelPath, "/") {
+ return nil, wskderrors.NewInvalidAPIPathError("Relative path must begin with /", manifestPath, gatewayRelPath)
+ }
+ for actionName, gatewayMethod := range gatewayRelPathMap {
+ // verify that the action is defined under actions sections
+ if _, ok := pkg.Actions[actionName]; ok {
+ // verify that the action is defined as web action
+ web := pkg.Actions[actionName].Webexport
+ // (TODO) Convert web export in Action struct from string to bool
+ if strings.ToUpper(web) == "TRUE" {
+ request := new(whisk.ApiCreateRequest)
+ request.ApiDoc = new(whisk.Api)
+ request.ApiDoc.GatewayBasePath = gatewayBasePath
+ // is API verb is valid, it must be one of (GET, PUT, POST, DELETE)
+ request.ApiDoc.GatewayRelPath = gatewayRelPath
+ if _, ok := whisk.ApiVerbs[strings.ToUpper(gatewayMethod)]; !ok {
+ return nil, wskderrors.NewInvalidAPIGatewayMethodError(manifestPath,
+ gatewayBasePath + gatewayRelPath,
+ gatewayMethod,
+ dm.getGatewayMethods())
+ }
+ request.ApiDoc.GatewayMethod = strings.ToUpper(gatewayMethod)
+ request.ApiDoc.Namespace = client.Namespace
+ request.ApiDoc.ApiName = apiName
+ request.ApiDoc.Id = "API:" + request.ApiDoc.Namespace + ":" + request.ApiDoc.GatewayRelPath
+
+ request.ApiDoc.Action = new(whisk.ApiAction)
+ request.ApiDoc.Action.Name = packageName + "/" + actionName
+ request.ApiDoc.Action.Namespace = client.Namespace
+ request.ApiDoc.Action.BackendUrl = "https://" + client.Host + "/api/v1/web/" +
+ client.Namespace + "/" + packageName + "/" + actionName + ".http"
+ request.ApiDoc.Action.BackendMethod = gatewayMethod
+ request.ApiDoc.Action.Auth = client.AuthToken
+
+ requests = append(requests, request)
+ } else {
+ //(TODO) exit with WARNING
+ }
+ } else {
+ //(TODO) exit with WARNING
+ }
+ }
+ }
+ }
+ }
+ return requests, nil
+}
- for _, api := range apis {
- acr := new(whisk.ApiCreateRequest)
- acr.ApiDoc = api
- acq = append(acq, acr)
+func (dm *YAMLParser) getGatewayMethods() []string {
+ methods := []string{}
+ for k := range whisk.ApiVerbs {
+ methods = append(methods, k)
}
- return acq, nil
+ return methods
}
diff --git a/parsers/yamlparser.go b/parsers/yamlparser.go
index 6bcee666..788441b5 100644
--- a/parsers/yamlparser.go
+++ b/parsers/yamlparser.go
@@ -194,6 +194,7 @@ type Package struct {
Namespace string `yaml:"namespace"` //used in both manifest.yaml and deployment.yaml
Credential string `yaml:"credential"` //used in both manifest.yaml and deployment.yaml
ApiHost string `yaml:"apiHost"` //used in both manifest.yaml and deployment.yaml
+ ApigwAccessToken string `yaml:"apigwAccessToken"` //used in both manifest.yaml and deployment.yaml
Actions map[string]Action `yaml:"actions"` //used in both manifest.yaml and deployment.yaml
Triggers map[string]Trigger `yaml:"triggers"` //used in both manifest.yaml and deployment.yaml
Feeds map[string]Feed `yaml:"feeds"` //used in both manifest.yaml and deployment.yaml
@@ -210,6 +211,7 @@ type Project struct {
Namespace string `yaml:"namespace"` //used in deployment.yaml
Credential string `yaml:"credential"`
ApiHost string `yaml:"apiHost"`
+ ApigwAccessToken string `yaml:"apigwAccessToken"` //used in both manifest.yaml and deployment.yaml
Version string `yaml:"version"`
Packages map[string]Package `yaml:"packages"` //used in deployment.yaml
Package Package `yaml:"package"` // being deprecated, used in deployment.yaml
diff --git a/tests/dat/deployment_validate_credentials.yaml b/tests/dat/deployment_validate_credentials.yaml
index e44868d3..5fb12f96 100644
--- a/tests/dat/deployment_validate_credentials.yaml
+++ b/tests/dat/deployment_validate_credentials.yaml
@@ -1,4 +1,4 @@
-# do not change or delete this file without changing deployers/whiskclient_test.go
+
# this is used for testing whiskclient functionality
project:
name: UnitTestCredentials
diff --git a/tests/src/integration/apigateway/manifest.yml b/tests/src/integration/apigateway/manifest.yml
index 56286e54..320fedda 100644
--- a/tests/src/integration/apigateway/manifest.yml
+++ b/tests/src/integration/apigateway/manifest.yml
@@ -1,34 +1,41 @@
packages:
- api-gateway-test:
- version: 1.0
- license: Apache-2.0
- actions:
- greeting:
- version: 1.0
- function: src/greeting.js
- runtime: nodejs:6
- inputs:
- name: string
- place: string
- outputs:
- payload: string
- apis: # new top-level key for defining groups of named APIs
- book-club: #api name
- club: # shared base path
- books: #path
- getBooks: get #action name:verb
- postBooks: post
- putBooks: put
- deleteBooks: delete
- members: #path
- listMembers: get #action name:verb
- book-club2: #api name, added for multi api definition test
- club2: # shared base path
- books2: #path
- getBooks2: get #action name:verb
- postBooks2: post
- putBooks2: put
- deleteBooks2: delete
- members2: #path
- listMembers2: get #action name:verb
-
+ api-gateway-test:
+ version: 1.0
+ license: Apache-2.0
+ actions:
+ greeting:
+ web-export: true
+ version: 1.0
+ function: src/greeting.js
+ runtime: nodejs:6
+ getBooks:
+ web-export: true
+ function: src/get-books.js
+# postBooks:
+# web-export: true
+# function: src/post-books.js
+# putBooks:
+# web-export: true
+# function: src/put-books.js
+# deleteBooks:
+# web-export: true
+# function: src/delete-books.js
+# listMembers:
+# web-export: true
+# function: src/list-members.js
+ # new top-level key for defining groups of named APIs
+ apis:
+ hello-world:
+ /hello:
+ /world:
+ greeting: GET
+ book-club:
+ /club:
+ /books:
+ getBooks: GET
+# postBooks: POST
+# putBooks: PUT
+# deleteBooks: DELETE
+# /members:
+# listMembers: GET
+
diff --git a/tests/src/integration/apigateway/src/get-books.js b/tests/src/integration/apigateway/src/get-books.js
new file mode 100644
index 00000000..9b026a61
--- /dev/null
+++ b/tests/src/integration/apigateway/src/get-books.js
@@ -0,0 +1,13 @@
+/**
+ * Return a simple greeting message for someone.
+ *
+ * @param name A person's name.
+ * @param place Where the person is from.
+ */
+function main() {
+ return {
+ body: new Buffer(JSON.stringify({result:[{"name":"JavaScript: The Good Parts", "isbn":"978-0596517748"}]})).toString('base64'),
+ statusCode: 200,
+ headers:{ 'Content-Type': 'application/json'}
+ };
+}
diff --git a/tests/src/integration/apigateway/src/greeting.js b/tests/src/integration/apigateway/src/greeting.js
index 7c069f1e..c9e6edab 100644
--- a/tests/src/integration/apigateway/src/greeting.js
+++ b/tests/src/integration/apigateway/src/greeting.js
@@ -4,9 +4,10 @@
* @param name A person's name.
* @param place Where the person is from.
*/
-function main(params) {
- var name = params.name || params.payload || 'stranger';
- var place = params.place || 'somewhere';
- return {payload: 'Hello, ' + name + ' from ' + place + '!'};
+function main({name:name='Serverless API Gateway'}) {
+ return {
+ body: new Buffer(JSON.stringify({payload:`Hello world ${name}`})).toString('base64'),
+ statusCode: 200,
+ headers:{ 'Content-Type': 'application/json'}
+ };
}
-
diff --git a/utils/flags.go b/utils/flags.go
index 6cbc0d9e..226e6781 100644
--- a/utils/flags.go
+++ b/utils/flags.go
@@ -27,6 +27,7 @@ type WskDeployFlags struct {
ApiHost string // OpenWhisk API host
Auth string // OpenWhisk API key
Namespace string
+ ApigwAccessToken string
ApiVersion string // OpenWhisk version
CfgFile string
CliVersion string
diff --git a/wskderrors/wskdeployerror.go b/wskderrors/wskdeployerror.go
index c7d5e83a..4429def0 100644
--- a/wskderrors/wskdeployerror.go
+++ b/wskderrors/wskdeployerror.go
@@ -42,6 +42,9 @@ const (
STR_SUPPORTED_RUNTIMES = "Supported Runtimes"
STR_HTTP_STATUS = "HTTP Response Status"
STR_HTTP_BODY = "HTTP Response Body"
+ STR_API = "API"
+ STR_API_METHOD = "API gateway method"
+ STR_API_SUPPORTED_METHODS = "API gateway supported methods"
// Formatting
STR_INDENT_1 = "==>"
@@ -57,6 +60,8 @@ const (
ERROR_YAML_PARAMETER_TYPE_MISMATCH = "ERROR_YAML_PARAMETER_TYPE_MISMATCH"
ERROR_YAML_INVALID_PARAMETER_TYPE = "ERROR_YAML_INVALID_PARAMETER_TYPE"
ERROR_YAML_INVALID_RUNTIME = "ERROR_YAML_INVALID_RUNTIME"
+ ERROR_YAML_INVALID_API_GATEWAY_METHOD = "ERROR_YAML_INVALID_API_GATEWAY_METHOD"
+ ERROR_YAML_INVALID_API_PATH = "ERROR_YAML_INVALID_API_PATH"
)
/*
@@ -389,6 +394,48 @@ func NewInvalidRuntimeError(errMessage string, fpath string, action string, runt
return err
}
+/*
+ * Invalid API Gateway Method
+ */
+type InvalidAPIGatewayMethodError struct {
+ FileError
+ method string
+ SupportedMethods []string
+}
+
+func NewInvalidAPIGatewayMethodError(fpath string, api string, method string, supportedMethods []string) *InvalidAPIGatewayMethodError {
+ var err = &InvalidAPIGatewayMethodError{
+ SupportedMethods: supportedMethods,
+ }
+ err.SetErrorFilePath(fpath)
+ err.SetErrorType(ERROR_YAML_INVALID_API_GATEWAY_METHOD)
+ err.SetCallerByStackFrameSkip(2)
+ str := fmt.Sprintf("%s [%s]: %s [%s]: %s [%s]",
+ STR_API, api,
+ STR_API_METHOD, method,
+ STR_API_SUPPORTED_METHODS, strings.Join(supportedMethods, ", "))
+ err.SetMessage(str)
+ return err
+}
+
+/*
+ * Invalid API Path
+ */
+type InvalidAPIPathError struct {
+ FileError
+}
+
+func NewInvalidAPIPathError(errMessage string, fpath string, api string) *InvalidAPIPathError {
+ var err = &InvalidAPIPathError{}
+ err.SetErrorFilePath(fpath)
+ err.SetErrorType(ERROR_YAML_INVALID_API_PATH)
+ err.SetCallerByStackFrameSkip(2)
+ str := fmt.Sprintf("%s %s [%s]",
+ errMessage,
+ STR_API, api)
+ err.SetMessage(str)
+ return err
+}
func IsCustomError( err error ) bool {
switch err.(type) {
diff --git a/wski18n/i18n_ids.go b/wski18n/i18n_ids.go
index 8f8b544e..1c5a6b21 100644
--- a/wski18n/i18n_ids.go
+++ b/wski18n/i18n_ids.go
@@ -48,6 +48,7 @@ const (
TRIGGER_FEED = "trigger feed"
TRIGGERS = "Triggers"
WHISK_PROPS = "wskprops"
+ APIGW_ACCESS_TOKEN = "API Gateway Access Token"
)
// i18n Identifiers
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services