Commit 8c974485 authored by Kirill Smelkov's avatar Kirill Smelkov

X Adjust NEO/go to neo:// URL change + py fixups

parent b9a42957
...@@ -25,6 +25,8 @@ import ( ...@@ -25,6 +25,8 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"net/url" "net/url"
"os"
"strings"
"sync" "sync"
"time" "time"
...@@ -608,48 +610,66 @@ func (c *Client) Watch(ctx context.Context) (zodb.Tid, []zodb.Oid, error) { ...@@ -608,48 +610,66 @@ func (c *Client) Watch(ctx context.Context) (zodb.Tid, []zodb.Oid, error) {
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://name@master1,master2,...,masterN?options // neo(s)://[credentials@]master1,master2,...,masterN/name?options
defer xerr.Contextf(&err, "neo: open %s", u) defer xerr.Contextf(&err, "neo: open %s", u)
if u.User == nil { var ssl bool
return nil, zodb.InvalidTid, fmt.Errorf("cluster name not specified") var ca, cert, key string
switch u.Scheme {
case "neo": ssl = false
case "neos": ssl = true
default: return nil, zodb.InvalidTid, fmt.Errorf("invalid scheme")
} }
qv, err := url.ParseQuery(u.RawQuery) cred := u.User.String()
if err != nil { if !ssl {
return nil, zodb.InvalidTid, err if cred != "" {
} return nil, zodb.InvalidTid, fmt.Errorf("credentials can be specified only with neos:// scheme")
q := map[string]string{}
for k, vv := range qv {
if len(vv) == 0 {
return nil, zodb.InvalidTid, fmt.Errorf("parameter %q without value", k)
} }
if len(vv) != 1 { } else {
return nil, zodb.InvalidTid, fmt.Errorf("duplicate parameter %q ", k) x, err := parseQuery(cred)
if err != nil {
return nil, zodb.InvalidTid, fmt.Errorf("credentials: %s", err)
} }
q[k] = vv[0]
}
qpop := func(k string) string { // xpop pops k from credentials, defaultin to NEO_<K>
v := q[k] xpop := func(k string) string {
delete(q, k) v, ok := x[k]
return v if !ok {
} v = os.Getenv("NEO_"+strings.ToUpper(k))
}
delete(x, k)
return v
}
ssl := false ca = xpop("ca")
ca := qpop("ca") cert = xpop("cert")
cert := qpop("cert") key = xpop("key")
key := qpop("key")
if len(q) != 0 { if len(x) != 0 {
return nil, zodb.InvalidTid, fmt.Errorf("invalid query: %v", q) return nil, zodb.InvalidTid, fmt.Errorf("invalid credentials: %v", x)
} }
if ca != "" || cert != "" || key != "" {
if !(ca != "" && cert != "" && key != "") { if !(ca != "" && cert != "" && key != "") {
return nil, zodb.InvalidTid, fmt.Errorf("incomplete ca/cert/key provided") return nil, zodb.InvalidTid, fmt.Errorf("incomplete ca/cert/key provided")
} }
ssl = true }
name := u.Path
if strings.HasPrefix(name, "/") {
name = name[1:]
}
if name == "" {
return nil, zodb.InvalidTid, fmt.Errorf("cluster name not specified")
}
q, err := parseQuery(u.RawQuery)
if err != nil {
return nil, zodb.InvalidTid, err
}
if len(q) != 0 {
return nil, zodb.InvalidTid, fmt.Errorf("invalid query: %v", q)
} }
...@@ -666,7 +686,7 @@ func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) ( ...@@ -666,7 +686,7 @@ func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) (
net = xnet.NetTLS(net, tlsCfg) net = xnet.NetTLS(net, tlsCfg)
} }
c := NewClient(u.User.Username(), u.Host, net) c := NewClient(name, u.Host, net)
c.watchq = opt.Watchq c.watchq = opt.Watchq
defer func() { defer func() {
if err != nil { if err != nil {
...@@ -712,10 +732,15 @@ func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) ( ...@@ -712,10 +732,15 @@ func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) (
} }
func (c *Client) URL() string { func (c *Client) URL() string {
// XXX neos:// depending whether it was tls
// XXX options if such were given to open are discarded // XXX options if such were given to open are discarded
// (but we need to be able to construct URL if Client was created via NewClient directly) // (but we need to be able to construct URL if Client was created via NewClient directly)
return fmt.Sprintf("neo://%s@%s", c.node.ClusterName, c.node.MasterAddr)
zurl := "neo"
if strings.Contains(c.node.Net.Network(), "+tls") {
zurl += "s"
}
zurl += fmt.Sprintf("://%s/%s", c.node.MasterAddr, c.node.ClusterName)
return zurl
} }
func init() { func init() {
......
...@@ -26,7 +26,6 @@ import ( ...@@ -26,7 +26,6 @@ import (
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
"strings"
"testing" "testing"
"time" "time"
...@@ -175,19 +174,18 @@ func (n *NEOPySrv) MasterAddr() string { ...@@ -175,19 +174,18 @@ func (n *NEOPySrv) MasterAddr() string {
} }
func (n *NEOPySrv) ZUrl() string { func (n *NEOPySrv) ZUrl() string {
zurl := fmt.Sprintf("neo://%s@%s", n.ClusterName(), n.MasterAddr()) zurl := ""
argv := []string{} if !n.opt.SSL {
if n.opt.SSL { zurl = "neo://"
argv = append(argv, "ca=" +url.QueryEscape(n.CA)) } else {
argv = append(argv, "cert="+url.QueryEscape(n.Cert)) zurl = "neos://"
argv = append(argv, "key=" +url.QueryEscape(n.Key)) zurl += "ca=" + url.QueryEscape(n.CA) +";"
} zurl += "cert=" + url.QueryEscape(n.Cert) +";"
zurl += "key=" + url.QueryEscape(n.Key)
if len(argv) != 0 { zurl += "@"
zurl += "?"
zurl += strings.Join(argv, "&")
} }
zurl += fmt.Sprintf("%s/%s", n.MasterAddr(), n.ClusterName())
return zurl return zurl
} }
......
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/url"
"lab.nexedi.com/kirr/go123/xerr" "lab.nexedi.com/kirr/go123/xerr"
...@@ -148,3 +149,23 @@ func tlsForSSL(ca, cert, key string) (_ *tls.Config, err error) { ...@@ -148,3 +149,23 @@ func tlsForSSL(ca, cert, key string) (_ *tls.Config, err error) {
return tlsCfg, nil return tlsCfg, nil
} }
// parseQuery parses query string into regular map.
// see also url.ParseQuery
func parseQuery(query string) (map[string]string, error) {
qv, err := url.ParseQuery(query)
if err != nil {
return nil, err
}
q := map[string]string{}
for k, vv := range qv {
if len(vv) == 0 {
return nil, fmt.Errorf("parameter %q without value", k)
}
if len(vv) != 1 {
return nil, fmt.Errorf("duplicate parameter %q ", k)
}
q[k] = vv[0]
}
return q, nil
}
...@@ -82,11 +82,9 @@ def _resolve_uri(uri): ...@@ -82,11 +82,9 @@ def _resolve_uri(uri):
# parse credentials # parse credentials
if cred: if cred:
if scheme != "neos": if scheme != "neos":
raise ValueError("invalid uri: %s : credentials can be provided only with neos:// scheme" % uri) raise ValueError("invalid uri: %s : credentials can be specified only with neos:// scheme" % uri)
# ca:ca.crt;cert:my.crt;key:my.key # ca=ca.crt;cert=my.crt;key=my.key
credv = cred.split(';') for k, v in OrderedDict(parse_qsl(cred)).items():
for arg in credv:
k,v = arg.split(':', 1)
if k not in _credopts: if k not in _credopts:
raise ValueError("invalid uri: %s : unexpected credential %s" % (uri, k)) raise ValueError("invalid uri: %s : unexpected credential %s" % (uri, k))
neokw[k] = v neokw[k] = v
......
...@@ -42,7 +42,7 @@ testv = [ ...@@ -42,7 +42,7 @@ testv = [
""", """,
{}), {}),
("neos://ca:qqq;cert:rrr;key:sss@[2001:67c:1254:2a::1]:1234,master2:port2/db4?read_only=false" ("neos://ca=qqq;cert=rrr;key=sss@[2001:67c:1254:2a::1]:1234,master2:port2/db4?read_only=false"
"&compress=true&logfile=xxx&alpha=111&dynamic_master_list=zzz" "&compress=true&logfile=xxx&alpha=111&dynamic_master_list=zzz"
"&beta=222", "&beta=222",
"""\ """\
......
...@@ -104,7 +104,8 @@ setup( ...@@ -104,7 +104,8 @@ setup(
'stat_zodb=neo.tests.stat_zodb:main', 'stat_zodb=neo.tests.stat_zodb:main',
], ],
'zodburi.resolvers': [ 'zodburi.resolvers': [
'neo = neo.client.zodburi:resolve_uri [client]', 'neo = neo.client.zodburi:resolve_uri [client]',
'neos = neo.client.zodburi:resolve_uri [client]',
], ],
}, },
install_requires = [ install_requires = [
......
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