From 6b5cdb5730f2adac546429d0b7183e79efa58704 Mon Sep 17 00:00:00 2001 From: Mark Deuser Date: Mon, 6 Jan 2020 13:45:50 -0500 Subject: [PATCH 1/6] trigger delete fails when feed deletion fails - add --force flag to force trigger deletion --- commands/flags.go | 1 + commands/trigger.go | 30 ++++++++++++++- tests/src/dat/feed-action-fails-delete.js | 37 +++++++++++++++++++ .../core/cli/test/WskCliBasicUsageTests.scala | 31 ++++++++++++++++ vendor/vendor.json | 12 +++--- wski18n/resources/en_US.all.json | 4 ++ 6 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 tests/src/dat/feed-action-fails-delete.js diff --git a/commands/flags.go b/commands/flags.go index 25c9b968f..e51ad0084 100644 --- a/commands/flags.go +++ b/commands/flags.go @@ -67,6 +67,7 @@ type FlagsStruct struct { detail bool format string nameSort bool // sorts list alphabetically by entity name + force bool } property struct { diff --git a/commands/trigger.go b/commands/trigger.go index 86b18da46..b39d247dd 100644 --- a/commands/trigger.go +++ b/commands/trigger.go @@ -20,6 +20,7 @@ package commands import ( "errors" "fmt" + "strings" "github.com/apache/openwhisk-cli/wski18n" "github.com/apache/openwhisk-client-go/whisk" @@ -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 @@ -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) } @@ -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")) @@ -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) diff --git a/tests/src/dat/feed-action-fails-delete.js b/tests/src/dat/feed-action-fails-delete.js new file mode 100644 index 000000000..764cf0aac --- /dev/null +++ b/tests/src/dat/feed-action-fails-delete.js @@ -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' }, + } + }; +} diff --git a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala index f907109d2..c6c216103 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala @@ -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") diff --git a/vendor/vendor.json b/vendor/vendor.json index d80a786d4..539f13ef8 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -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=", diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json index fbcdfb87c..532c3b609 100644 --- a/wski18n/resources/en_US.all.json +++ b/wski18n/resources/en_US.all.json @@ -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", From 5167a81cd87ca6f34f77504413cf7ed76bc189aa Mon Sep 17 00:00:00 2001 From: Mark Deuser Date: Wed, 8 Jan 2020 17:31:30 -0500 Subject: [PATCH 2/6] temp add test for troubleshooting --- .../core/cli/test/WskCliBasicUsageTests.scala | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala index c6c216103..1ebcc2cb5 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala @@ -1672,6 +1672,32 @@ 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(guestWskProps) { + (wp, assetHelper) => + val samplePackage = "samplePackage" + val guestNamespace = guestWskProps.namespace + + 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)) + } + } + behavior of "Wsk entity list formatting" it should "create, and list a package with a long name" in withAssetCleaner(wskprops) { (wp, assetHelper) => From 0fab134b2baa62086b447619f4d3e7660f71a512 Mon Sep 17 00:00:00 2001 From: Mark Deuser Date: Fri, 10 Jan 2020 11:15:35 -0500 Subject: [PATCH 3/6] temp add test for troubleshooting --- .../openwhisk/core/cli/test/WskCliBasicUsageTests.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala index 1ebcc2cb5..e4986e212 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala @@ -1672,10 +1672,11 @@ 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(guestWskProps) { + it should "not create a trigger with timeout error when feed fails to initialize" in withAssetCleaner(wskprops) { (wp, assetHelper) => val samplePackage = "samplePackage" - val guestNamespace = guestWskProps.namespace + val guestNamespace = wskprops.namespace + val defaultWskProps = WskProps() assetHelper.withCleaner(wsk.pkg, samplePackage) { (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp) From 11ebe3cf25ba977b28c26a68f582dc1347d6390d Mon Sep 17 00:00:00 2001 From: Mark Deuser Date: Fri, 10 Jan 2020 15:20:25 -0500 Subject: [PATCH 4/6] add debug --- .../apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala index e4986e212..c285666fd 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala @@ -1689,6 +1689,8 @@ class WskCliBasicUsageTests extends TestHelpers with WskTestHelpers { action.create(sampleFeed, file, kind = Some("nodejs:default"))(wp) } + val original_overrides = wp.overrides + wp.overrides = overrides ++ Seq("-d") val fullyQualifiedFeedName = s"/$guestNamespace/$sampleFeed" withAssetCleaner(defaultWskProps) { (wp, assetHelper) => assetHelper.withCleaner(wsk.trigger, "badfeed", confirmDelete = false) { (trigger, name) => @@ -1697,6 +1699,7 @@ class WskCliBasicUsageTests extends TestHelpers with WskTestHelpers { // 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 } behavior of "Wsk entity list formatting" From 6484bebf61375fa1d28ee6d454db8f8440399bbc Mon Sep 17 00:00:00 2001 From: Mark Deuser Date: Sat, 11 Jan 2020 08:01:04 -0500 Subject: [PATCH 5/6] add debug --- .../openwhisk/core/cli/test/WskCliBasicUsageTests.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala index c285666fd..3d901fe0d 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala @@ -1678,6 +1678,11 @@ class WskCliBasicUsageTests extends TestHelpers with WskTestHelpers { val guestNamespace = wskprops.namespace val defaultWskProps = WskProps() + val original_overrides = wp.overrides + wp.overrides = overrides ++ Seq("-d") + val original_defaultWskProps_overrides = defaultWskProps.overrides + defaultWskProps.overrides = overrides ++ Seq("-d") + assetHelper.withCleaner(wsk.pkg, samplePackage) { (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp) } @@ -1689,8 +1694,6 @@ class WskCliBasicUsageTests extends TestHelpers with WskTestHelpers { action.create(sampleFeed, file, kind = Some("nodejs:default"))(wp) } - val original_overrides = wp.overrides - wp.overrides = overrides ++ Seq("-d") val fullyQualifiedFeedName = s"/$guestNamespace/$sampleFeed" withAssetCleaner(defaultWskProps) { (wp, assetHelper) => assetHelper.withCleaner(wsk.trigger, "badfeed", confirmDelete = false) { (trigger, name) => @@ -1700,6 +1703,7 @@ class WskCliBasicUsageTests extends TestHelpers with WskTestHelpers { retry(wsk.trigger.get("badfeed", expectedExitCode = NOT_FOUND)(wp)) } wp.overrides = original_overrides + defaultWskProps.overrides = original_defaultWskProps_overrides } behavior of "Wsk entity list formatting" From 8b08f86c46ee8b5db7ade79ae4d17ab23d414b69 Mon Sep 17 00:00:00 2001 From: Mark Deuser Date: Sun, 12 Jan 2020 15:57:40 -0500 Subject: [PATCH 6/6] add debug --- .../openwhisk/core/cli/test/WskCliBasicUsageTests.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala index 3d901fe0d..963993309 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskCliBasicUsageTests.scala @@ -1679,9 +1679,9 @@ class WskCliBasicUsageTests extends TestHelpers with WskTestHelpers { val defaultWskProps = WskProps() val original_overrides = wp.overrides - wp.overrides = overrides ++ Seq("-d") + wp.overrides = wp.overrides ++ Seq("-d") val original_defaultWskProps_overrides = defaultWskProps.overrides - defaultWskProps.overrides = overrides ++ Seq("-d") + defaultWskProps.overrides = defaultWskProps.overrides ++ Seq("-d") assetHelper.withCleaner(wsk.pkg, samplePackage) { (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp)