2020-09-22 10:56:43 +00:00
|
|
|
package attributes
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
2023-03-07 13:38:26 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
2020-09-22 10:56:43 +00:00
|
|
|
)
|
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
const keyValueSeparator = ":"
|
2020-09-22 10:56:43 +00:00
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
// ReadNodeAttributes parses node attributes from list of string in "Key:Value" format
|
|
|
|
// and writes them into netmap.NodeInfo instance. Supports escaped symbols
|
|
|
|
// "\:", "\/" and "\\".
|
|
|
|
func ReadNodeAttributes(dst *netmap.NodeInfo, attrs []string) error {
|
|
|
|
cache := make(map[string]struct{}, len(attrs))
|
2020-09-22 10:56:43 +00:00
|
|
|
|
|
|
|
for i := range attrs {
|
2022-06-08 23:18:26 +00:00
|
|
|
line := replaceEscaping(attrs[i], false) // replaced escaped symbols with non-printable symbols
|
2020-09-22 10:56:43 +00:00
|
|
|
|
2023-02-27 14:19:35 +00:00
|
|
|
k, v, found := strings.Cut(line, keyValueSeparator)
|
|
|
|
if !found {
|
2023-06-27 11:26:39 +00:00
|
|
|
return fmt.Errorf("wrong format for node attribute: '%s'", attrs[i])
|
2022-06-08 23:18:26 +00:00
|
|
|
}
|
2021-09-01 09:55:09 +00:00
|
|
|
|
2023-02-27 14:19:35 +00:00
|
|
|
_, ok := cache[k]
|
2022-06-08 23:18:26 +00:00
|
|
|
if ok {
|
2023-02-27 14:19:35 +00:00
|
|
|
return fmt.Errorf("duplicated keys %s", k)
|
2022-06-08 23:18:26 +00:00
|
|
|
}
|
2021-08-04 09:21:40 +00:00
|
|
|
|
2023-02-27 14:19:35 +00:00
|
|
|
cache[k] = struct{}{}
|
2020-09-22 10:56:43 +00:00
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
// replace non-printable symbols with escaped symbols without escape character
|
2023-02-27 14:19:35 +00:00
|
|
|
k = replaceEscaping(k, true)
|
|
|
|
v = replaceEscaping(v, true)
|
2020-09-22 10:56:43 +00:00
|
|
|
|
2023-02-27 14:19:35 +00:00
|
|
|
if k == "" {
|
2023-06-27 11:26:39 +00:00
|
|
|
return fmt.Errorf("empty key in node attribute: '%s'", attrs[i])
|
2023-02-27 14:19:35 +00:00
|
|
|
} else if v == "" {
|
2023-06-27 11:26:39 +00:00
|
|
|
return fmt.Errorf("empty value in node attribute: '%s'", attrs[i])
|
2020-09-22 10:56:43 +00:00
|
|
|
}
|
2022-06-08 23:18:26 +00:00
|
|
|
|
2023-02-27 14:19:35 +00:00
|
|
|
dst.SetAttribute(k, v)
|
2020-09-22 10:56:43 +00:00
|
|
|
}
|
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
return nil
|
2020-09-22 10:56:43 +00:00
|
|
|
}
|
2021-08-04 09:21:40 +00:00
|
|
|
|
|
|
|
func replaceEscaping(target string, rollback bool) (s string) {
|
|
|
|
const escChar = `\`
|
|
|
|
|
|
|
|
var (
|
2022-06-08 23:18:26 +00:00
|
|
|
oldKVSep = escChar + keyValueSeparator
|
|
|
|
oldEsc = escChar + escChar
|
|
|
|
newKVSep = string(uint8(2))
|
|
|
|
newEsc = string(uint8(3))
|
2021-08-04 09:21:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if rollback {
|
2022-06-08 23:18:26 +00:00
|
|
|
oldKVSep, oldEsc = newKVSep, newEsc
|
2021-08-04 09:21:40 +00:00
|
|
|
newKVSep = keyValueSeparator
|
|
|
|
newEsc = escChar
|
|
|
|
}
|
|
|
|
|
|
|
|
s = strings.ReplaceAll(target, oldEsc, newEsc)
|
|
|
|
s = strings.ReplaceAll(s, oldKVSep, newKVSep)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|