From d4ff6f155b5932e6dde3593947ecfea1773b7978 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 28 Dec 2020 15:46:24 -0600 Subject: [PATCH 1/7] Add kv "entry" actions An "entry" is a JSON object with properties. Multiple entries are stored under a JSON serialized object (as created by st2.kv.set_object) in the datastore. You can upsert or delete properties within an entry. And, you can define a fallback entry (which is named "default" by default) to allow getting properties from an entry, and using the fallback entry to provide defaults for any properties that are undfined in the entry. One use-case for objects like this is to store environment-specific (eg dev, stage, prod, etc) variables with global defaults. Each environment would be an entry and "global" could be the fallback entry. The variables would be properties inside the entries. Signed-off-by: Jacob Floyd --- README.md | 11 +++++++ actions/kv_delete_entry_property.py | 47 +++++++++++++++++++++++++++ actions/kv_delete_entry_property.yaml | 26 +++++++++++++++ actions/kv_get_entry.py | 25 ++++++++++++++ actions/kv_get_entry.yaml | 26 +++++++++++++++ actions/kv_upsert_entry_property.py | 46 ++++++++++++++++++++++++++ actions/kv_upsert_entry_property.yaml | 28 ++++++++++++++++ pack.yaml | 2 +- 8 files changed, 210 insertions(+), 1 deletion(-) create mode 100755 actions/kv_delete_entry_property.py create mode 100755 actions/kv_delete_entry_property.yaml create mode 100755 actions/kv_get_entry.py create mode 100755 actions/kv_get_entry.yaml create mode 100755 actions/kv_upsert_entry_property.py create mode 100755 actions/kv_upsert_entry_property.yaml diff --git a/README.md b/README.md index 647eb73..22347d4 100755 --- a/README.md +++ b/README.md @@ -42,6 +42,17 @@ You can also use dynamic values from the datastore. See the is serialized as JSON. * ``kv.grep_object`` - Find datastore items which name matches the provided query amd deserialize their values from JSON serialized objects. + +* ``kv.get_entry`` - Retrieve entry object in a JSON serialized object from the + datastore. An entry is a standard JSON object with properties. + Fails if the datastore key does not exist. +* ``kv.upsert_entry_property`` - Update or insert a property in the named entry + of a JSON serialized object. Then, serialize and store the updated object. + The property's value may be any json-serializable type. + Fails if the datastore key does not exist. +* ``kv.delete_entry_property`` - Delete a property from a named entry of a JSON + serialized object in the datastore. If the entry is empty, delete it as well. + Fails if the datastore key does not exist. Note: ``kv.set`` and ``kv.get`` actions support compressing value before storing it in a datastore and decompressing it when retrieving it from diff --git a/actions/kv_delete_entry_property.py b/actions/kv_delete_entry_property.py new file mode 100755 index 0000000..dd3b672 --- /dev/null +++ b/actions/kv_delete_entry_property.py @@ -0,0 +1,47 @@ +import json + +from lib.action import St2BaseAction + +__all__ = [ + 'St2KVPDeleteEntryPropertyAction' +] + + +class St2KVPDeleteEntryPropertyAction(St2BaseAction): + # noinspection PyShadowingBuiltins + def run(self, key, entry, property): + # get and deserialize object or fail. + _key = self.client.keys.get_by_name(key, decrypt=False) + + if not _key: + raise Exception("Key does not exist in datastore") + + deserialized = json.loads(_key.value) + + # delete object.entry.property + _entry = deserialized.get(entry, {}) + try: + del _entry[property] + except KeyError: + pass + + # delete object.entry if entry is empty + if not _entry: + try: + del deserialized[entry] + except KeyError: + pass + + # re-serialize and save + serialized = json.dumps(deserialized) + kvp = self._kvp(name=key, value=serialized) + kvp.id = key + + self.client.keys.update(kvp) + response = { + 'key': key, + 'entry_name': entry, + 'entry': _entry, + 'entry_deleted': not _entry, + } + return response diff --git a/actions/kv_delete_entry_property.yaml b/actions/kv_delete_entry_property.yaml new file mode 100755 index 0000000..89e3b39 --- /dev/null +++ b/actions/kv_delete_entry_property.yaml @@ -0,0 +1,26 @@ +--- +name: 'kv.delete_entry_property' +enabled: true +description: | + Delete a property (if it exists) under an named entry (sub-object) of a + serialized object in kv datastore. If the entry is empty after deleting + the property, this deletes the entry as well. + Fails if the key does not exist in the datastore. + The kv object uses this structure: { entry: { property: value, ... }, entry: {}, ...} + This action does not support encrypted datastore objects. + +runner_type: python-script +entry_point: kv_delete_entry_property.py +parameters: + key: + required: true + type: string + entry: + description: name of the key's entry + required: false + type: string + default: default + property: + description: name of the entry's property to upsert + required: true + type: string diff --git a/actions/kv_get_entry.py b/actions/kv_get_entry.py new file mode 100755 index 0000000..e9399ba --- /dev/null +++ b/actions/kv_get_entry.py @@ -0,0 +1,25 @@ +import json + +from lib.action import St2BaseAction + +__all__ = [ + 'St2KVPGetEntryAction' +] + + +class St2KVPGetEntryAction(St2BaseAction): + # noinspection PyShadowingBuiltins + def run(self, key, fallback, entry): + # get and deserialize object or fail. + _key = self.client.keys.get_by_name(key, decrypt=False) + + if not _key: + raise Exception("Key does not exist in datastore") + + deserialized = json.loads(_key.value) + + # try get object.entry.property + _entry = deserialized.get(fallback, {}) + _entry.update(deserialized.get(entry, {})) + + return _entry diff --git a/actions/kv_get_entry.yaml b/actions/kv_get_entry.yaml new file mode 100755 index 0000000..9eb0802 --- /dev/null +++ b/actions/kv_get_entry.yaml @@ -0,0 +1,26 @@ +--- +name: 'kv.get_entry' +enabled: true +description: | + Get a named entry (sub-object) of a serialized object in kv datastore + merged on top of the fallback entry (ie the fallback provides defaults). + Fails if the key does not exist in the datastore. + Does not fail if the entry or fallback is missing. + The kv object uses this structure: { fallback: { property: value, ... }, entry: {}, ...} + This action does not support encrypted datastore objects. + +runner_type: python-script +entry_point: kv_get_entry.py +parameters: + key: + required: true + type: string + fallback: + description: name of the key's fallback entry + required: false + type: string + default: default + entry: + description: name of the key's entry + required: true + type: string diff --git a/actions/kv_upsert_entry_property.py b/actions/kv_upsert_entry_property.py new file mode 100755 index 0000000..4da09f0 --- /dev/null +++ b/actions/kv_upsert_entry_property.py @@ -0,0 +1,46 @@ +import json + +from lib.action import St2BaseAction + +__all__ = [ + 'St2KVPUpsertEntryPropertyAction' +] + + +class St2KVPUpsertEntryPropertyAction(St2BaseAction): + # noinspection PyShadowingBuiltins + def run(self, key, entry, property, value): + # get and deserialize object or fail. + _key = self.client.keys.get_by_name(key, decrypt=False) + + if not _key: + raise Exception("Key does not exist in datastore") + + # optimistically try to decode a json value + try: + value = json.loads(value) + except (TypeError, ValueError): + # assume it is either already decoded (TypeError) + # or it is a plain string (ValueError) + # (malformed JSON objects/arrays will be strings) + pass + + deserialized = json.loads(_key.value) + + # update or insert object.entry.property + _entry = deserialized.get(entry, {}) + _entry[property] = value + deserialized[entry] = _entry + + # re-serialize and save + serialized = json.dumps(deserialized) + kvp = self._kvp(name=key, value=serialized) + kvp.id = key + + self.client.keys.update(kvp) + response = { + 'key': key, + 'entry_name': entry, + 'entry': _entry, + } + return response diff --git a/actions/kv_upsert_entry_property.yaml b/actions/kv_upsert_entry_property.yaml new file mode 100755 index 0000000..d8d2e27 --- /dev/null +++ b/actions/kv_upsert_entry_property.yaml @@ -0,0 +1,28 @@ +--- +name: 'kv.upsert_entry_property' +enabled: true +description: | + Insert or update a property under an named entry (sub-object) of a serialized object in kv datastore. + Fails if the key does not exist in the datastore, as a property inside it can't be upserted yet. + The kv object uses this structure: { entry: { property: value, ... }, entry: {}, ...} + This action does not support encrypted datastore objects. + +runner_type: python-script +entry_point: kv_upsert_entry_property.py +parameters: + key: + required: true + type: string + entry: + description: name of the key's entry + required: false + type: string + default: default + property: + description: name of the entry's property to upsert + required: true + type: string + value: + description: the property value may be any json-serialible type (string, number, array, object) + required: true + # type: any diff --git a/pack.yaml b/pack.yaml index d88c4cc..8925815 100755 --- a/pack.yaml +++ b/pack.yaml @@ -2,7 +2,7 @@ ref: st2 name: st2 description: StackStorm utility actions and aliases -version: 1.3.1 +version: 1.4.0 python_versions: - "2" - "3" From 7f496c57ce27cf4ccc0e47a7524138f27ccee2cc Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 28 Dec 2020 19:51:57 -0600 Subject: [PATCH 2/7] Add distributed lock to entry_property actions Signed-off-by: Jacob Floyd --- README.md | 4 +- actions/kv_delete_entry_property.py | 59 ++++++++++++------------ actions/kv_upsert_entry_property.py | 71 +++++++++++++++-------------- 3 files changed, 70 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 22347d4..73373b9 100755 --- a/README.md +++ b/README.md @@ -49,10 +49,10 @@ You can also use dynamic values from the datastore. See the * ``kv.upsert_entry_property`` - Update or insert a property in the named entry of a JSON serialized object. Then, serialize and store the updated object. The property's value may be any json-serializable type. - Fails if the datastore key does not exist. + Fails if the datastore key does not exist. A coordination backend is recommended. * ``kv.delete_entry_property`` - Delete a property from a named entry of a JSON serialized object in the datastore. If the entry is empty, delete it as well. - Fails if the datastore key does not exist. + Fails if the datastore key does not exist. A coordination backend is recommended. Note: ``kv.set`` and ``kv.get`` actions support compressing value before storing it in a datastore and decompressing it when retrieving it from diff --git a/actions/kv_delete_entry_property.py b/actions/kv_delete_entry_property.py index dd3b672..2f80062 100755 --- a/actions/kv_delete_entry_property.py +++ b/actions/kv_delete_entry_property.py @@ -1,5 +1,7 @@ import json +from st2common.services import coordination as coordination_service + from lib.action import St2BaseAction __all__ = [ @@ -10,38 +12,39 @@ class St2KVPDeleteEntryPropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property): - # get and deserialize object or fail. - _key = self.client.keys.get_by_name(key, decrypt=False) - - if not _key: - raise Exception("Key does not exist in datastore") + with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): + # get and deserialize object or fail. + _key = self.client.keys.get_by_name(key, decrypt=False) - deserialized = json.loads(_key.value) + if not _key: + raise Exception("Key does not exist in datastore") - # delete object.entry.property - _entry = deserialized.get(entry, {}) - try: - del _entry[property] - except KeyError: - pass + deserialized = json.loads(_key.value) - # delete object.entry if entry is empty - if not _entry: + # delete object.entry.property + _entry = deserialized.get(entry, {}) try: - del deserialized[entry] + del _entry[property] except KeyError: pass - # re-serialize and save - serialized = json.dumps(deserialized) - kvp = self._kvp(name=key, value=serialized) - kvp.id = key - - self.client.keys.update(kvp) - response = { - 'key': key, - 'entry_name': entry, - 'entry': _entry, - 'entry_deleted': not _entry, - } - return response + # delete object.entry if entry is empty + if not _entry: + try: + del deserialized[entry] + except KeyError: + pass + + # re-serialize and save + serialized = json.dumps(deserialized) + kvp = self._kvp(name=key, value=serialized) + kvp.id = key + + self.client.keys.update(kvp) + response = { + 'key': key, + 'entry_name': entry, + 'entry': _entry, + 'entry_deleted': not _entry, + } + return response diff --git a/actions/kv_upsert_entry_property.py b/actions/kv_upsert_entry_property.py index 4da09f0..e9f0544 100755 --- a/actions/kv_upsert_entry_property.py +++ b/actions/kv_upsert_entry_property.py @@ -1,5 +1,7 @@ import json +from st2common.services import coordination as coordination_service + from lib.action import St2BaseAction __all__ = [ @@ -10,37 +12,38 @@ class St2KVPUpsertEntryPropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property, value): - # get and deserialize object or fail. - _key = self.client.keys.get_by_name(key, decrypt=False) - - if not _key: - raise Exception("Key does not exist in datastore") - - # optimistically try to decode a json value - try: - value = json.loads(value) - except (TypeError, ValueError): - # assume it is either already decoded (TypeError) - # or it is a plain string (ValueError) - # (malformed JSON objects/arrays will be strings) - pass - - deserialized = json.loads(_key.value) - - # update or insert object.entry.property - _entry = deserialized.get(entry, {}) - _entry[property] = value - deserialized[entry] = _entry - - # re-serialize and save - serialized = json.dumps(deserialized) - kvp = self._kvp(name=key, value=serialized) - kvp.id = key - - self.client.keys.update(kvp) - response = { - 'key': key, - 'entry_name': entry, - 'entry': _entry, - } - return response + with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): + # get and deserialize object or fail. + _key = self.client.keys.get_by_name(key, decrypt=False) + + if not _key: + raise Exception("Key does not exist in datastore") + + # optimistically try to decode a json value + try: + value = json.loads(value) + except (TypeError, ValueError): + # assume it is either already decoded (TypeError) + # or it is a plain string (ValueError) + # (malformed JSON objects/arrays will be strings) + pass + + deserialized = json.loads(_key.value) + + # update or insert object.entry.property + _entry = deserialized.get(entry, {}) + _entry[property] = value + deserialized[entry] = _entry + + # re-serialize and save + serialized = json.dumps(deserialized) + kvp = self._kvp(name=key, value=serialized) + kvp.id = key + + self.client.keys.update(kvp) + response = { + 'key': key, + 'entry_name': entry, + 'entry': _entry, + } + return response From b66ac5d69d0490fea1aa1b1759c85f9745841bee Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 28 Dec 2020 21:17:21 -0600 Subject: [PATCH 3/7] Add an append action for entry array properties plus fix a few typos Signed-off-by: Jacob Floyd --- README.md | 4 ++ actions/kv_append_entry_property.py | 55 +++++++++++++++++++++++++++ actions/kv_append_entry_property.yaml | 29 ++++++++++++++ actions/kv_delete_entry_property.yaml | 2 +- actions/kv_upsert_entry_property.yaml | 4 +- 5 files changed, 91 insertions(+), 3 deletions(-) create mode 100755 actions/kv_append_entry_property.py create mode 100755 actions/kv_append_entry_property.yaml diff --git a/README.md b/README.md index 73373b9..d6d5d2d 100755 --- a/README.md +++ b/README.md @@ -50,6 +50,10 @@ You can also use dynamic values from the datastore. See the of a JSON serialized object. Then, serialize and store the updated object. The property's value may be any json-serializable type. Fails if the datastore key does not exist. A coordination backend is recommended. +* ``kv.append_entry_property`` - Add the value to the end of an array property + in the named entry of a JSON serialized object. Then, serialize and store the + updated object. The property must be an array. The value to append can be anything. + Fails if the datastore key does not exist. A coordination backend is recommended. * ``kv.delete_entry_property`` - Delete a property from a named entry of a JSON serialized object in the datastore. If the entry is empty, delete it as well. Fails if the datastore key does not exist. A coordination backend is recommended. diff --git a/actions/kv_append_entry_property.py b/actions/kv_append_entry_property.py new file mode 100755 index 0000000..1ad6f26 --- /dev/null +++ b/actions/kv_append_entry_property.py @@ -0,0 +1,55 @@ +import json + +from st2common.services import coordination as coordination_service + +from lib.action import St2BaseAction + +__all__ = [ + 'St2KVPAppendEntryPropertyAction' +] + + +class St2KVPAppendEntryPropertyAction(St2BaseAction): + # noinspection PyShadowingBuiltins + def run(self, key, entry, property, value): + with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): + # get and deserialize object or fail. + _key = self.client.keys.get_by_name(key, decrypt=False) + + if not _key: + raise Exception("Key does not exist in datastore") + + # optimistically try to decode a json value + try: + value = json.loads(value) + except (TypeError, ValueError): + # assume it is either already decoded (TypeError) + # or it is a plain string (ValueError) + # (malformed JSON objects/arrays will be strings) + pass + + deserialized = json.loads(_key.value) + + # update or insert object.entry.property + _entry = deserialized.get(entry, {}) + _property = _entry.get(property, []) + try: + _property.append(value) + except AttributeError: + raise Exception("Cannot append. Property {}.{}.{} is not an array!".format(key, entry, property)) + + _entry[property] = _property + deserialized[entry] = _entry + + # re-serialize and save + serialized = json.dumps(deserialized) + kvp = self._kvp(name=key, value=serialized) + kvp.id = key + + self.client.keys.update(kvp) + response = { + 'key': key, + 'entry_name': entry, + 'entry': _entry, + } + return response diff --git a/actions/kv_append_entry_property.yaml b/actions/kv_append_entry_property.yaml new file mode 100755 index 0000000..02e88dc --- /dev/null +++ b/actions/kv_append_entry_property.yaml @@ -0,0 +1,29 @@ +--- +name: 'kv.append_entry_property' +enabled: true +description: | + Add a value to the end of an array property under a named entry (sub-object) + of a serialized object in kv datastore. + Fails if the key does not exist in the datastore, as a property inside it can't be appended to yet. + The kv object uses this structure: { entry: { property: [value, value], ...}, ...} + This action does not support encrypted datastore objects. + +runner_type: python-script +entry_point: kv_append_entry_property.py +parameters: + key: + required: true + type: string + entry: + description: name of the key's entry + required: false + type: string + default: default + property: + description: name of the entry's property to append to (property should have an array value) + required: true + type: string + value: + description: the value may be any json-serializable type (string, number, array, object) + required: true + # type: any diff --git a/actions/kv_delete_entry_property.yaml b/actions/kv_delete_entry_property.yaml index 89e3b39..40c67ea 100755 --- a/actions/kv_delete_entry_property.yaml +++ b/actions/kv_delete_entry_property.yaml @@ -2,7 +2,7 @@ name: 'kv.delete_entry_property' enabled: true description: | - Delete a property (if it exists) under an named entry (sub-object) of a + Delete a property (if it exists) under a named entry (sub-object) of a serialized object in kv datastore. If the entry is empty after deleting the property, this deletes the entry as well. Fails if the key does not exist in the datastore. diff --git a/actions/kv_upsert_entry_property.yaml b/actions/kv_upsert_entry_property.yaml index d8d2e27..9eb05f9 100755 --- a/actions/kv_upsert_entry_property.yaml +++ b/actions/kv_upsert_entry_property.yaml @@ -2,7 +2,7 @@ name: 'kv.upsert_entry_property' enabled: true description: | - Insert or update a property under an named entry (sub-object) of a serialized object in kv datastore. + Insert or update a property under a named entry (sub-object) of a serialized object in kv datastore. Fails if the key does not exist in the datastore, as a property inside it can't be upserted yet. The kv object uses this structure: { entry: { property: value, ... }, entry: {}, ...} This action does not support encrypted datastore objects. @@ -23,6 +23,6 @@ parameters: required: true type: string value: - description: the property value may be any json-serialible type (string, number, array, object) + description: the property value may be any json-serializable type (string, number, array, object) required: true # type: any From 6352608248a7ddf86b4efa6fc802fdb98f00b4b3 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 28 Dec 2020 21:24:01 -0600 Subject: [PATCH 4/7] Improve webui UX with kv.entry.* It's confusing to have to scroll down in the web UI to remember to include the entry name, so make it required, and use position to tell the webui order the params should be shown in. Signed-off-by: Jacob Floyd --- actions/kv_append_entry_property.yaml | 9 ++++++--- actions/kv_delete_entry_property.yaml | 8 +++++--- actions/kv_get_entry.py | 2 +- actions/kv_get_entry.yaml | 11 +++++++---- actions/kv_upsert_entry_property.yaml | 9 ++++++--- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/actions/kv_append_entry_property.yaml b/actions/kv_append_entry_property.yaml index 02e88dc..6a06465 100755 --- a/actions/kv_append_entry_property.yaml +++ b/actions/kv_append_entry_property.yaml @@ -14,16 +14,19 @@ parameters: key: required: true type: string + position: 0 entry: - description: name of the key's entry - required: false + description: name of the key's entry (or fallback entry) + required: true type: string - default: default + position: 1 property: description: name of the entry's property to append to (property should have an array value) required: true type: string + position: 2 value: description: the value may be any json-serializable type (string, number, array, object) required: true # type: any + position: 3 diff --git a/actions/kv_delete_entry_property.yaml b/actions/kv_delete_entry_property.yaml index 40c67ea..ba55e66 100755 --- a/actions/kv_delete_entry_property.yaml +++ b/actions/kv_delete_entry_property.yaml @@ -15,12 +15,14 @@ parameters: key: required: true type: string + position: 0 entry: - description: name of the key's entry - required: false + description: name of the key's entry (or fallback entry) + required: true type: string - default: default + position: 1 property: description: name of the entry's property to upsert required: true type: string + position: 2 diff --git a/actions/kv_get_entry.py b/actions/kv_get_entry.py index e9399ba..1ed47d2 100755 --- a/actions/kv_get_entry.py +++ b/actions/kv_get_entry.py @@ -9,7 +9,7 @@ class St2KVPGetEntryAction(St2BaseAction): # noinspection PyShadowingBuiltins - def run(self, key, fallback, entry): + def run(self, key, entry, fallback): # get and deserialize object or fail. _key = self.client.keys.get_by_name(key, decrypt=False) diff --git a/actions/kv_get_entry.yaml b/actions/kv_get_entry.yaml index 9eb0802..7da3dca 100755 --- a/actions/kv_get_entry.yaml +++ b/actions/kv_get_entry.yaml @@ -15,12 +15,15 @@ parameters: key: required: true type: string + position: 0 + entry: + description: name of the key's entry + required: true + type: string + position: 1 fallback: description: name of the key's fallback entry required: false type: string default: default - entry: - description: name of the key's entry - required: true - type: string + position: 2 diff --git a/actions/kv_upsert_entry_property.yaml b/actions/kv_upsert_entry_property.yaml index 9eb05f9..6ca1126 100755 --- a/actions/kv_upsert_entry_property.yaml +++ b/actions/kv_upsert_entry_property.yaml @@ -13,16 +13,19 @@ parameters: key: required: true type: string + position: 0 entry: - description: name of the key's entry - required: false + description: name of the key's entry (or fallback entry) + required: true type: string - default: default + position: 1 property: description: name of the entry's property to upsert required: true type: string + position: 2 value: description: the property value may be any json-serializable type (string, number, array, object) required: true # type: any + position: 3 From 31dfefc0e52f0fcb2e7d992f22629a1cd6b3c80e Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 28 Dec 2020 22:11:36 -0600 Subject: [PATCH 5/7] Make the entry actions more discoverable Group them under st2.kv.entry.* Signed-off-by: Jacob Floyd --- README.md | 8 ++++---- ...pend_entry_property.py => kv_entry_append_property.py} | 4 ++-- ..._entry_property.yaml => kv_entry_append_property.yaml} | 4 ++-- ...lete_entry_property.py => kv_entry_delete_property.py} | 4 ++-- ..._entry_property.yaml => kv_entry_delete_property.yaml} | 4 ++-- actions/{kv_get_entry.py => kv_entry_get.py} | 4 ++-- actions/{kv_get_entry.yaml => kv_entry_get.yaml} | 4 ++-- ...sert_entry_property.py => kv_entry_upsert_property.py} | 4 ++-- ..._entry_property.yaml => kv_entry_upsert_property.yaml} | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) rename actions/{kv_append_entry_property.py => kv_entry_append_property.py} (95%) rename actions/{kv_append_entry_property.yaml => kv_entry_append_property.yaml} (92%) rename actions/{kv_delete_entry_property.py => kv_entry_delete_property.py} (93%) rename actions/{kv_delete_entry_property.yaml => kv_entry_delete_property.yaml} (91%) rename actions/{kv_get_entry.py => kv_entry_get.py} (88%) rename actions/{kv_get_entry.yaml => kv_entry_get.yaml} (93%) rename actions/{kv_upsert_entry_property.py => kv_entry_upsert_property.py} (94%) rename actions/{kv_upsert_entry_property.yaml => kv_entry_upsert_property.yaml} (92%) diff --git a/README.md b/README.md index d6d5d2d..2b3bc61 100755 --- a/README.md +++ b/README.md @@ -43,18 +43,18 @@ You can also use dynamic values from the datastore. See the * ``kv.grep_object`` - Find datastore items which name matches the provided query amd deserialize their values from JSON serialized objects. -* ``kv.get_entry`` - Retrieve entry object in a JSON serialized object from the +* ``kv.entry.get`` - Retrieve entry in a JSON serialized object from the datastore. An entry is a standard JSON object with properties. Fails if the datastore key does not exist. -* ``kv.upsert_entry_property`` - Update or insert a property in the named entry +* ``kv.entry.upsert_property`` - Update or insert a property in the named entry of a JSON serialized object. Then, serialize and store the updated object. The property's value may be any json-serializable type. Fails if the datastore key does not exist. A coordination backend is recommended. -* ``kv.append_entry_property`` - Add the value to the end of an array property +* ``kv.entry.append_property`` - Add the value to the end of an array property in the named entry of a JSON serialized object. Then, serialize and store the updated object. The property must be an array. The value to append can be anything. Fails if the datastore key does not exist. A coordination backend is recommended. -* ``kv.delete_entry_property`` - Delete a property from a named entry of a JSON +* ``kv.entry.delete_property`` - Delete a property from a named entry of a JSON serialized object in the datastore. If the entry is empty, delete it as well. Fails if the datastore key does not exist. A coordination backend is recommended. diff --git a/actions/kv_append_entry_property.py b/actions/kv_entry_append_property.py similarity index 95% rename from actions/kv_append_entry_property.py rename to actions/kv_entry_append_property.py index 1ad6f26..f6cad79 100755 --- a/actions/kv_append_entry_property.py +++ b/actions/kv_entry_append_property.py @@ -5,11 +5,11 @@ from lib.action import St2BaseAction __all__ = [ - 'St2KVPAppendEntryPropertyAction' + 'St2KVPEntryAppendPropertyAction' ] -class St2KVPAppendEntryPropertyAction(St2BaseAction): +class St2KVPEntryAppendPropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property, value): with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): diff --git a/actions/kv_append_entry_property.yaml b/actions/kv_entry_append_property.yaml similarity index 92% rename from actions/kv_append_entry_property.yaml rename to actions/kv_entry_append_property.yaml index 6a06465..e2b57e7 100755 --- a/actions/kv_append_entry_property.yaml +++ b/actions/kv_entry_append_property.yaml @@ -1,5 +1,5 @@ --- -name: 'kv.append_entry_property' +name: 'kv.entry.append_property' enabled: true description: | Add a value to the end of an array property under a named entry (sub-object) @@ -9,7 +9,7 @@ description: | This action does not support encrypted datastore objects. runner_type: python-script -entry_point: kv_append_entry_property.py +entry_point: kv_entry_append_property.py parameters: key: required: true diff --git a/actions/kv_delete_entry_property.py b/actions/kv_entry_delete_property.py similarity index 93% rename from actions/kv_delete_entry_property.py rename to actions/kv_entry_delete_property.py index 2f80062..0ba9d2a 100755 --- a/actions/kv_delete_entry_property.py +++ b/actions/kv_entry_delete_property.py @@ -5,11 +5,11 @@ from lib.action import St2BaseAction __all__ = [ - 'St2KVPDeleteEntryPropertyAction' + 'St2KVPEntryDeletePropertyAction' ] -class St2KVPDeleteEntryPropertyAction(St2BaseAction): +class St2KVPEntryDeletePropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property): with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): diff --git a/actions/kv_delete_entry_property.yaml b/actions/kv_entry_delete_property.yaml similarity index 91% rename from actions/kv_delete_entry_property.yaml rename to actions/kv_entry_delete_property.yaml index ba55e66..8e6cf23 100755 --- a/actions/kv_delete_entry_property.yaml +++ b/actions/kv_entry_delete_property.yaml @@ -1,5 +1,5 @@ --- -name: 'kv.delete_entry_property' +name: 'kv.entry.delete_property' enabled: true description: | Delete a property (if it exists) under a named entry (sub-object) of a @@ -10,7 +10,7 @@ description: | This action does not support encrypted datastore objects. runner_type: python-script -entry_point: kv_delete_entry_property.py +entry_point: kv_entry_delete_property.py parameters: key: required: true diff --git a/actions/kv_get_entry.py b/actions/kv_entry_get.py similarity index 88% rename from actions/kv_get_entry.py rename to actions/kv_entry_get.py index 1ed47d2..a9b50ad 100755 --- a/actions/kv_get_entry.py +++ b/actions/kv_entry_get.py @@ -3,11 +3,11 @@ from lib.action import St2BaseAction __all__ = [ - 'St2KVPGetEntryAction' + 'St2KVPEntryGetAction' ] -class St2KVPGetEntryAction(St2BaseAction): +class St2KVPEntryGetAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, fallback): # get and deserialize object or fail. diff --git a/actions/kv_get_entry.yaml b/actions/kv_entry_get.yaml similarity index 93% rename from actions/kv_get_entry.yaml rename to actions/kv_entry_get.yaml index 7da3dca..1121ce4 100755 --- a/actions/kv_get_entry.yaml +++ b/actions/kv_entry_get.yaml @@ -1,5 +1,5 @@ --- -name: 'kv.get_entry' +name: 'kv.entry.get' enabled: true description: | Get a named entry (sub-object) of a serialized object in kv datastore @@ -10,7 +10,7 @@ description: | This action does not support encrypted datastore objects. runner_type: python-script -entry_point: kv_get_entry.py +entry_point: kv_entry_get.py parameters: key: required: true diff --git a/actions/kv_upsert_entry_property.py b/actions/kv_entry_upsert_property.py similarity index 94% rename from actions/kv_upsert_entry_property.py rename to actions/kv_entry_upsert_property.py index e9f0544..02d2522 100755 --- a/actions/kv_upsert_entry_property.py +++ b/actions/kv_entry_upsert_property.py @@ -5,11 +5,11 @@ from lib.action import St2BaseAction __all__ = [ - 'St2KVPUpsertEntryPropertyAction' + 'St2KVPEntryUpsertPropertyAction' ] -class St2KVPUpsertEntryPropertyAction(St2BaseAction): +class St2KVPEntryUpsertPropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property, value): with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): diff --git a/actions/kv_upsert_entry_property.yaml b/actions/kv_entry_upsert_property.yaml similarity index 92% rename from actions/kv_upsert_entry_property.yaml rename to actions/kv_entry_upsert_property.yaml index 6ca1126..e75cb65 100755 --- a/actions/kv_upsert_entry_property.yaml +++ b/actions/kv_entry_upsert_property.yaml @@ -1,5 +1,5 @@ --- -name: 'kv.upsert_entry_property' +name: 'kv.entry.upsert_property' enabled: true description: | Insert or update a property under a named entry (sub-object) of a serialized object in kv datastore. @@ -8,7 +8,7 @@ description: | This action does not support encrypted datastore objects. runner_type: python-script -entry_point: kv_upsert_entry_property.py +entry_point: kv_entry_upsert_property.py parameters: key: required: true From 5dc2aba60a185e8f4646784d1651e1598434d246 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Wed, 30 Dec 2020 11:51:00 -0600 Subject: [PATCH 6/7] reformat kv_entry actions with black Signed-off-by: Jacob Floyd --- actions/kv_entry_append_property.py | 18 ++++++++++-------- actions/kv_entry_delete_property.py | 14 ++++++-------- actions/kv_entry_get.py | 4 +--- actions/kv_entry_upsert_property.py | 12 +++++------- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/actions/kv_entry_append_property.py b/actions/kv_entry_append_property.py index f6cad79..234654e 100755 --- a/actions/kv_entry_append_property.py +++ b/actions/kv_entry_append_property.py @@ -4,15 +4,13 @@ from lib.action import St2BaseAction -__all__ = [ - 'St2KVPEntryAppendPropertyAction' -] +__all__ = ["St2KVPEntryAppendPropertyAction"] class St2KVPEntryAppendPropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property, value): - with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): + with coordination_service.get_coordinator().get_lock("st2.kv_entry." + key): # get and deserialize object or fail. _key = self.client.keys.get_by_name(key, decrypt=False) @@ -36,7 +34,11 @@ def run(self, key, entry, property, value): try: _property.append(value) except AttributeError: - raise Exception("Cannot append. Property {}.{}.{} is not an array!".format(key, entry, property)) + raise Exception( + "Cannot append. Property {}.{}.{} is not an array!".format( + key, entry, property + ) + ) _entry[property] = _property deserialized[entry] = _entry @@ -48,8 +50,8 @@ def run(self, key, entry, property, value): self.client.keys.update(kvp) response = { - 'key': key, - 'entry_name': entry, - 'entry': _entry, + "key": key, + "entry_name": entry, + "entry": _entry, } return response diff --git a/actions/kv_entry_delete_property.py b/actions/kv_entry_delete_property.py index 0ba9d2a..deb9208 100755 --- a/actions/kv_entry_delete_property.py +++ b/actions/kv_entry_delete_property.py @@ -4,15 +4,13 @@ from lib.action import St2BaseAction -__all__ = [ - 'St2KVPEntryDeletePropertyAction' -] +__all__ = ["St2KVPEntryDeletePropertyAction"] class St2KVPEntryDeletePropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property): - with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): + with coordination_service.get_coordinator().get_lock("st2.kv_entry." + key): # get and deserialize object or fail. _key = self.client.keys.get_by_name(key, decrypt=False) @@ -42,9 +40,9 @@ def run(self, key, entry, property): self.client.keys.update(kvp) response = { - 'key': key, - 'entry_name': entry, - 'entry': _entry, - 'entry_deleted': not _entry, + "key": key, + "entry_name": entry, + "entry": _entry, + "entry_deleted": not _entry, } return response diff --git a/actions/kv_entry_get.py b/actions/kv_entry_get.py index a9b50ad..1ac5b3e 100755 --- a/actions/kv_entry_get.py +++ b/actions/kv_entry_get.py @@ -2,9 +2,7 @@ from lib.action import St2BaseAction -__all__ = [ - 'St2KVPEntryGetAction' -] +__all__ = ["St2KVPEntryGetAction"] class St2KVPEntryGetAction(St2BaseAction): diff --git a/actions/kv_entry_upsert_property.py b/actions/kv_entry_upsert_property.py index 02d2522..2e1b16f 100755 --- a/actions/kv_entry_upsert_property.py +++ b/actions/kv_entry_upsert_property.py @@ -4,15 +4,13 @@ from lib.action import St2BaseAction -__all__ = [ - 'St2KVPEntryUpsertPropertyAction' -] +__all__ = ["St2KVPEntryUpsertPropertyAction"] class St2KVPEntryUpsertPropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property, value): - with coordination_service.get_coordinator().get_lock('st2.kv_entry.' + key): + with coordination_service.get_coordinator().get_lock("st2.kv_entry." + key): # get and deserialize object or fail. _key = self.client.keys.get_by_name(key, decrypt=False) @@ -42,8 +40,8 @@ def run(self, key, entry, property, value): self.client.keys.update(kvp) response = { - 'key': key, - 'entry_name': entry, - 'entry': _entry, + "key": key, + "entry_name": entry, + "entry": _entry, } return response From a152661d05189faccffe8035a3cc2789fafbef87 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Tue, 5 Jan 2021 17:31:01 -0600 Subject: [PATCH 7/7] Rename kv.entry.upsert -> kv.entry.set Signed-off-by: Jacob Floyd --- README.md | 2 +- actions/kv_entry_delete_property.yaml | 2 +- ..._entry_upsert_property.py => kv_entry_set_property.py} | 4 ++-- ...ry_upsert_property.yaml => kv_entry_set_property.yaml} | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) rename actions/{kv_entry_upsert_property.py => kv_entry_set_property.py} (93%) rename actions/{kv_entry_upsert_property.yaml => kv_entry_set_property.yaml} (82%) diff --git a/README.md b/README.md index 2b3bc61..1743a64 100755 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ You can also use dynamic values from the datastore. See the * ``kv.entry.get`` - Retrieve entry in a JSON serialized object from the datastore. An entry is a standard JSON object with properties. Fails if the datastore key does not exist. -* ``kv.entry.upsert_property`` - Update or insert a property in the named entry +* ``kv.entry.set_property`` - Set a property in the named entry of a JSON serialized object. Then, serialize and store the updated object. The property's value may be any json-serializable type. Fails if the datastore key does not exist. A coordination backend is recommended. diff --git a/actions/kv_entry_delete_property.yaml b/actions/kv_entry_delete_property.yaml index 8e6cf23..8e60030 100755 --- a/actions/kv_entry_delete_property.yaml +++ b/actions/kv_entry_delete_property.yaml @@ -22,7 +22,7 @@ parameters: type: string position: 1 property: - description: name of the entry's property to upsert + description: name of the entry's property to delete required: true type: string position: 2 diff --git a/actions/kv_entry_upsert_property.py b/actions/kv_entry_set_property.py similarity index 93% rename from actions/kv_entry_upsert_property.py rename to actions/kv_entry_set_property.py index 2e1b16f..a6b5000 100755 --- a/actions/kv_entry_upsert_property.py +++ b/actions/kv_entry_set_property.py @@ -4,10 +4,10 @@ from lib.action import St2BaseAction -__all__ = ["St2KVPEntryUpsertPropertyAction"] +__all__ = ["St2KVPEntrySetPropertyAction"] -class St2KVPEntryUpsertPropertyAction(St2BaseAction): +class St2KVPEntrySetPropertyAction(St2BaseAction): # noinspection PyShadowingBuiltins def run(self, key, entry, property, value): with coordination_service.get_coordinator().get_lock("st2.kv_entry." + key): diff --git a/actions/kv_entry_upsert_property.yaml b/actions/kv_entry_set_property.yaml similarity index 82% rename from actions/kv_entry_upsert_property.yaml rename to actions/kv_entry_set_property.yaml index e75cb65..4c64c01 100755 --- a/actions/kv_entry_upsert_property.yaml +++ b/actions/kv_entry_set_property.yaml @@ -1,14 +1,14 @@ --- -name: 'kv.entry.upsert_property' +name: 'kv.entry.set_property' enabled: true description: | Insert or update a property under a named entry (sub-object) of a serialized object in kv datastore. - Fails if the key does not exist in the datastore, as a property inside it can't be upserted yet. + Fails if the key does not exist in the datastore, as a property inside it can't be inserted/updated yet. The kv object uses this structure: { entry: { property: value, ... }, entry: {}, ...} This action does not support encrypted datastore objects. runner_type: python-script -entry_point: kv_entry_upsert_property.py +entry_point: kv_entry_set_property.py parameters: key: required: true @@ -20,7 +20,7 @@ parameters: type: string position: 1 property: - description: name of the entry's property to upsert + description: name of the entry's property to set required: true type: string position: 2