Skip to content

fail trigger delete when associated feed deletion fails #476

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions commands/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type FlagsStruct struct {
detail bool
format string
nameSort bool // sorts list alphabetically by entity name
force bool
}

property struct {
Expand Down
30 changes: 29 additions & 1 deletion commands/trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package commands
import (
"errors"
"fmt"
"strings"

"github.com/apache/openwhisk-cli/wski18n"
"github.com/apache/openwhisk-client-go/whisk"
Expand Down Expand Up @@ -286,6 +287,30 @@ var triggerDeleteCmd = &cobra.Command{
err = configureFeed(qualifiedName.GetEntityName(), fullFeedName, getParameters(Flags.common.param, false, false))
if err != nil {
whisk.Debug(whisk.DbgError, "configureFeed(%s, %s) failed: %s\n", qualifiedName.GetEntityName(), fullFeedName, err)

// If the trigger feed does not exist, it's deleted! This error message will look like
// "could not find trigger /NAMESPACE_ID/TRIGGER_NAME in the database"
// OR if the feed action is not present, there's no way to clean up the feed
// "The requested resource does not exist"
// likewise, if the feed action has no code, there's no way to clean up the feed
// "Missing main/no code to execute"
if strings.Contains(err.Error(), "could not find trigger") {
whisk.Debug(whisk.DbgWarn, "trigger feed is already deleted for trigger %s\n", qualifiedName.GetEntityName())
} else if strings.Contains(err.Error(), "The requested resource does not exist") {
whisk.Debug(whisk.DbgWarn, "trigger feed action '%s' does not exist\n", fullFeedName)
} else if strings.Contains(err.Error(), "no code to execute") {
whisk.Debug(whisk.DbgWarn, "trigger feed action '%s' does not contain valid code\n", fullFeedName)
} else {
errStr := wski18n.T("Unable to delete trigger '{{.name}}': {{.err}}",
map[string]interface{}{"name": qualifiedName.GetEntityName(), "err": err})

if !Flags.common.force {
werr := whisk.MakeWskErrorFromWskError(errors.New(errStr), err, whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE)
return werr
} else {
whisk.Debug(whisk.DbgInfo, "trigger delete is forced despite feed deletion failure\n")
}
}
}

Flags.common.param = origParams
Expand Down Expand Up @@ -370,7 +395,7 @@ func configureFeed(triggerName string, feedName string, parameters interface{})
if err != nil {
whisk.Debug(whisk.DbgError, "Invoke of action '%s' failed: %s\n", feedName, err)
errStr := wski18n.T(FEED_CONFIGURATION_FAILURE, map[string]interface{}{"feedname": feedName, "trigname": triggerName, "err": err})
err = whisk.MakeWskErrorFromWskError(errors.New(errStr), err, whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE)
err = whisk.MakeWskError(errors.New(errStr), whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE)
} else {
whisk.Debug(whisk.DbgInfo, "Successfully configured trigger feed via feed action '%s'\n", feedName)
}
Expand Down Expand Up @@ -405,6 +430,8 @@ func init() {

triggerGetCmd.Flags().BoolVarP(&Flags.trigger.summary, "summary", "s", false, wski18n.T("summarize trigger details; parameters with prefix \"*\" are bound"))

triggerDeleteCmd.Flags().BoolVarP(&Flags.common.force, "force", "f", false, wski18n.T("force trigger deletion even when feed deletion fails"))

triggerFireCmd.Flags().StringSliceVarP(&Flags.common.param, "param", "p", []string{}, wski18n.T("parameter values in `KEY VALUE` format"))
triggerFireCmd.Flags().StringVarP(&Flags.common.paramFile, "param-file", "P", "", wski18n.T("`FILE` containing parameter values in JSON format"))

Expand Down Expand Up @@ -477,6 +504,7 @@ func (t *Trigger) Create(Client *whisk.Client, args []string) error {
printFailedBlockingInvocationResponse(*feedName, false, res, err)

reason := wski18n.T(FEED_CONFIGURATION_FAILURE, map[string]interface{}{"feedname": feedName.GetFullQualifiedName(), "err": err})

errStr := wski18n.T("Unable to create trigger '{{.name}}': {{.err}}",
map[string]interface{}{"name": trigger.Name, "err": reason})
werr := whisk.MakeWskErrorFromWskError(errors.New(errStr), err, whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE)
Expand Down
37 changes: 37 additions & 0 deletions tests/src/dat/feed-action-fails-delete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.
*/
function main(params) {
var bodyobj = params || {};
var sc = params.statusCode || 412;
bodystr = JSON.stringify(bodyobj);
var resp = {}
if (sc >=200 && sc <= 299) {
return {
statusCode: sc,
headers: { 'Content-Type': 'application/json' },
body: bodystr,
};
}
return {
error: {
error: 'Some sort of error string',
message: 'Some sort of error message',
statusCode: sc,
headers: { 'Content-Type': 'application/json' },
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,37 @@ class WskCliBasicUsageTests extends TestHelpers with WskTestHelpers {
}
}

it should "not delete a trigger when feed deletion fails" in withAssetCleaner(wskprops) { (wp, assetHelper) =>
val actionName = withTimestamp("feed-action-fails-delete")
val triggerName = withTimestamp("feedDeleteTest")
val feedActionCreateParams = Map("statusCode" -> JsNumber(200))
val feedActionPath = new File(".").getAbsolutePath() + "/src/dat/feed-action-fails-delete.js"

assetHelper.withCleaner(wsk.action, actionName) { (action, _) =>
action.create(actionName, Some(feedActionPath))
}

try {
wsk.trigger.create(triggerName, feed = Some(actionName), parameters = feedActionCreateParams)
wsk.trigger.delete(triggerName, expectedExitCode = ERROR_EXIT).stderr should include(
"""Unable to delete trigger""")
} finally {
wsk.cli(
Seq(
"trigger",
"delete",
s"$triggerName",
"--auth",
wskprops.authKey,
"--apihost",
wskprops.apihost,
"--apiversion",
wskprops.apiversion,
"-i",
"-f"))
}
}

it should "invoke a feed action with the correct lifecyle event when creating, retrieving and deleting a feed trigger" in withAssetCleaner(
wskprops) { (wp, assetHelper) =>
val actionName = withTimestamp("echo")
Expand Down Expand Up @@ -1641,6 +1672,40 @@ class WskCliBasicUsageTests extends TestHelpers with WskTestHelpers {
stdoutNoDescOrParams should include regex (s"(?i)trigger ${qualtrgNoDescOrParams}\\s*\\(parameters: none defined\\)")
}

it should "not create a trigger with timeout error when feed fails to initialize" in withAssetCleaner(wskprops) {
(wp, assetHelper) =>
val samplePackage = "samplePackage"
val guestNamespace = wskprops.namespace
val defaultWskProps = WskProps()

val original_overrides = wp.overrides
wp.overrides = wp.overrides ++ Seq("-d")
val original_defaultWskProps_overrides = defaultWskProps.overrides
defaultWskProps.overrides = defaultWskProps.overrides ++ Seq("-d")

assetHelper.withCleaner(wsk.pkg, samplePackage) { (pkg, _) =>
pkg.create(samplePackage, shared = Some(true))(wp)
}

val sampleFeed = s"$samplePackage/sampleFeed"
assetHelper.withCleaner(wsk.action, sampleFeed) {
val file = Some(TestUtils.getTestActionFilename("empty.js"))
(action, _) =>
action.create(sampleFeed, file, kind = Some("nodejs:default"))(wp)
}

val fullyQualifiedFeedName = s"/$guestNamespace/$sampleFeed"
withAssetCleaner(defaultWskProps) { (wp, assetHelper) =>
assetHelper.withCleaner(wsk.trigger, "badfeed", confirmDelete = false) { (trigger, name) =>
trigger.create(name, feed = Some(fullyQualifiedFeedName), expectedExitCode = TIMEOUT)(wp)
}
// with several active controllers race condition with cache invalidation might occur, thus retry
retry(wsk.trigger.get("badfeed", expectedExitCode = NOT_FOUND)(wp))
}
wp.overrides = original_overrides
defaultWskProps.overrides = original_defaultWskProps_overrides
}

behavior of "Wsk entity list formatting"

it should "create, and list a package with a long name" in withAssetCleaner(wskprops) { (wp, assetHelper) =>
Expand Down
12 changes: 6 additions & 6 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
"ignore": "test",
"package": [
{
"checksumSHA1": "upP6n3vm+l0xwq1EswdwVQSHDOg=",
"checksumSHA1": "v0S6R6MWfslQgopOXRIhcd9OdHk=",
"path": "github.com/apache/openwhisk-client-go/whisk",
"revision": "d8ccb1442651beee6a9245913e3ca0cb182888b1",
"revisionTime": "2019-08-09T21:43:19Z"
"revision": "d272b2b1129269d384c1dbba6c39156abc10ad3c",
"revisionTime": "2019-12-11T16:53:14Z"
},
{
"checksumSHA1": "uN1QmjP7Z6Rlkw73uOAQrtNKQR0=",
"checksumSHA1": "wdSbAqtYatmuN3ckhnIfwLMJM0U=",
"path": "github.com/apache/openwhisk-client-go/wski18n",
"revision": "d8ccb1442651beee6a9245913e3ca0cb182888b1",
"revisionTime": "2019-08-09T21:43:19Z"
"revision": "d272b2b1129269d384c1dbba6c39156abc10ad3c",
"revisionTime": "2019-12-11T16:53:14Z"
},
{
"checksumSHA1": "jgCQbGeq+qGCWmBQOcl0LF6Dy0E=",
Expand Down
4 changes: 4 additions & 0 deletions wski18n/resources/en_US.all.json
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,10 @@
"id": "FEED_CONFIGURATION_FAILURE",
"translation": "Unable to configure feed '{{.feedname}}': {{.err}}"
},
{
"id": "force trigger deletion even when feed deletion fails",
"translation": "force trigger deletion even when feed deletion fails"
},
{
"note-to-translators": "DO NOT TRANSLATE THE 'yes' AND 'no'. THOSE ARE FIXED CLI ARGUMENT VALUES",
"id": "trigger visibility `SCOPE`; yes = shared, no = private",
Expand Down