From f4f0d6dd9a94df647b0e2d3b98475babef7be154 Mon Sep 17 00:00:00 2001 From: John Mulligan Date: Mon, 6 Mar 2023 15:25:10 -0500 Subject: [PATCH] rbd: add functions to parse json in mirroring status description field Add UnmarshalDescriptionJSON method to SiteMirrorImageStatus Add DescriptionReplayStatus method to SiteMirrorImageStatus Both these functions are meant to help extract the JSON object that is some times appended to the Description field in the SiteMirrorImageStatus struct. I have only seen the JSON appear after "replaying, " but there's little docs for this and I skimmed to code to even find out what fields the JSON might include. As such, the UnmarshalDescriptionJSON tries to unmarshal the appended JSON into an object the caller provides in case skimming the code was insufficient or the caller has other needs. For most cases, DescriptionReplayStatus can be used to parse the JSON into a struct containing known fields. Signed-off-by: John Mulligan --- rbd/mirror_desc_status.go | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 rbd/mirror_desc_status.go diff --git a/rbd/mirror_desc_status.go b/rbd/mirror_desc_status.go new file mode 100644 index 0000000..94b1b1d --- /dev/null +++ b/rbd/mirror_desc_status.go @@ -0,0 +1,71 @@ +//go:build !nautilus && ceph_preview +// +build !nautilus,ceph_preview + +package rbd + +// #cgo LDFLAGS: -lrbd +// #include +// #include +import "C" + +import ( + "encoding/json" + "strings" +) + +// MirrorDescriptionReplayStatus contains information pertaining to the status +// of snapshot based RBD image mirroring. +type MirrorDescriptionReplayStatus struct { + ReplayState string `json:"replay_state"` + RemoteSnapshotTimestamp int64 `json:"remote_snapshot_timestamp"` + LocalSnapshotTimestamp int64 `json:"local_snapshot_timestamp"` + SyncingSnapshotTimestamp int64 `json:"syncing_snapshot_timestamp"` + SyncingPercent int `json:"syncing_percent"` + BytesPerSecond float64 `json:"bytes_per_second"` + BytesPerSnapshot float64 `json:"bytes_per_snapshot"` + LastSnapshotSyncSeconds int64 `json:"last_snapshot_sync_seconds"` + LastSnapshotBytes int64 `json:"last_snapshot_bytes"` +} + +// extractDescriptionJSON will extract one string containing a JSON object from +// the description if one can be found. +func (s *SiteMirrorImageStatus) extractDescriptionJSON() (string, error) { + start := strings.Index(s.Description, "{") + if start == -1 { + return "", ErrNotExist + } + end := strings.LastIndex(s.Description, "}") + if end == -1 { + return "", ErrNotExist + } + if start >= end { + return "", ErrNotExist + } + return s.Description[start : end+1], nil +} + +// UnmarshalDescriptionJSON parses an embedded JSON string that may be found in +// the description of the SiteMirrorImageStatus. It will store the result in +// the value pointed to by v. If no embedded JSON string is found an +// ErrNotExist error is returned. An error may also be returned if the contents +// can not be parsed. +func (s *SiteMirrorImageStatus) UnmarshalDescriptionJSON(v interface{}) error { + desc, err := s.extractDescriptionJSON() + if err != nil { + return err + } + return json.Unmarshal([]byte(desc), v) +} + +// DescriptionReplayStatus parses a MirrorDescriptionReplayStatus result out of +// the image status description field if available. If the embedded status JSON +// is not found or fails to parse and error will be returned. +func (s *SiteMirrorImageStatus) DescriptionReplayStatus() ( + *MirrorDescriptionReplayStatus, error) { + // --- + mdrs := MirrorDescriptionReplayStatus{} + if err := s.UnmarshalDescriptionJSON(&mdrs); err != nil { + return nil, err + } + return &mdrs, nil +}