Commit e97ac850 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
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)
var ssl bool
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)
urlinfo, err := parseURL(ctx, u, opt)
if err != nil {
return nil, zodb.InvalidTid, err
}
if len(q) != 0 {
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)
net, err := neonet.Join(ctx, urlinfo.netcfg)
if err != nil {
return nil, zodb.InvalidTid, err
}
c := NewClient(name, u.Host, net)
c := NewClient(urlinfo.name, urlinfo.masterAddr, net)
c.ownNet = true
c.watchq = opt.Watchq
defer func() {
......@@ -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 NEOUrlInfo. If anything fails within this process an error and an empty
// NEOUrlInfo are returned.
func parseURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) (urlinfo NEOUrlInfo, 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 NEOUrlInfo{}, 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 NEOUrlInfo{}, 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 NEOUrlInfo{}, 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 NEOUrlInfo{}, fmt.Errorf("invalid credentials: %v", x)
}
}
name := u.Path
name = strings.TrimPrefix(name, "/")
if name == "" {
return NEOUrlInfo{}, fmt.Errorf("cluster name not specified")
}
q, err := xurl.ParseQuery(u.RawQuery)
if err != nil {
return NEOUrlInfo{}, err
}
if len(q) != 0 {
return NEOUrlInfo{}, fmt.Errorf("invalid query: %v", q)
}
if !opt.ReadOnly {
return NEOUrlInfo{}, fmt.Errorf("TODO write mode not implemented")
}
masterAddr := u.Host
return NEOUrlInfo{masterAddr, name, netcfg}, nil
}
// NEOUrlInfo encapsulates data extracted from a NEO URI.
type NEOUrlInfo struct {
masterAddr string
name string
netcfg neonet.Config
}
// URL implements zodb.IStorageDriver.
func (c *Client) URL() string {
// 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