Commit 7904f767 authored by Levin Zimmermann's avatar Levin Zimmermann

client: Refactor openClientByURL for easier testing

With all the recent changes of the NEO URI scheme we need to reliably test
the function which parses the URI and convert it into the different
parameter. Testing is much simpler if we can only analyse how the URI
parsing works. Therefore this patch moves NEO URI parsing to an
external function.
parent b6222954
...@@ -414,76 +414,19 @@ func (c *Client) Iterate(ctx context.Context, tidMin, tidMax zodb.Tid) zodb.ITxn ...@@ -414,76 +414,19 @@ func (c *Client) Iterate(ctx context.Context, tidMin, tidMax zodb.Tid) zodb.ITxn
func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) (_ zodb.IStorageDriver, _ zodb.Tid, err error) { func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) (_ zodb.IStorageDriver, _ zodb.Tid, err error) {
// neo(s)://[credentials@]master1,master2,...,masterN/name?options
defer task.Runningf(&ctx, "neo: open %s", u)(&err) defer task.Runningf(&ctx, "neo: open %s", u)(&err)
var ssl bool urlinfo, err := parseURL(ctx, u, opt)
switch u.Scheme {
case "neo": ssl = false
case "neos": ssl = true
default: return nil, zodb.InvalidTid, fmt.Errorf("invalid scheme")
}
cred := u.User.String()
// ca=ca.crt;cert=my.crt;key=my.key
cred = strings.ReplaceAll(cred, ";", "&") // ; is no longer in default separators set https://github.com/golang/go/issues/25192
x, err := xurl.ParseQuery(cred)
if err != nil {
return nil, zodb.InvalidTid, fmt.Errorf("credentials: %s", err)
}
// xpop pops k from credentials, defaulting to $NEO_<K> if envok.
xpop := func(k string, envok bool) string {
v, ok := x[k]
if !ok && envok {
v = os.Getenv("NEO_"+strings.ToUpper(k))
}
delete(x, k)
return v
}
netcfg := neonet.Config{}
netcfg.LoNode = xpop("lonode", false)
if !ssl {
if len(x) != 0 {
return nil, zodb.InvalidTid, fmt.Errorf("credentials can be specified only with neos:// scheme")
}
} else {
netcfg.CA = xpop("ca", true)
netcfg.Cert = xpop("cert", true)
netcfg.Key = xpop("key", true)
if len(x) != 0 {
return nil, zodb.InvalidTid, fmt.Errorf("invalid credentials: %v", x)
}
}
name := u.Path
name = strings.TrimPrefix(name, "/")
if name == "" {
return nil, zodb.InvalidTid, fmt.Errorf("cluster name not specified")
}
q, err := xurl.ParseQuery(u.RawQuery)
if err != nil { if err != nil {
return nil, zodb.InvalidTid, err return nil, zodb.InvalidTid, err
} }
if len(q) != 0 { net, err := neonet.Join(ctx, urlinfo.netcfg)
return nil, zodb.InvalidTid, fmt.Errorf("invalid query: %v", q)
}
if !opt.ReadOnly {
return nil, zodb.InvalidTid, fmt.Errorf("TODO write mode not implemented")
}
net, err := neonet.Join(ctx, netcfg)
if err != nil { if err != nil {
return nil, zodb.InvalidTid, err return nil, zodb.InvalidTid, err
} }
c := NewClient(name, u.Host, net) c := NewClient(urlinfo.name, urlinfo.masterAddr, net)
c.ownNet = true c.ownNet = true
c.watchq = opt.Watchq c.watchq = opt.Watchq
defer func() { defer func() {
...@@ -533,6 +476,84 @@ func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) ( ...@@ -533,6 +476,84 @@ func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) (
} }
} }
// parseURL extracts information from a NEO URI and puts this information into
// a urlInfo and the DriverOptions. If anything fails within this process
// an error and nil are returned.
func parseURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) (urlinfo urlInfo, err error) {
// neo(s)://[credentials@]master1,master2,...,masterN/name?options
var ssl bool
switch u.Scheme {
case "neo": ssl = false
case "neos": ssl = true
default: return nil, fmt.Errorf("invalid scheme")
}
cred := u.User.String()
// ca=ca.crt;cert=my.crt;key=my.key
cred = strings.ReplaceAll(cred, ";", "&") // ; is no longer in default separators set https://github.com/golang/go/issues/25192
x, err := xurl.ParseQuery(cred)
if err != nil {
return nil, fmt.Errorf("credentials: %s", err)
}
// xpop pops k from credentials, defaulting to $NEO_<K> if envok.
xpop := func(k string, envok bool) string {
v, ok := x[k]
if !ok && envok {
v = os.Getenv("NEO_"+strings.ToUpper(k))
}
delete(x, k)
return v
}
netcfg := neonet.Config{}
netcfg.LoNode = xpop("lonode", false)
if !ssl {
if len(x) != 0 {
return nil, fmt.Errorf("credentials can be specified only with neos:// scheme")
}
} else {
netcfg.CA = xpop("ca", true)
netcfg.Cert = xpop("cert", true)
netcfg.Key = xpop("key", true)
if len(x) != 0 {
return nil, fmt.Errorf("invalid credentials: %v", x)
}
}
name := u.Path
name = strings.TrimPrefix(name, "/")
if name == "" {
return nil, fmt.Errorf("cluster name not specified")
}
q, err := xurl.ParseQuery(u.RawQuery)
if err != nil {
return nil, err
}
if len(q) != 0 {
return nil, fmt.Errorf("invalid query: %v", q)
}
if !opt.ReadOnly {
return nil, fmt.Errorf("TODO write mode not implemented")
}
masterAddr := u.Host
return urlInfo{masterAddr, name, netcfg}, nil
}
// urlInfo encapsulates data extracted from a NEO URI.
type urlInfo struct {
masterAddr string
name string
netcfg neonet.Config
}
// URL implements zodb.IStorageDriver. // URL implements zodb.IStorageDriver.
func (c *Client) URL() string { func (c *Client) URL() string {
// XXX options if such were given to open are discarded // XXX options if such were given to open are discarded
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment