Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Web Secure token for sequences on API create #1087

Merged
merged 8 commits into from
Feb 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deployers/manifestreader.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (reader *ManifestReader) HandleYaml(manifestParser *parsers.YAMLParser, man
return wskderrors.NewYAMLFileFormatError(manifestName, err)
}

apis, responses, err := manifestParser.ComposeApiRecordsFromAllPackages(reader.serviceDeployer.ClientConfig, manifest)
apis, responses, err := manifestParser.ComposeApiRecordsFromAllPackages(reader.serviceDeployer.ClientConfig, manifest, actions, sequences)
if err != nil {
return wskderrors.NewYAMLFileFormatError(manifestName, err)
}
Expand Down
11 changes: 8 additions & 3 deletions deployers/servicedeployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -1012,15 +1012,18 @@ func (deployer *ServiceDeployer) createAction(pkgname string, action *whisk.Acti
return nil
}

func (deployer *ServiceDeployer) getAnnotationsFromPackageAction(packageActionName string) *whisk.KeyValueArr {
func (deployer *ServiceDeployer) getAnnotationsFromPackageActionOrSequence(packageActionName string) *whisk.KeyValueArr {

if len(packageActionName)!=0 {
// Split the package name and action name being searched for
aActionName := strings.Split(packageActionName,"/")
aActionName := strings.Split(packageActionName, parsers.PATH_SEPARATOR)

// Attempt to locate the named action (or sequence) to return its annotations
if pkg, found := deployer.Deployment.Packages[aActionName[0]]; found {
if atemp, found := pkg.Actions[aActionName[1]]; found {
return &(atemp.Action.Annotations)
} else if atemp, found := pkg.Sequences[aActionName[1]]; found {
return &(atemp.Action.Annotations)
}
}
}
Expand All @@ -1041,9 +1044,11 @@ func (deployer *ServiceDeployer) createApi(api *whisk.ApiCreateRequest) error {

// Retrieve annotations on the action we are attempting to create an API for
var actionAnnotations *whisk.KeyValueArr
actionAnnotations = deployer.getAnnotationsFromPackageAction(api.ApiDoc.Action.Name)
actionAnnotations = deployer.getAnnotationsFromPackageActionOrSequence(api.ApiDoc.Action.Name)

// Process any special annotations (e.g., "require-whisk-auth") on the associated Action
// NOTE: we do not throw an error if annotations are NOT found (nil) since this is already done in
// the parsing phase and would be redundant.
if actionAnnotations != nil {
wskprint.PrintlnOpenWhiskVerbose(utils.Flags.Verbose, fmt.Sprintf("Processing action annotations: %v", actionAnnotations))

Expand Down
57 changes: 22 additions & 35 deletions parsers/manifest_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,9 @@ func (dm *YAMLParser) ComposeRules(pkg Package, packageName string, managedAnnot
return rules, nil
}

func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(client *whisk.Config, manifest *YAML) ([]*whisk.ApiCreateRequest, map[string]*whisk.ApiCreateRequestOptions, error) {
func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(client *whisk.Config, manifest *YAML,
actionrecords []utils.ActionRecord,
sequencerecords []utils.ActionRecord) ([]*whisk.ApiCreateRequest, map[string]*whisk.ApiCreateRequestOptions, error) {
var requests = make([]*whisk.ApiCreateRequest, 0)
var responses = make(map[string]*whisk.ApiCreateRequestOptions, 0)
manifestPackages := make(map[string]Package)
Expand All @@ -1143,7 +1145,8 @@ func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(client *whisk.Config, man
}

for packageName, p := range manifestPackages {
r, response, err := dm.ComposeApiRecords(client, packageName, p, manifest.Filepath)
r, response, err := dm.ComposeApiRecords(client, packageName, p, manifest.Filepath,
actionrecords, sequencerecords)
if err == nil {
requests = append(requests, r...)
for k, v := range response {
Expand Down Expand Up @@ -1181,7 +1184,8 @@ func (dm *YAMLParser) ComposeApiRecordsFromAllPackages(client *whisk.Config, man
* }
* }
*/
func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName string, pkg Package, manifestPath string) ([]*whisk.ApiCreateRequest, map[string]*whisk.ApiCreateRequestOptions, error) {
func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName string, pkg Package, manifestPath string,
actionrecords []utils.ActionRecord, sequencerecords []utils.ActionRecord) ([]*whisk.ApiCreateRequest, map[string]*whisk.ApiCreateRequestOptions, error) {
var requests = make([]*whisk.ApiCreateRequest, 0)

// supply a dummy API GW token as it is optional
Expand Down Expand Up @@ -1217,41 +1221,24 @@ func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName string
gatewayRelPath = PATH_SEPARATOR + gatewayRelPath
}
for actionName, gatewayMethodResponse := range gatewayRelPathMap {
// verify that the action is defined under actions sections
// verify that the action is defined under action records
if _, ok := pkg.Actions[actionName]; ok {
// verify that the action is defined as web action
// web or web-export set to any of [true, yes, raw]
a := pkg.Actions[actionName]
if !webaction.IsWebAction(a.GetWeb()) {
warningString := wski18n.T(wski18n.ID_WARN_API_MISSING_WEB_ACTION_X_action_X_api_X,
map[string]interface{}{
wski18n.KEY_ACTION: actionName,
wski18n.KEY_API: apiName})
wskprint.PrintOpenWhiskWarning(warningString)
if a.Annotations == nil {
a.Annotations = make(map[string]interface{}, 0)
}
a.Annotations[webaction.WEB_EXPORT_ANNOT] = true
pkg.Actions[actionName] = a
// verify that the action is defined as web action;
// web or web-export set to any of [true, yes, raw]; if not,
// we will try to add it (if no strict" flag) and warn user that we did so
if err := webaction.TryUpdateAPIsActionToWebAction(actionrecords, packageName,
apiName, actionName, false); err!=nil {
return requests, requestOptions, err
}
// verify that the sequence is defined under sequences sections
// verify that the sequence action is defined under sequence records
} else if _, ok := pkg.Sequences[actionName]; ok {
// verify that the sequence is defined as web sequence
// web set to any of [true, yes, raw]
a := pkg.Sequences[actionName]
if !webaction.IsWebSequence(a.Web) {
warningString := wski18n.T(wski18n.ID_WARN_API_MISSING_WEB_SEQUENCE_X_sequence_X_api_X,
map[string]interface{}{
wski18n.KEY_SEQUENCE: actionName,
wski18n.KEY_API: apiName})
wskprint.PrintOpenWhiskWarning(warningString)
if a.Annotations == nil {
a.Annotations = make(map[string]interface{}, 0)
}
a.Annotations[webaction.WEB_EXPORT_ANNOT] = true
pkg.Sequences[actionName] = a
// verify that the sequence action is defined as web sequence
// web or web-export set to any of [true, yes, raw]; if not,
// we will try to add it (if no strict" flag) and warn user that we did so
if err := webaction.TryUpdateAPIsActionToWebAction(sequencerecords, packageName,
apiName, actionName, true); err!=nil {
return requests, requestOptions, err
}
// return failure since action or sequence are not defined in the manifest
} else {
return nil, nil, wskderrors.NewYAMLFileFormatError(manifestPath,
wski18n.T(wski18n.ID_ERR_API_MISSING_ACTION_OR_SEQUENCE_X_action_or_sequence_X_api_X,
Expand All @@ -1275,7 +1262,7 @@ func (dm *YAMLParser) ComposeApiRecords(client *whisk.Config, packageName string
gatewayMethodResponse.Response = utils.HTTP_FILE_EXTENSION
}

// Chekc if API verb is valid, it must be one of (GET, PUT, POST, DELETE)
// Check if API verb is valid, it must be one of (GET, PUT, POST, DELETE)
if _, ok := whisk.ApiVerbs[strings.ToUpper(gatewayMethodResponse.Method)]; !ok {
return nil, nil, wskderrors.NewInvalidAPIGatewayMethodError(manifestPath,
gatewayBasePath+gatewayRelPath,
Expand Down
2 changes: 1 addition & 1 deletion parsers/manifest_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1576,7 +1576,7 @@ func TestComposeApiRecords(t *testing.T) {
ApigwAccessToken: "token",
}

apiList, apiRequestOptions, err := p.ComposeApiRecordsFromAllPackages(&config, m)
apiList, apiRequestOptions, err := p.ComposeApiRecordsFromAllPackages(&config, m, nil, nil)
if err != nil {
assert.Fail(t, "Failed to compose api records: "+err.Error())
}
Expand Down
7 changes: 7 additions & 0 deletions specification/html/spec_sequences.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ sequences:
<sequence name>:
<Entity schema>
actions: <ordered list of action names>
web: <boolean> | yes | no | raw
annotations:
<map of annotation key-values>
web-export: <boolean> | yes | no | raw # optional
web-custom-options: <boolean> # optional, only valid when `web-export` enabled
require-whisk-auth: <boolean> | <string> | <positive integer> # optional, only valid when `web-export` enabled
...
```

Expand All @@ -75,6 +81,7 @@ sequences:
sequences:
newbot:
actions: newbot-create, newbot-select-persona, newbot-greeting
web: true
```

<!--
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#
# 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.
#

# TODO automate this testcase
# Test automatically adding web annotations on Actions that do not have them declared
# when these actions are used to create APIs.
# 1) Test an Action missing web-export, but with existing Annotations declared
# 2) Test a Sequence missing web-export with NO existing Annotations (to verify we allocate)
# 3) Test if web-action is set to false that we error out as we cannot override explicit value
packages:
TestMissingWebAnnotation:
actions:
hello_validate:
function: src/hello_http_validate.js
hello:
function: src/hello.js
annotations:
foo: bar
hello_wrap:
function: src/hello_http_wrap.js
helloWebFalse:
function: src/hello.js
web: false
sequences:
hellosequence:
actions: hello_validate, hello, hello_wrap
apis:
actionmissingweb:
helloworlds:
helloweb:
hello:
method: GET
response: http
hellosequence:
method: GET
response: http
helloWebFalse:
method: GET
response: http
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#
# 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.
#

packages:
hellosequencespkg:
version: 1.0
license: Apache-2.0
actions:
hello_validate:
function: src/hello_http_validate.js
hello:
function: src/hello.js
hello_wrap:
function: src/hello_http_wrap.js
sequences:
hellosequence:
actions: hello_validate, hello, hello_wrap
web: true
annotations:
require-whisk-auth: "mytoken"
apis:
web-secure-sequences:
helloworlds:
hellosequence:
hellosequence:
method: GET
response: http
24 changes: 24 additions & 0 deletions tests/src/integration/webaction/src/hello.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.
*/

/*
* Hello, world
*/
function main(params) {
msg = "Hello, " + params.name + " from " + params.place;
return { greeting: msg };
}
36 changes: 36 additions & 0 deletions tests/src/integration/webaction/src/hello_http_validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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.
*/

/*
* This action validates the parameters passed to the hello world action and
* returns an error if any of them is missing.
*/
function main(params) {
if(params.name && params.place) {
return params;
} else {
return {
error: {
body: {
message: 'Attributes name and place are mandatory'
},
statusCode: 400,
headers: {'Content-Type': 'application/json'}
}
}
}
}
28 changes: 28 additions & 0 deletions tests/src/integration/webaction/src/hello_http_wrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.
*/

/*
* This action take a result from the previous action and wraps it into a
* HTTP response structure.
*/
function main(params) {
return {
body: params,
statusCode: 200,
headers: {'Content-Type': 'application/json'}
};
}
11 changes: 11 additions & 0 deletions utils/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,14 @@ func getKeyValueFormattedJSON(data map[string]interface{}) whisk.KeyValueArr {
}
return keyValueArr
}

func GetActionFromActionRecords( records []ActionRecord, packageName string, actionName string ) *whisk.Action {
for _, record := range records {
if record.Packagename == packageName {
if record.Action.Name == actionName {
return record.Action
}
}
}
return nil
}
Loading