rbd: fix parsing mapOptions

Currently, we support

mapOption: "krbd:v1,v2,v3;nbd:v1,v2,v3"

- By omitting `krbd:` or `nbd:`, the option(s) apply to
  rbdDefaultMounter which is krbd.
- A user can _override_ the options for a mounter by specifying `krbd:`
  or `nbd:`.
  mapOption: "v1,v2,v3;nbd:v1,v2,v3"
  is effectively the same as the 1st example.
- Sections are split by `;`.
- If users want to specify common options for both `krbd` and `nbd`,
  they should mention them twice.

But in case if the krbd or nbd specifc options contian `:` within them,
then the parsing is failing now.

E0301 10:19:13.615111 7348 utils.go:200] ID: 63 Req-ID:
0001-0009-rook-ceph-0000000000000001-fd37c41b-9948-11ec-ad32-0242ac110004
GRPC error: badly formatted map/unmap options:
"krbd:read_from_replica=localize,crush_location=zone:zone1;"

This patch fix the above case where the options itself contain `:`
delimitor
ex: krbd:v1,v2,v3=v31:v32;nbd:v1,v2,v3"

Please note, if you are using such options which contain `:` delimiter,
then it is mandatory to specify the mounter-type.

Fixes: #2910
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
This commit is contained in:
Prasanna Kumar Kalever 2022-03-10 16:31:25 +05:30 committed by mergify[bot]
parent c435c7bf21
commit 3eb0fa5e21
2 changed files with 19 additions and 16 deletions

View File

@ -228,21 +228,19 @@ func setRbdNbdToolFeatures() {
// returns mounter specific options. // returns mounter specific options.
func parseMapOptions(mapOptions string) (string, string, error) { func parseMapOptions(mapOptions string) (string, string, error) {
var krbdMapOptions, nbdMapOptions string var krbdMapOptions, nbdMapOptions string
const (
noKeyLength = 1
validLength = 2
)
for _, item := range strings.Split(mapOptions, ";") { for _, item := range strings.Split(mapOptions, ";") {
var mounter, options string var mounter, options string
if item == "" { if item == "" {
continue continue
} }
s := strings.Split(item, ":") s := strings.SplitN(item, ":", 2)
switch len(s) { if len(s) == 1 {
case noKeyLength:
options = strings.TrimSpace(s[0]) options = strings.TrimSpace(s[0])
krbdMapOptions = options krbdMapOptions = options
case validLength: } else {
// options might also contain values delimited with ":", in this
// case mounter type MUST be specified.
// ex: krbd:read_from_replica=localize,crush_location=zone:zone1;
mounter = strings.TrimSpace(s[0]) mounter = strings.TrimSpace(s[0])
options = strings.TrimSpace(s[1]) options = strings.TrimSpace(s[1])
switch strings.ToLower(mounter) { switch strings.ToLower(mounter) {
@ -251,10 +249,8 @@ func parseMapOptions(mapOptions string) (string, string, error) {
case accessTypeNbd: case accessTypeNbd:
nbdMapOptions = options nbdMapOptions = options
default: default:
return "", "", fmt.Errorf("unknown mounter type: %q", mounter) return "", "", fmt.Errorf("unknown mounter type: %q, please specify mounter type", mounter)
} }
default:
return "", "", fmt.Errorf("badly formatted map/unmap options: %q", mapOptions)
} }
} }

View File

@ -60,18 +60,25 @@ func TestParseMapOptions(t *testing.T) {
expectErr: "", expectErr: "",
}, },
{ {
name: "unknown mounter used", name: "with `:` delimiter used with in the options",
mapOption: "xyz:xOp1,xOp2", mapOption: "krbd:kOp1,kOp2=kOp21:kOp22;nbd:nOp1,nOp2=nOp21:nOp22",
expectKrbdOptions: "kOp1,kOp2=kOp21:kOp22",
expectNbdOptions: "nOp1,nOp2=nOp21:nOp22",
expectErr: "",
},
{
name: "with `:` delimiter used with in the options, without mounter label",
mapOption: "kOp1,kOp2=kOp21:kOp22;nbd:nOp1,nOp2",
expectKrbdOptions: "", expectKrbdOptions: "",
expectNbdOptions: "", expectNbdOptions: "",
expectErr: "unknown mounter type", expectErr: "unknown mounter type",
}, },
{ {
name: "bad formatted options", name: "unknown mounter used",
mapOption: "nbd:nOp1:nOp2;", mapOption: "xyz:xOp1,xOp2",
expectKrbdOptions: "", expectKrbdOptions: "",
expectNbdOptions: "", expectNbdOptions: "",
expectErr: "badly formatted map/unmap options", expectErr: "unknown mounter type",
}, },
} }
for _, tt := range tests { for _, tt := range tests {