Skip to content

Commit

Permalink
Store compact JSON in annotations storages
Browse files Browse the repository at this point in the history
Improve how the annotations look like in `kubectl` yaml-format: as one line,
not wrapped at arbitrary spaces, making it difficult to read and debug.

It still be wrapped at spaces in the handler's progress field, e.g. `message`
(which contains error/exception messages), but this happens not so often.

The behaviour of the operators during the switch it not affected: they only
compare and operate on the actual values, not their string representation.
Mass-recoding is not expected either: the existing fields will be compacted
only on the next occasion when they are written for any other reason.

Note: this is the same as `kubectl` itself stores its own annotation.

Compare the output of a command during a sample operator run:

```
kubectl get -o yaml -f examples/obj.yaml
```

Before:

```
apiVersion: zalando.org/v1
kind: KopfExample
metadata:
  annotations:
    kopf.zalando.org/last-handled-configuration: '{"spec":{"duration":"1m","field":"value","items":["item1","item2"],"x":600},"metadata":{"labels":{"somelabel":"somevalue"},"annotations":{"someannotation":"somevalue"}}}'
    kopf.zalando.org/update: '{"started": "2020-08-22T19:38:36.850462", "delayed":
      "2020-08-22T19:38:37.277965", "retries": 4, "success": false, "failure": false,
      "message": "None", "subrefs": ["update/s1", "update/s2", "update/s2/z1", "update/s2/z2",
      "update/s3", "update/s4", "update/s4/z1", "update/s4/z2"]}'
    kopf.zalando.org/update.s1: '{"started": "2020-08-22T19:38:36.851463", "stopped":
      "2020-08-22T19:38:36.853665", "retries": 1, "success": true, "failure": false}'
    kopf.zalando.org/update.s2: '{"started": "2020-08-22T19:38:36.851542", "stopped":
      "2020-08-22T19:38:37.134753", "retries": 2, "success": true, "failure": false,
      "subrefs": ["update/s2/z1", "update/s2/z2"]}'
    kopf.zalando.org/update.s2.z1: '{"started": "2020-08-22T19:38:36.997186", "stopped":
      "2020-08-22T19:38:36.998416", "retries": 1, "success": true, "failure": false}'
    kopf.zalando.org/update.s2.z2: '{"started": "2020-08-22T19:38:36.997264", "stopped":
      "2020-08-22T19:38:37.133993", "retries": 1, "success": true, "failure": false}'
    kopf.zalando.org/update.s3: '{"started": "2020-08-22T19:38:37.135138", "stopped":
      "2020-08-22T19:38:37.136068", "retries": 1, "success": true, "failure": false}'
    kopf.zalando.org/update.s4: '{"started": "2020-08-22T19:38:37.135197", "delayed":
      "2020-08-22T19:38:37.277547", "retries": 1, "success": false, "failure": false,
      "message": "None", "subrefs": ["update/s4/z1", "update/s4/z2"]}'
    kopf.zalando.org/update.s4.z1: '{"started": "2020-08-22T19:38:37.275760", "stopped":
      "2020-08-22T19:38:37.276967", "retries": 1, "success": true, "failure": false}'
    kopf.zalando.org/update.s4.z2: '{"started": "2020-08-22T19:38:37.275867", "retries":
      0, "success": false, "failure": false}'
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"zalando.org/v1","kind":"KopfExample","metadata":{"annotations":{"someannotation":"somevalue"},"labels":{"somelabel":"somevalue"},"name":"kopf-example-1","namespace":"default"},"spec":{"duration":"1m","field":"value","
    someannotation: somevalue
```

After:

```
apiVersion: zalando.org/v1
kind: KopfExample
metadata:
  annotations:
    kopf.zalando.org/last-handled-configuration: |
      {"spec":{"duration":"1m","field":"value","items":["item1","item2"],"x":700},"metadata":{"labels":{"somelabel":"somevalue"},"annotations":{"someannotation":"somevalue"}}}
    kopf.zalando.org/update: '{"started":"2020-08-22T19:35:41.853274","delayed":"2020-08-22T19:35:42.291393","retries":4,"success":false,"failure":false,"message":"None","subrefs":["update/s1","update/s2","update/s2/z1","update/s2/z2","up
    kopf.zalando.org/update.s1: '{"started":"2020-08-22T19:35:41.854561","stopped":"2020-08-22T19:35:41.856038","retries":1,"success":true,"failure":false}'
    kopf.zalando.org/update.s2: '{"started":"2020-08-22T19:35:41.854639","stopped":"2020-08-22T19:35:42.146998","retries":2,"success":true,"failure":false,"subrefs":["update/s2/z1","update/s2/z2"]}'
    kopf.zalando.org/update.s2.z1: '{"started":"2020-08-22T19:35:42.013957","stopped":"2020-08-22T19:35:42.014978","retries":1,"success":true,"failure":false}'
    kopf.zalando.org/update.s2.z2: '{"started":"2020-08-22T19:35:42.014018","stopped":"2020-08-22T19:35:42.145090","retries":1,"success":true,"failure":false}'
    kopf.zalando.org/update.s3: '{"started":"2020-08-22T19:35:42.147980","stopped":"2020-08-22T19:35:42.149392","retries":1,"success":true,"failure":false}'
    kopf.zalando.org/update.s4: '{"started":"2020-08-22T19:35:42.148266","delayed":"2020-08-22T19:35:42.290835","retries":1,"success":false,"failure":false,"message":"None","subrefs":["update/s4/z1","update/s4/z2"]}'
    kopf.zalando.org/update.s4.z1: '{"started":"2020-08-22T19:35:42.288954","stopped":"2020-08-22T19:35:42.290224","retries":1,"success":true,"failure":false}'
    kopf.zalando.org/update.s4.z2: '{"started":"2020-08-22T19:35:42.289030","retries":0,"success":false,"failure":false}'
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"zalando.org/v1","kind":"KopfExample","metadata":{"annotations":{"someannotation":"somevalue"},"labels":{"somelabel":"somevalue"},"name":"kopf-example-1","namespace":"default"},"spec":{"duration":"1m","field":"value","
    someannotation: somevalue
```
  • Loading branch information
