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 (
"fmt"
"math/rand"
"net/url"
"os"
"strings"
"sync"
"time"
......@@ -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) {
// neo://name@master1,master2,...,masterN?options
// neo(s)://[credentials@]master1,master2,...,masterN/name?options
defer xerr.Contextf(&err, "neo: open %s", u)
if u.User == nil {
return nil, zodb.InvalidTid, fmt.Errorf("cluster name not specified")
var ssl bool
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)
if err != nil {
return nil, zodb.InvalidTid, err
cred := u.User.String()
if !ssl {
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 {
return nil, zodb.InvalidTid, fmt.Errorf("duplicate parameter %q ", k)
}
q[k] = vv[0]
} else {
x, err := parseQuery(cred)
if err != nil {
return nil, zodb.InvalidTid, fmt.Errorf("credentials: %s", err)
}
qpop := func(k string) string {
v := q[k]
delete(q, k)
// xpop pops k from credentials, defaultin to NEO_<K>
xpop := func(k string) string {
v, ok := x[k]
if !ok {
v = os.Getenv("NEO_"+strings.ToUpper(k))
}
delete(x, k)
return v
}
ssl := false
ca := qpop("ca")
cert := qpop("cert")
key := qpop("key")
ca = xpop("ca")
cert = xpop("cert")
key = xpop("key")
if len(q) != 0 {
return nil, zodb.InvalidTid, fmt.Errorf("invalid query: %v", q)
if len(x) != 0 {
return nil, zodb.InvalidTid, fmt.Errorf("invalid credentials: %v", x)
}
if ca != "" || cert != "" || key != "" {
if !(ca != "" && cert != "" && key != "") {
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) (
net = xnet.NetTLS(net, tlsCfg)
}
c := NewClient(u.User.Username(), u.Host, net)
c := NewClient(name, u.Host, net)
c.watchq = opt.Watchq
defer func() {
if err != nil {
......@@ -712,10 +732,15 @@ func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.DriverOptions) (
}
func (c *Client) URL() string {
// XXX neos:// depending whether it was tls
// 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)
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() {
......
......@@ -26,7 +26,6 @@ import (
"net/url"
"os"
"os/exec"
"strings"
"testing"
"time"
......@@ -175,19 +174,18 @@ func (n *NEOPySrv) MasterAddr() string {
}
func (n *NEOPySrv) ZUrl() string {
zurl := fmt.Sprintf("neo://%s@%s", n.ClusterName(), n.MasterAddr())
argv := []string{}
if n.opt.SSL {
argv = append(argv, "ca=" +url.QueryEscape(n.CA))
argv = append(argv, "cert="+url.QueryEscape(n.Cert))
argv = append(argv, "key=" +url.QueryEscape(n.Key))
}
if len(argv) != 0 {
zurl += "?"
zurl += strings.Join(argv, "&")
zurl := ""
if !n.opt.SSL {
zurl = "neo://"
} else {
zurl = "neos://"
zurl += "ca=" + url.QueryEscape(n.CA) +";"
zurl += "cert=" + url.QueryEscape(n.Cert) +";"
zurl += "key=" + url.QueryEscape(n.Key)
zurl += "@"
}
zurl += fmt.Sprintf("%s/%s", n.MasterAddr(), n.ClusterName())
return zurl
}
......
......@@ -26,6 +26,7 @@ import (
"fmt"
"io"
"io/ioutil"
"net/url"
"lab.nexedi.com/kirr/go123/xerr"
......@@ -148,3 +149,23 @@ func tlsForSSL(ca, cert, key string) (_ *tls.Config, err error) {
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):
# parse credentials
if cred:
if scheme != "neos":
raise ValueError("invalid uri: %s : credentials can be provided only with neos:// scheme" % uri)
# ca:ca.crt;cert:my.crt;key:my.key
credv = cred.split(';')
for arg in credv:
k,v = arg.split(':', 1)
raise ValueError("invalid uri: %s : credentials can be specified only with neos:// scheme" % uri)
# ca=ca.crt;cert=my.crt;key=my.key
for k, v in OrderedDict(parse_qsl(cred)).items():
if k not in _credopts:
raise ValueError("invalid uri: %s : unexpected credential %s" % (uri, k))
neokw[k] = v
......
......@@ -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"
"&beta=222",
"""\
......
......@@ -105,6 +105,7 @@ setup(
],
'zodburi.resolvers': [
'neo = neo.client.zodburi:resolve_uri [client]',
'neos = neo.client.zodburi:resolve_uri [client]',
],
},
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