nolar committed Aug 22, 2020
1 parent 8a99e2e commit 2a32732
Show file tree
Hide file tree
Showing 6 changed files with 12 additions and 10 deletions.
6 changes: 4 additions & 2 deletions kopf/storage/diffbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ def store(
patch: patches.Patch,
essence: bodies.BodyEssence,
) -> None:
patch.metadata.annotations[self.name] = json.dumps(essence)
encoded: str = json.dumps(essence, separators=(',', ':')) # NB: no spaces
encoded += '\n' # for better kubectl presentation without wrapping (same as kubectl's one)
patch.metadata.annotations[self.name] = encoded


class StatusDiffBaseStorage(DiffBaseStorage):
Expand Down Expand Up @@ -206,7 +208,7 @@ def store(
essence: bodies.BodyEssence,
) -> None:
# Store as a single string instead of full dict -- to avoid merges and unexpected data.
encoded: str = json.dumps(essence)
encoded: str = json.dumps(essence, separators=(',', ':')) # NB: no spaces
dicts.ensure(patch, self.field, encoded)


Expand Down
2 changes: 1 addition & 1 deletion kopf/storage/progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def store(
full_key = self.make_key(key)
key_field = ['metadata', 'annotations', full_key]
decoded = {key: val for key, val in record.items() if self.verbose or val is not None}
encoded = json.dumps(decoded)
encoded = json.dumps(decoded, separators=(',', ':')) # NB: no spaces
dicts.ensure(patch, key_field, encoded)

def purge(
Expand Down
4 changes: 2 additions & 2 deletions tests/causation/test_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

# Encoded at runtime, so that we do not make any assumptions on json formatting.
SPEC_DATA = {'spec': {'field': 'value'}}
SPEC_JSON = json.dumps((SPEC_DATA))
SPEC_JSON = json.dumps(SPEC_DATA, separators=(',', ':'))
ALT_DATA = {'spec': {'field': 'other'}}
ALT_JSON = json.dumps((ALT_DATA))
ALT_JSON = json.dumps(ALT_DATA, separators=(',', ':'))

#
# The following factors contribute to the detection of the cause
Expand Down
2 changes: 1 addition & 1 deletion tests/persistence/test_annotations_hashing.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
message=None,
)

CONTENT_JSON = json.dumps(CONTENT_DATA) # the same serialisation for all environments
CONTENT_JSON = json.dumps(CONTENT_DATA, separators=(',', ':'))


keys = pytest.mark.parametrize('prefix, provided_key, expected_key', [
Expand Down
4 changes: 2 additions & 2 deletions tests/persistence/test_storing_of_diffbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def __init__(
},
)

ESSENCE_JSON_1 = json.dumps(ESSENCE_DATA_1) # the same serialisation for all environments
ESSENCE_JSON_2 = json.dumps(ESSENCE_DATA_2) # the same serialisation for all environments
ESSENCE_JSON_1 = json.dumps(ESSENCE_DATA_1, separators=(',', ':')) + '\n'
ESSENCE_JSON_2 = json.dumps(ESSENCE_DATA_2, separators=(',', ':')) + '\n'


#
Expand Down
4 changes: 2 additions & 2 deletions tests/persistence/test_storing_of_progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
message="Some error.",
)

CONTENT_JSON_1 = json.dumps(CONTENT_DATA_1) # the same serialisation for all environments
CONTENT_JSON_2 = json.dumps(CONTENT_DATA_2) # the same serialisation for all environments
CONTENT_JSON_1 = json.dumps(CONTENT_DATA_1, separators=(',', ':'))
CONTENT_JSON_2 = json.dumps(CONTENT_DATA_2, separators=(',', ':'))


#
Expand Down

0 comments on commit 2a32732

Please sign in to comment.