<commit_before>package consul

import (
	"fmt"
	"github.com/hashicorp/consul/testutil"
	"io/ioutil"
	"net"
	"os"
	"testing"
	"time"
	"errors"
)

var nextPort = 15000

func getPort() int {
	p := nextPort
	nextPort++
	return p
}

func tmpDir(t *testing.T) string {
	dir, err := ioutil.TempDir("", "consul")
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return dir
}

func configureTLS(config *Config) {
	config.CAFile = "../test/ca/root.cer"
	config.CertFile = "../test/key/ourdomain.cer"
	config.KeyFile = "../test/key/ourdomain.key"
}

func testServerConfig(t *testing.T) (string, *Config) {
	dir := tmpDir(t)
	config := DefaultConfig()
	config.Bootstrap = true
	config.Datacenter = "dc1"
	config.DataDir = dir

	// Adjust the ports
	p := getPort()
	config.NodeName = fmt.Sprintf("Node %d", p)
	config.RPCAddr = &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: p,
	}
	config.SerfLANConfig.MemberlistConfig.BindAddr = "127.0.0.1"
	config.SerfLANConfig.MemberlistConfig.BindPort = getPort()
	config.SerfLANConfig.MemberlistConfig.SuspicionMult = 2
	config.SerfLANConfig.MemberlistConfig.ProbeTimeout = 50 * time.Millisecond
	config.SerfLANConfig.MemberlistConfig.ProbeInterval = 100 * time.Millisecond
	config.SerfLANConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond

	config.SerfWANConfig.MemberlistConfig.BindAddr = "127.0.0.1"
	config.SerfWANConfig.MemberlistConfig.BindPort = getPort()
	config.SerfWANConfig.MemberlistConfig.SuspicionMult = 2
	config.SerfWANConfig.MemberlistConfig.ProbeTimeout = 50 * time.Millisecond
	config.SerfWANConfig.MemberlistConfig.ProbeInterval = 100 * time.Millisecond
	config.SerfWANConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond

	config.RaftConfig.HeartbeatTimeout = 40 * time.Millisecond
	config.RaftConfig.ElectionTimeout = 40 * time.Millisecond

	config.ReconcileInterval = 100 * time.Millisecond
	return dir, config
}

func testServer(t *testing.T) (string, *Server) {
	return testServerDC(t, "dc1")
}

func testServerDC(t *testing.T, dc string) (string, *Server) {
	return testServerDCBootstrap(t, dc, true)
}

func testServerDCBootstrap(t *testing.T, dc string, bootstrap bool) (string, *Server) {
	dir, config := testServerConfig(t)
	config.Datacenter = dc
	config.Bootstrap = bootstrap
	server, err := NewServer(config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return dir, server
}

func TestServer_StartStop(t *testing.T) {
	dir := tmpDir(t)
	defer os.RemoveAll(dir)

	config := DefaultConfig()
	config.DataDir = dir

	private, err := GetPrivateIP()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	config.RPCAdvertise = &net.TCPAddr{
		IP:   private.IP,
		Port: 8300,
	}

	server, err := NewServer(config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if err := server.Shutdown(); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Idempotent
	if err := server.Shutdown(); err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestServer_JoinLAN(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, s2 := testServer(t)
	defer os.RemoveAll(dir2)
	defer s2.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := s2.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	if len(s1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	if len(s2.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}
}

func TestServer_JoinWAN(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, s2 := testServerDC(t, "dc2")
	defer os.RemoveAll(dir2)
	defer s2.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfWANConfig.MemberlistConfig.BindPort)
	if _, err := s2.JoinWAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	if len(s1.WANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	if len(s2.WANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	// Check the remoteConsuls has both
	if len(s1.remoteConsuls) != 2 {
		t.Fatalf("remote consul missing")
	}

	testutil.WaitForResult(func() (bool, error) {
		return len(s2.remoteConsuls) == 2, nil
	}, func(err error) {
		t.Fatalf("remote consul missing")
	})
}

func TestServer_Leave(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	// Second server not in bootstrap mode
	dir2, s2 := testServerDCBootstrap(t, "dc1", false)
	defer os.RemoveAll(dir2)
	defer s2.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := s2.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	var p1 []net.Addr
	var p2 []net.Addr

	testutil.WaitForResult(func() (bool, error) {
		p1, _ = s1.raftPeers.Peers()
		return len(p1) == 2, errors.New(fmt.Sprintf("%v", p1))
	}, func(err error) {
		t.Fatalf("should have 2 peers: %v", err)
	})

	testutil.WaitForResult(func() (bool, error) {
		p2, _ = s2.raftPeers.Peers()
		return len(p2) == 2, errors.New(fmt.Sprintf("%v", p1))
	}, func(err error) {
		t.Fatalf("should have 2 peers: %v", err)
	})

	// Issue a leave
	if err := s2.Leave(); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Should lose a peer
	p1, _ = s1.raftPeers.Peers()
	if len(p1) != 1 {
		t.Fatalf("should have 1 peer: %v", p1)
	}
}

func TestServer_RPC(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	var out struct{}
	if err := s1.RPC("Status.Ping", struct{}{}, &out); err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestServer_JoinLAN_TLS(t *testing.T) {
	dir1, conf1 := testServerConfig(t)
	conf1.VerifyIncoming = true
	conf1.VerifyOutgoing = true
	configureTLS(conf1)
	s1, err := NewServer(conf1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, conf2 := testServerConfig(t)
	conf2.Bootstrap = false
	conf2.VerifyIncoming = true
	conf2.VerifyOutgoing = true
	configureTLS(conf2)
	s2, err := NewServer(conf2)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	defer os.RemoveAll(dir2)
	defer s2.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := s2.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	if len(s1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	if len(s2.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	// Verify Raft has established a peer
	testutil.WaitForResult(func() (bool, error) {
		return s1.Stats()["raft"]["num_peers"] == "1", nil
	}, func(err error) {
		t.Fatalf("no peer established")
	})

	testutil.WaitForResult(func() (bool, error) {
		return s2.Stats()["raft"]["num_peers"] == "1", nil
	}, func(err error) {
		t.Fatalf("no peer established")
	})
}
<commit_msg>Wait wrap tests in `TestServer_JoinLAN`<commit_after>package consul

import (
	"fmt"
	"github.com/hashicorp/consul/testutil"
	"io/ioutil"
	"net"
	"os"
	"testing"
	"time"
	"errors"
)

var nextPort = 15000

func getPort() int {
	p := nextPort
	nextPort++
	return p
}

func tmpDir(t *testing.T) string {
	dir, err := ioutil.TempDir("", "consul")
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return dir
}

func configureTLS(config *Config) {
	config.CAFile = "../test/ca/root.cer"
	config.CertFile = "../test/key/ourdomain.cer"
	config.KeyFile = "../test/key/ourdomain.key"
}

func testServerConfig(t *testing.T) (string, *Config) {
	dir := tmpDir(t)
	config := DefaultConfig()
	config.Bootstrap = true
	config.Datacenter = "dc1"
	config.DataDir = dir

	// Adjust the ports
	p := getPort()
	config.NodeName = fmt.Sprintf("Node %d", p)
	config.RPCAddr = &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: p,
	}
	config.SerfLANConfig.MemberlistConfig.BindAddr = "127.0.0.1"
	config.SerfLANConfig.MemberlistConfig.BindPort = getPort()
	config.SerfLANConfig.MemberlistConfig.SuspicionMult = 2
	config.SerfLANConfig.MemberlistConfig.ProbeTimeout = 50 * time.Millisecond
	config.SerfLANConfig.MemberlistConfig.ProbeInterval = 100 * time.Millisecond
	config.SerfLANConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond

	config.SerfWANConfig.MemberlistConfig.BindAddr = "127.0.0.1"
	config.SerfWANConfig.MemberlistConfig.BindPort = getPort()
	config.SerfWANConfig.MemberlistConfig.SuspicionMult = 2
	config.SerfWANConfig.MemberlistConfig.ProbeTimeout = 50 * time.Millisecond
	config.SerfWANConfig.MemberlistConfig.ProbeInterval = 100 * time.Millisecond
	config.SerfWANConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond

	config.RaftConfig.HeartbeatTimeout = 40 * time.Millisecond
	config.RaftConfig.ElectionTimeout = 40 * time.Millisecond

	config.ReconcileInterval = 100 * time.Millisecond
	return dir, config
}

func testServer(t *testing.T) (string, *Server) {
	return testServerDC(t, "dc1")
}

func testServerDC(t *testing.T, dc string) (string, *Server) {
	return testServerDCBootstrap(t, dc, true)
}

func testServerDCBootstrap(t *testing.T, dc string, bootstrap bool) (string, *Server) {
	dir, config := testServerConfig(t)
	config.Datacenter = dc
	config.Bootstrap = bootstrap
	server, err := NewServer(config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return dir, server
}

func TestServer_StartStop(t *testing.T) {
	dir := tmpDir(t)
	defer os.RemoveAll(dir)

	config := DefaultConfig()
	config.DataDir = dir

	private, err := GetPrivateIP()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	config.RPCAdvertise = &net.TCPAddr{
		IP:   private.IP,
		Port: 8300,
	}

	server, err := NewServer(config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if err := server.Shutdown(); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Idempotent
	if err := server.Shutdown(); err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestServer_JoinLAN(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, s2 := testServer(t)
	defer os.RemoveAll(dir2)
	defer s2.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := s2.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	testutil.WaitForResult(func() (bool, error) {
		return len(s1.LANMembers()) == 2, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	testutil.WaitForResult(func() (bool, error) {
		return len(s2.LANMembers()) == 2, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})
}

func TestServer_JoinWAN(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, s2 := testServerDC(t, "dc2")
	defer os.RemoveAll(dir2)
	defer s2.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfWANConfig.MemberlistConfig.BindPort)
	if _, err := s2.JoinWAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	testutil.WaitForResult(func() (bool, error) {
		return len(s1.WANMembers()) == 2, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	testutil.WaitForResult(func() (bool, error) {
		return len(s2.WANMembers()) == 2, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	// Check the remoteConsuls has both
	if len(s1.remoteConsuls) != 2 {
		t.Fatalf("remote consul missing")
	}

	testutil.WaitForResult(func() (bool, error) {
		return len(s2.remoteConsuls) == 2, nil
	}, func(err error) {
		t.Fatalf("remote consul missing")
	})
}

func TestServer_Leave(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	// Second server not in bootstrap mode
	dir2, s2 := testServerDCBootstrap(t, "dc1", false)
	defer os.RemoveAll(dir2)
	defer s2.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := s2.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	var p1 []net.Addr
	var p2 []net.Addr

	testutil.WaitForResult(func() (bool, error) {
		p1, _ = s1.raftPeers.Peers()
		return len(p1) == 2, errors.New(fmt.Sprintf("%v", p1))
	}, func(err error) {
		t.Fatalf("should have 2 peers: %v", err)
	})

	testutil.WaitForResult(func() (bool, error) {
		p2, _ = s2.raftPeers.Peers()
		return len(p2) == 2, errors.New(fmt.Sprintf("%v", p1))
	}, func(err error) {
		t.Fatalf("should have 2 peers: %v", err)
	})

	// Issue a leave
	if err := s2.Leave(); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Should lose a peer
	p1, _ = s1.raftPeers.Peers()
	if len(p1) != 1 {
		t.Fatalf("should have 1 peer: %v", p1)
	}
}

func TestServer_RPC(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	var out struct{}
	if err := s1.RPC("Status.Ping", struct{}{}, &out); err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestServer_JoinLAN_TLS(t *testing.T) {
	dir1, conf1 := testServerConfig(t)
	conf1.VerifyIncoming = true
	conf1.VerifyOutgoing = true
	configureTLS(conf1)
	s1, err := NewServer(conf1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, conf2 := testServerConfig(t)
	conf2.Bootstrap = false
	conf2.VerifyIncoming = true
	conf2.VerifyOutgoing = true
	configureTLS(conf2)
	s2, err := NewServer(conf2)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	defer os.RemoveAll(dir2)
	defer s2.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := s2.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	testutil.WaitForResult(func() (bool, error) {
		return len(s1.LANMembers()) == 2, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	testutil.WaitForResult(func() (bool, error) {
		return len(s2.LANMembers()) == 2, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	// Verify Raft has established a peer
	testutil.WaitForResult(func() (bool, error) {
		return s1.Stats()["raft"]["num_peers"] == "1", nil
	}, func(err error) {
		t.Fatalf("no peer established")
	})

	testutil.WaitForResult(func() (bool, error) {
		return s2.Stats()["raft"]["num_peers"] == "1", nil
	}, func(err error) {
		t.Fatalf("no peer established")
	})
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/coreos/etcd-operator/pkg/cluster"
	"github.com/coreos/etcd-operator/pkg/spec"
	"github.com/coreos/etcd-operator/pkg/util/constants"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil"
	"github.com/coreos/etcd-operator/test/e2e/framework"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	k8sclient "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util/wait"
)

func waitBackupPodUp(f *framework.Framework, clusterName string, timeout time.Duration) error {
	return wait.Poll(5*time.Second, timeout, func() (done bool, err error) {
		podList, err := f.KubeClient.Pods(f.Namespace.Name).List(api.ListOptions{
			LabelSelector: labels.SelectorFromSet(map[string]string{
				"app":          k8sutil.BackupPodSelectorAppField,
				"etcd_cluster": clusterName,
			})})
		if err != nil {
			return false, err
		}
		return len(podList.Items) > 0, nil
	})
}

func makeBackup(f *framework.Framework, clusterName string) error {
	svc, err := f.KubeClient.Services(f.Namespace.Name).Get(k8sutil.MakeBackupName(clusterName))
	if err != nil {
		return err
	}

	err = wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
		// In our test environment, we assume kube-proxy should be running on the same node.
		// Thus we can use the service IP.
		// We are polling here because there could be delay of propagating service IP.
		err := cluster.RequestBackupNow(f.KubeClient.Client, fmt.Sprintf("%s:%d", svc.Spec.ClusterIP, constants.DefaultBackupPodHTTPPort))
		if err != nil {
			logrus.Errorf("fail to request backupnow: %v", err)
			return false, nil
		}
		return true, nil
	})
	return err
}

func waitUntilSizeReached(f *framework.Framework, clusterName string, size, timeout int) ([]string, error) {
	return waitSizeReachedWithFilter(f, clusterName, size, timeout, func(*api.Pod) bool { return true })
}

func waitSizeReachedWithFilter(f *framework.Framework, clusterName string, size, timeout int, filterPod func(*api.Pod) bool) ([]string, error) {
	var names []string
	err := wait.Poll(5*time.Second, time.Duration(timeout)*time.Second, func() (done bool, err error) {
		podList, err := f.KubeClient.Pods(f.Namespace.Name).List(k8sutil.EtcdPodListOpt(clusterName))
		if err != nil {
			return false, err
		}
		names = nil
		for i := range podList.Items {
			pod := &podList.Items[i]
			if pod.Status.Phase == api.PodRunning {
				names = append(names, pod.Name)
			}
		}
		fmt.Printf("waiting size (%d), etcd pods: %v\n", size, names)
		if len(names) != size {
			return false, nil
		}
		// TODO: check etcd member membership
		return true, nil
	})
	if err != nil {
		return nil, err
	}
	return names, nil
}

func killMembers(f *framework.Framework, names ...string) error {
	for _, name := range names {
		err := f.KubeClient.Pods(f.Namespace.Name).Delete(name, api.NewDeleteOptions(0))
		if err != nil {
			return err
		}
	}
	return nil
}

func makeEtcdCluster(genName string, size int) *spec.EtcdCluster {
	return &spec.EtcdCluster{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "EtcdCluster",
			APIVersion: "coreos.com/v1",
		},
		ObjectMeta: api.ObjectMeta{
			GenerateName: genName,
		},
		Spec: spec.ClusterSpec{
			Size: size,
		},
	}
}

func etcdClusterWithBackup(ec *spec.EtcdCluster, backupPolicy *spec.BackupPolicy) *spec.EtcdCluster {
	ec.Spec.Backup = backupPolicy
	return ec
}
func etcdClusterWithVersion(ec *spec.EtcdCluster, version string) *spec.EtcdCluster {
	ec.Spec.Version = version
	return ec
}

func createEtcdCluster(f *framework.Framework, e *spec.EtcdCluster) (*spec.EtcdCluster, error) {
	b, err := json.Marshal(e)
	if err != nil {
		return nil, err
	}
	resp, err := f.KubeClient.Client.Post(
		fmt.Sprintf("%s/apis/coreos.com/v1/namespaces/%s/etcdclusters", f.MasterHost, f.Namespace.Name),
		"application/json", bytes.NewReader(b))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusCreated {
		return nil, fmt.Errorf("unexpected status: %v", resp.Status)
	}
	decoder := json.NewDecoder(resp.Body)
	res := &spec.EtcdCluster{}
	if err := decoder.Decode(res); err != nil {
		return nil, err
	}
	fmt.Printf("created etcd cluster: %v\n", res.Name)
	return res, nil
}

func updateEtcdCluster(f *framework.Framework, e *spec.EtcdCluster) (*spec.EtcdCluster, error) {
	b, err := json.Marshal(e)
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest("PUT",
		fmt.Sprintf("%s/apis/coreos.com/v1/namespaces/%s/etcdclusters/%s", f.MasterHost, f.Namespace.Name, e.Name),
		bytes.NewReader(b))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := f.KubeClient.Client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unexpected status: %v", resp.Status)
	}
	decoder := json.NewDecoder(resp.Body)
	nspec := &spec.EtcdCluster{}
	if err := decoder.Decode(nspec); err != nil {
		return nil, err
	}
	return nspec, nil
}

func deleteEtcdCluster(f *framework.Framework, name string) error {
	fmt.Printf("deleting etcd cluster: %v\n", name)
	podList, err := f.KubeClient.Pods(f.Namespace.Name).List(k8sutil.EtcdPodListOpt(name))
	if err != nil {
		return err
	}
	fmt.Println("etcd pods ======")
	for i := range podList.Items {
		pod := &podList.Items[i]
		fmt.Printf("pod (%v): status (%v)\n", pod.Name, pod.Status.Phase)
		buf := bytes.NewBuffer(nil)

		if pod.Status.Phase == api.PodFailed {
			if err := getLogs(f.KubeClient, f.Namespace.Name, pod.Name, "etcd", buf); err != nil {
				return err
			}
			fmt.Println(pod.Name, "logs ===")
			fmt.Println(buf.String())
			fmt.Println(pod.Name, "logs END ===")
		}
	}

	buf := bytes.NewBuffer(nil)
	if err := getLogs(f.KubeClient, f.Namespace.Name, "etcd-operator", "etcd-operator", buf); err != nil {
		return err
	}
	fmt.Println("etcd-operator logs ===")
	fmt.Println(buf.String())
	fmt.Println("etcd-operator logs END ===")

	req, err := http.NewRequest("DELETE",
		fmt.Sprintf("%s/apis/coreos.com/v1/namespaces/%s/etcdclusters/%s", f.MasterHost, f.Namespace.Name, name), nil)
	if err != nil {
		return err
	}
	resp, err := f.KubeClient.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected status: %v", resp.Status)
	}
	return nil
}

func getLogs(kubecli *k8sclient.Client, ns, p, c string, out io.Writer) error {
	req := kubecli.RESTClient.Get().
		Namespace(ns).
		Resource("pods").
		Name(p).
		SubResource("log").
		Param("container", c).
		Param("tailLines", "20")

	readCloser, err := req.Stream()
	if err != nil {
		return err
	}
	defer readCloser.Close()

	_, err = io.Copy(out, readCloser)
	return err
}
<commit_msg>e2e: refactor make backup using pod IP<commit_after>// Copyright 2016 The etcd-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/coreos/etcd-operator/pkg/cluster"
	"github.com/coreos/etcd-operator/pkg/spec"
	"github.com/coreos/etcd-operator/pkg/util/constants"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil"
	"github.com/coreos/etcd-operator/test/e2e/framework"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	k8sclient "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util/wait"
)

func waitBackupPodUp(f *framework.Framework, clusterName string, timeout time.Duration) error {
	return wait.Poll(5*time.Second, timeout, func() (done bool, err error) {
		podList, err := f.KubeClient.Pods(f.Namespace.Name).List(api.ListOptions{
			LabelSelector: labels.SelectorFromSet(map[string]string{
				"app":          k8sutil.BackupPodSelectorAppField,
				"etcd_cluster": clusterName,
			})})
		if err != nil {
			return false, err
		}
		return len(podList.Items) > 0, nil
	})
}

func makeBackup(f *framework.Framework, clusterName string) error {
	ls := map[string]string{
		"app":          k8sutil.BackupPodSelectorAppField,
		"etcd_cluster": clusterName,
	}
	podList, err := f.KubeClient.Pods(f.Namespace.Name).List(api.ListOptions{
		LabelSelector: labels.SelectorFromSet(ls),
	})
	if err != nil {
		return err
	}
	if len(podList.Items) < 1 {
		return fmt.Errorf("no backup pod found")
	}

	// We are assuming pod ip is accessible from test machine.
	addr := fmt.Sprintf("%s:%d", podList.Items[0].Status.PodIP, constants.DefaultBackupPodHTTPPort)
	return cluster.RequestBackupNow(f.KubeClient.Client, addr)
}

func waitUntilSizeReached(f *framework.Framework, clusterName string, size, timeout int) ([]string, error) {
	return waitSizeReachedWithFilter(f, clusterName, size, timeout, func(*api.Pod) bool { return true })
}

func waitSizeReachedWithFilter(f *framework.Framework, clusterName string, size, timeout int, filterPod func(*api.Pod) bool) ([]string, error) {
	var names []string
	err := wait.Poll(5*time.Second, time.Duration(timeout)*time.Second, func() (done bool, err error) {
		podList, err := f.KubeClient.Pods(f.Namespace.Name).List(k8sutil.EtcdPodListOpt(clusterName))
		if err != nil {
			return false, err
		}
		names = nil
		for i := range podList.Items {
			pod := &podList.Items[i]
			if pod.Status.Phase == api.PodRunning {
				names = append(names, pod.Name)
			}
		}
		fmt.Printf("waiting size (%d), etcd pods: %v\n", size, names)
		if len(names) != size {
			return false, nil
		}
		// TODO: check etcd member membership
		return true, nil
	})
	if err != nil {
		return nil, err
	}
	return names, nil
}

func killMembers(f *framework.Framework, names ...string) error {
	for _, name := range names {
		err := f.KubeClient.Pods(f.Namespace.Name).Delete(name, api.NewDeleteOptions(0))
		if err != nil {
			return err
		}
	}
	return nil
}

func makeEtcdCluster(genName string, size int) *spec.EtcdCluster {
	return &spec.EtcdCluster{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "EtcdCluster",
			APIVersion: "coreos.com/v1",
		},
		ObjectMeta: api.ObjectMeta{
			GenerateName: genName,
		},
		Spec: spec.ClusterSpec{
			Size: size,
		},
	}
}

func etcdClusterWithBackup(ec *spec.EtcdCluster, backupPolicy *spec.BackupPolicy) *spec.EtcdCluster {
	ec.Spec.Backup = backupPolicy
	return ec
}
func etcdClusterWithVersion(ec *spec.EtcdCluster, version string) *spec.EtcdCluster {
	ec.Spec.Version = version
	return ec
}

func createEtcdCluster(f *framework.Framework, e *spec.EtcdCluster) (*spec.EtcdCluster, error) {
	b, err := json.Marshal(e)
	if err != nil {
		return nil, err
	}
	resp, err := f.KubeClient.Client.Post(
		fmt.Sprintf("%s/apis/coreos.com/v1/namespaces/%s/etcdclusters", f.MasterHost, f.Namespace.Name),
		"application/json", bytes.NewReader(b))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusCreated {
		return nil, fmt.Errorf("unexpected status: %v", resp.Status)
	}
	decoder := json.NewDecoder(resp.Body)
	res := &spec.EtcdCluster{}
	if err := decoder.Decode(res); err != nil {
		return nil, err
	}
	fmt.Printf("created etcd cluster: %v\n", res.Name)
	return res, nil
}

func updateEtcdCluster(f *framework.Framework, e *spec.EtcdCluster) (*spec.EtcdCluster, error) {
	b, err := json.Marshal(e)
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest("PUT",
		fmt.Sprintf("%s/apis/coreos.com/v1/namespaces/%s/etcdclusters/%s", f.MasterHost, f.Namespace.Name, e.Name),
		bytes.NewReader(b))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := f.KubeClient.Client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unexpected status: %v", resp.Status)
	}
	decoder := json.NewDecoder(resp.Body)
	nspec := &spec.EtcdCluster{}
	if err := decoder.Decode(nspec); err != nil {
		return nil, err
	}
	return nspec, nil
}

func deleteEtcdCluster(f *framework.Framework, name string) error {
	fmt.Printf("deleting etcd cluster: %v\n", name)
	podList, err := f.KubeClient.Pods(f.Namespace.Name).List(k8sutil.EtcdPodListOpt(name))
	if err != nil {
		return err
	}
	fmt.Println("etcd pods ======")
	for i := range podList.Items {
		pod := &podList.Items[i]
		fmt.Printf("pod (%v): status (%v)\n", pod.Name, pod.Status.Phase)
		buf := bytes.NewBuffer(nil)

		if pod.Status.Phase == api.PodFailed {
			if err := getLogs(f.KubeClient, f.Namespace.Name, pod.Name, "etcd", buf); err != nil {
				return err
			}
			fmt.Println(pod.Name, "logs ===")
			fmt.Println(buf.String())
			fmt.Println(pod.Name, "logs END ===")
		}
	}

	buf := bytes.NewBuffer(nil)
	if err := getLogs(f.KubeClient, f.Namespace.Name, "etcd-operator", "etcd-operator", buf); err != nil {
		return err
	}
	fmt.Println("etcd-operator logs ===")
	fmt.Println(buf.String())
	fmt.Println("etcd-operator logs END ===")

	req, err := http.NewRequest("DELETE",
		fmt.Sprintf("%s/apis/coreos.com/v1/namespaces/%s/etcdclusters/%s", f.MasterHost, f.Namespace.Name, name), nil)
	if err != nil {
		return err
	}
	resp, err := f.KubeClient.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected status: %v", resp.Status)
	}
	return nil
}

func getLogs(kubecli *k8sclient.Client, ns, p, c string, out io.Writer) error {
	req := kubecli.RESTClient.Get().
		Namespace(ns).
		Resource("pods").
		Name(p).
		SubResource("log").
		Param("container", c).
		Param("tailLines", "20")

	readCloser, err := req.Stream()
	if err != nil {
		return err
	}
	defer readCloser.Close()

	_, err = io.Copy(out, readCloser)
	return err
}
<|endoftext|>


<commit_before>package protos

import (
	"errors"
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/elastic/beats/libbeat/common"
	"github.com/elastic/beats/libbeat/logp"
	"github.com/elastic/beats/libbeat/publisher"
)

const (
	DefaultTransactionHashSize                 = 2 ^ 16
	DefaultTransactionExpiration time.Duration = 10 * time.Second
)

// ProtocolData interface to represent an upper
// protocol private data. Used with types like
// HttpStream, MysqlStream, etc.
type ProtocolData interface{}

type Packet struct {
	Ts      time.Time
	Tuple   common.IpPortTuple
	Payload []byte
}

var ErrInvalidPort = errors.New("port number out of range")

// Protocol Plugin Port configuration with validation on init
type PortsConfig struct {
	Ports []int
}

func (p *PortsConfig) Init(ports ...int) error {
	return p.Set(ports)
}

func (p *PortsConfig) Set(ports []int) error {
	if err := validatePorts(ports); err != nil {
		return err
	}
	p.Ports = ports
	return nil
}

func validatePorts(ports []int) error {
	for port := range ports {
		if port < 0 || port > 65535 {
			return ErrInvalidPort
		}
	}
	return nil
}

// Functions to be exported by a protocol plugin
type ProtocolPlugin interface {
	// Called to initialize the Plugin
	Init(test_mode bool, results publisher.Client) error

	// Called to return the configured ports
	GetPorts() []int
}

type TcpProtocolPlugin interface {
	ProtocolPlugin

	// Called when TCP payload data is available for parsing.
	Parse(pkt *Packet, tcptuple *common.TcpTuple,
		dir uint8, private ProtocolData) ProtocolData

	// Called when the FIN flag is seen in the TCP stream.
	ReceivedFin(tcptuple *common.TcpTuple, dir uint8,
		private ProtocolData) ProtocolData

	// Called when a packets are missing from the tcp
	// stream.
	GapInStream(tcptuple *common.TcpTuple, dir uint8, nbytes int,
		private ProtocolData) (priv ProtocolData, drop bool)

	// ConnectionTimeout returns the per stream connection timeout.
	// Return <=0 to set default tcp module transaction timeout.
	ConnectionTimeout() time.Duration
}

type UdpProtocolPlugin interface {
	ProtocolPlugin

	// ParseUdp is invoked when UDP payload data is available for parsing.
	ParseUdp(pkt *Packet)
}

// Protocol identifier.
type Protocol uint16

// Protocol constants.
const (
	UnknownProtocol Protocol = iota
	HttpProtocol
	MysqlProtocol
	RedisProtocol
	PgsqlProtocol
	ThriftProtocol
	MongodbProtocol
	DnsProtocol
	MemcacheProtocol
)

// Protocol names
var ProtocolNames = []string{
	"unknown",
	"http",
	"mysql",
	"redis",
	"pgsql",
	"thrift",
	"mongodb",
	"dns",
	"memcache",
}

func (p Protocol) String() string {
	if int(p) >= len(ProtocolNames) {
		return "impossible"
	}
	return ProtocolNames[p]
}

type Protocols interface {
	BpfFilter(with_vlans bool, with_icmp bool) string
	GetTcp(proto Protocol) TcpProtocolPlugin
	GetUdp(proto Protocol) UdpProtocolPlugin
	GetAll() map[Protocol]ProtocolPlugin
	GetAllTcp() map[Protocol]TcpProtocolPlugin
	GetAllUdp() map[Protocol]UdpProtocolPlugin
	Register(proto Protocol, plugin ProtocolPlugin)
}

// list of protocol plugins
type ProtocolsStruct struct {
	all map[Protocol]ProtocolPlugin
	tcp map[Protocol]TcpProtocolPlugin
	udp map[Protocol]UdpProtocolPlugin
}

// Singleton of Protocols type.
var Protos ProtocolsStruct

func (protocols ProtocolsStruct) GetTcp(proto Protocol) TcpProtocolPlugin {
	plugin, exists := protocols.tcp[proto]
	if !exists {
		return nil
	}

	return plugin
}

func (protocols ProtocolsStruct) GetUdp(proto Protocol) UdpProtocolPlugin {
	plugin, exists := protocols.udp[proto]
	if !exists {
		return nil
	}

	return plugin
}

func (protocols ProtocolsStruct) GetAll() map[Protocol]ProtocolPlugin {
	return protocols.all
}

func (protocols ProtocolsStruct) GetAllTcp() map[Protocol]TcpProtocolPlugin {
	return protocols.tcp
}

func (protocols ProtocolsStruct) GetAllUdp() map[Protocol]UdpProtocolPlugin {
	return protocols.udp
}

// BpfFilter returns a Berkeley Packer Filter (BFP) expression that
// will match against packets for the registered protocols. If with_vlans is
// true the filter will match against both IEEE 802.1Q VLAN encapsulated
// and unencapsulated packets
func (protocols ProtocolsStruct) BpfFilter(with_vlans bool, with_icmp bool) string {
	// Sort the protocol IDs so that the return value is consistent.
	var protos []int
	for proto := range protocols.all {
		protos = append(protos, int(proto))
	}
	sort.Ints(protos)

	var expressions []string
	for _, key := range protos {
		proto := Protocol(key)
		plugin := protocols.all[proto]
		for _, port := range plugin.GetPorts() {
			has_tcp := false
			has_udp := false

			if _, present := protocols.tcp[proto]; present {
				has_tcp = true
			}
			if _, present := protocols.udp[proto]; present {
				has_udp = true
			}

			var expr string
			if has_tcp && !has_udp {
				expr = "tcp port %d"
			} else if !has_tcp && has_udp {
				expr = "udp port %d"
			} else {
				expr = "port %d"
			}

			expressions = append(expressions, fmt.Sprintf(expr, port))
		}
	}

	filter := strings.Join(expressions, " or ")
	if with_icmp {
		filter = fmt.Sprintf("%s or icmp or icmp6", filter)
	}
	if with_vlans {
		filter = fmt.Sprintf("%s or (vlan and (%s))", filter, filter)
	}
	return filter
}

func (protos ProtocolsStruct) Register(proto Protocol, plugin ProtocolPlugin) {
	protos.all[proto] = plugin
	if tcp, ok := plugin.(TcpProtocolPlugin); ok {
		protos.tcp[proto] = tcp
	}
	if udp, ok := plugin.(UdpProtocolPlugin); ok {
		protos.udp[proto] = udp
	}
}

func init() {
	logp.Debug("protos", "Initializing Protos")
	Protos = ProtocolsStruct{}
	Protos.all = make(map[Protocol]ProtocolPlugin)
	Protos.tcp = make(map[Protocol]TcpProtocolPlugin)
	Protos.udp = make(map[Protocol]UdpProtocolPlugin)
}
<commit_msg>Logging warn message if protocol plugin is not successful registered<commit_after>package protos

import (
	"errors"
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/elastic/beats/libbeat/common"
	"github.com/elastic/beats/libbeat/logp"
	"github.com/elastic/beats/libbeat/publisher"
)

const (
	DefaultTransactionHashSize                 = 2 ^ 16
	DefaultTransactionExpiration time.Duration = 10 * time.Second
)

// ProtocolData interface to represent an upper
// protocol private data. Used with types like
// HttpStream, MysqlStream, etc.
type ProtocolData interface{}

type Packet struct {
	Ts      time.Time
	Tuple   common.IpPortTuple
	Payload []byte
}

var ErrInvalidPort = errors.New("port number out of range")

// Protocol Plugin Port configuration with validation on init
type PortsConfig struct {
	Ports []int
}

func (p *PortsConfig) Init(ports ...int) error {
	return p.Set(ports)
}

func (p *PortsConfig) Set(ports []int) error {
	if err := validatePorts(ports); err != nil {
		return err
	}
	p.Ports = ports
	return nil
}

func validatePorts(ports []int) error {
	for port := range ports {
		if port < 0 || port > 65535 {
			return ErrInvalidPort
		}
	}
	return nil
}

// Functions to be exported by a protocol plugin
type ProtocolPlugin interface {
	// Called to initialize the Plugin
	Init(test_mode bool, results publisher.Client) error

	// Called to return the configured ports
	GetPorts() []int
}

type TcpProtocolPlugin interface {
	ProtocolPlugin

	// Called when TCP payload data is available for parsing.
	Parse(pkt *Packet, tcptuple *common.TcpTuple,
		dir uint8, private ProtocolData) ProtocolData

	// Called when the FIN flag is seen in the TCP stream.
	ReceivedFin(tcptuple *common.TcpTuple, dir uint8,
		private ProtocolData) ProtocolData

	// Called when a packets are missing from the tcp
	// stream.
	GapInStream(tcptuple *common.TcpTuple, dir uint8, nbytes int,
		private ProtocolData) (priv ProtocolData, drop bool)

	// ConnectionTimeout returns the per stream connection timeout.
	// Return <=0 to set default tcp module transaction timeout.
	ConnectionTimeout() time.Duration
}

type UdpProtocolPlugin interface {
	ProtocolPlugin

	// ParseUdp is invoked when UDP payload data is available for parsing.
	ParseUdp(pkt *Packet)
}

// Protocol identifier.
type Protocol uint16

// Protocol constants.
const (
	UnknownProtocol Protocol = iota
	HttpProtocol
	MysqlProtocol
	RedisProtocol
	PgsqlProtocol
	ThriftProtocol
	MongodbProtocol
	DnsProtocol
	MemcacheProtocol
)

// Protocol names
var ProtocolNames = []string{
	"unknown",
	"http",
	"mysql",
	"redis",
	"pgsql",
	"thrift",
	"mongodb",
	"dns",
	"memcache",
}

func (p Protocol) String() string {
	if int(p) >= len(ProtocolNames) {
		return "impossible"
	}
	return ProtocolNames[p]
}

type Protocols interface {
	BpfFilter(with_vlans bool, with_icmp bool) string
	GetTcp(proto Protocol) TcpProtocolPlugin
	GetUdp(proto Protocol) UdpProtocolPlugin
	GetAll() map[Protocol]ProtocolPlugin
	GetAllTcp() map[Protocol]TcpProtocolPlugin
	GetAllUdp() map[Protocol]UdpProtocolPlugin
	Register(proto Protocol, plugin ProtocolPlugin)
}

// list of protocol plugins
type ProtocolsStruct struct {
	all map[Protocol]ProtocolPlugin
	tcp map[Protocol]TcpProtocolPlugin
	udp map[Protocol]UdpProtocolPlugin
}

// Singleton of Protocols type.
var Protos ProtocolsStruct

func (protocols ProtocolsStruct) GetTcp(proto Protocol) TcpProtocolPlugin {
	plugin, exists := protocols.tcp[proto]
	if !exists {
		return nil
	}

	return plugin
}

func (protocols ProtocolsStruct) GetUdp(proto Protocol) UdpProtocolPlugin {
	plugin, exists := protocols.udp[proto]
	if !exists {
		return nil
	}

	return plugin
}

func (protocols ProtocolsStruct) GetAll() map[Protocol]ProtocolPlugin {
	return protocols.all
}

func (protocols ProtocolsStruct) GetAllTcp() map[Protocol]TcpProtocolPlugin {
	return protocols.tcp
}

func (protocols ProtocolsStruct) GetAllUdp() map[Protocol]UdpProtocolPlugin {
	return protocols.udp
}

// BpfFilter returns a Berkeley Packer Filter (BFP) expression that
// will match against packets for the registered protocols. If with_vlans is
// true the filter will match against both IEEE 802.1Q VLAN encapsulated
// and unencapsulated packets
func (protocols ProtocolsStruct) BpfFilter(with_vlans bool, with_icmp bool) string {
	// Sort the protocol IDs so that the return value is consistent.
	var protos []int
	for proto := range protocols.all {
		protos = append(protos, int(proto))
	}
	sort.Ints(protos)

	var expressions []string
	for _, key := range protos {
		proto := Protocol(key)
		plugin := protocols.all[proto]
		for _, port := range plugin.GetPorts() {
			has_tcp := false
			has_udp := false

			if _, present := protocols.tcp[proto]; present {
				has_tcp = true
			}
			if _, present := protocols.udp[proto]; present {
				has_udp = true
			}

			var expr string
			if has_tcp && !has_udp {
				expr = "tcp port %d"
			} else if !has_tcp && has_udp {
				expr = "udp port %d"
			} else {
				expr = "port %d"
			}

			expressions = append(expressions, fmt.Sprintf(expr, port))
		}
	}

	filter := strings.Join(expressions, " or ")
	if with_icmp {
		filter = fmt.Sprintf("%s or icmp or icmp6", filter)
	}
	if with_vlans {
		filter = fmt.Sprintf("%s or (vlan and (%s))", filter, filter)
	}
	return filter
}

func (protos ProtocolsStruct) Register(proto Protocol, plugin ProtocolPlugin) {
	protos.all[proto] = plugin
	var success bool = false
	if tcp, ok := plugin.(TcpProtocolPlugin); ok {
		protos.tcp[proto] = tcp
		success = true
	}
	if udp, ok := plugin.(UdpProtocolPlugin); ok {
		protos.udp[proto] = udp
		success = true;
	}
	if(!success){
		logp.Warn("Protocol (%s) register failed, port: %v",proto.String(),plugin.GetPorts())
	}
}

func init() {
	logp.Debug("protos", "Initializing Protos")
	Protos = ProtocolsStruct{}
	Protos.all = make(map[Protocol]ProtocolPlugin)
	Protos.tcp = make(map[Protocol]TcpProtocolPlugin)
	Protos.udp = make(map[Protocol]UdpProtocolPlugin)
}
<|endoftext|>


<commit_before>package schema

import (
	"encoding/json"
	"reflect"

	"github.com/cayleygraph/cayley/query/linkedql"
	"github.com/cayleygraph/quad"
	"github.com/cayleygraph/quad/voc/rdfs"
)

var (
	pathStep = reflect.TypeOf((*linkedql.PathStep)(nil)).Elem()
	value    = reflect.TypeOf((*quad.Value)(nil)).Elem()
	operator = reflect.TypeOf((*linkedql.Operator)(nil)).Elem()
)

func typeToRange(t reflect.Type) string {
	if t.Kind() == reflect.Slice {
		return typeToRange(t.Elem())
	}
	// TODO: add XSD types to voc package
	if t.Kind() == reflect.String {
		return "xsd:string"
	}
	if t.Kind() == reflect.Bool {
		return "xsd:boolean"
	}
	if kind := t.Kind(); kind == reflect.Int64 || kind == reflect.Int {
		return "xsd:int"
	}
	if t.Implements(pathStep) {
		return linkedql.Prefix + "PathStep"
	}
	if t.Implements(operator) {
		return linkedql.Prefix + "Operator"
	}
	if t.Implements(value) {
		return rdfs.Resource
	}
	panic("Unexpected type " + t.String())
}

// identified is used for referencing a type
type identified struct {
	ID string `json:"@id"`
}

// newIdentified creates new identified struct
func newIdentified(id string) identified {
	return identified{ID: id}
}

// cardinalityRestriction is used to indicate a how many values can a property get
type cardinalityRestriction struct {
	ID          string     `json:"@id"`
	Type        string     `json:"@type"`
	Cardinality int        `json:"owl:cardinality"`
	Property    identified `json:"owl:onProperty"`
}

func newBlankNodeID() string {
	return quad.RandomBlankNode().String()
}

// newSingleCardinalityRestriction creates a cardinality of 1 restriction for given property
func newSingleCardinalityRestriction(prop string) cardinalityRestriction {
	return cardinalityRestriction{
		ID:          newBlankNodeID(),
		Type:        "owl:Restriction",
		Cardinality: 1,
		Property:    identified{ID: prop},
	}
}

// getOWLPropertyType for given kind of value type returns property OWL type
func getOWLPropertyType(kind reflect.Kind) string {
	if kind == reflect.String || kind == reflect.Bool || kind == reflect.Int64 || kind == reflect.Int {
		return "owl:DatatypeProperty"
	}
	return "owl:ObjectProperty"
}

// property is used to declare a property
type property struct {
	ID     string      `json:"@id"`
	Type   string      `json:"@type"`
	Domain interface{} `json:"rdfs:domain"`
	Range  interface{} `json:"rdfs:range"`
}

// class is used to declare a class
type class struct {
	ID           string        `json:"@id"`
	Type         string        `json:"@type"`
	Comment      string        `json:"rdfs:comment"`
	SuperClasses []interface{} `json:"rdfs:subClassOf"`
}

// newClass creates a new class struct
func newClass(id string, superClasses []interface{}, comment string) class {
	return class{
		ID:           id,
		Type:         rdfs.Class,
		SuperClasses: superClasses,
		Comment:      comment,
	}
}

// getStepTypeClass for given step type returns the matching class identifier
func getStepTypeClass(t reflect.Type) string {
	if t.Implements(pathStep) {
		return linkedql.Prefix + "PathStep"
	}
	return linkedql.Prefix + "Step"
}

type list struct {
	ID      string        `json:"@id"`
	Members []interface{} `json:"@list"`
}

func newList(members []interface{}) list {
	return list{
		ID:      newBlankNodeID(),
		Members: members,
	}
}

type unionOf struct {
	ID   string `json:"@id"`
	Type string `json:"@type"`
	List list   `json:"owl:unionOf"`
}

func newUnionOf(classes []string) unionOf {
	var members []interface{}
	for _, class := range classes {
		members = append(members, newIdentified(class))
	}
	return unionOf{
		ID:   newBlankNodeID(),
		Type: "owl:Class",
		List: newList(members),
	}
}

func newGenerator() *generator {
	return &generator{
		propToTypes:   make(map[string]map[string]struct{}),
		propToDomains: make(map[string]map[string]struct{}),
		propToRanges:  make(map[string]map[string]struct{}),
	}
}

type generator struct {
	out           []interface{}
	propToTypes   map[string]map[string]struct{}
	propToDomains map[string]map[string]struct{}
	propToRanges  map[string]map[string]struct{}
}

// returns super types
func (g *generator) addTypeFields(name string, t reflect.Type, indirect bool) []interface{} {
	var super []interface{}
	for j := 0; j < t.NumField(); j++ {
		f := t.Field(j)
		if f.Anonymous {
			if f.Type.Kind() != reflect.Struct || !indirect {
				continue
			}
			super = append(super, g.addTypeFields(name, f.Type, false)...)
			continue
		}
		prop := linkedql.Prefix + f.Tag.Get("json")
		if f.Type.Kind() != reflect.Slice {
			super = append(super, newSingleCardinalityRestriction(prop))
		}
		typ := getOWLPropertyType(f.Type.Kind())

		if g.propToTypes[prop] == nil {
			g.propToTypes[prop] = make(map[string]struct{})
		}
		g.propToTypes[prop][typ] = struct{}{}

		if g.propToDomains[prop] == nil {
			g.propToDomains[prop] = make(map[string]struct{})
		}
		g.propToDomains[prop][name] = struct{}{}

		if g.propToRanges[prop] == nil {
			g.propToRanges[prop] = make(map[string]struct{})
		}
		g.propToRanges[prop][typeToRange(f.Type)] = struct{}{}
	}
	return super
}

func (g *generator) AddType(name string, t reflect.Type) {
	step, ok := reflect.New(t).Interface().(linkedql.Step)
	if !ok {
		return
	}
	super := []interface{}{
		newIdentified(getStepTypeClass(pathStep)),
	}
	super = append(super, g.addTypeFields(name, t, true)...)
	g.out = append(g.out, newClass(name, super, step.Description()))
}

func (g *generator) Generate() []byte {
	for prop, types := range g.propToTypes {
		if len(types) != 1 {
			panic("Properties must be either object properties or datatype properties. " + prop + " has both.")
		}
		var typ string
		for t := range types {
			typ = t
			break
		}
		var domains []string
		for d := range g.propToDomains[prop] {
			domains = append(domains, d)
		}
		var ranges []string
		for r := range g.propToRanges[prop] {
			ranges = append(ranges, r)
		}
		var dom interface{}
		if len(domains) == 1 {
			dom = domains[0]
		} else {
			dom = newUnionOf(domains)
		}
		var rng interface{}
		if len(ranges) == 1 {
			rng = ranges[0]
		} else {
			rng = newUnionOf(ranges)
		}
		g.out = append(g.out, property{
			ID:     prop,
			Type:   typ,
			Domain: dom,
			Range:  rng,
		})
	}
	data, err := json.Marshal(g.out)
	if err != nil {
		panic(err)
	}
	return data
}

// Generate a schema in JSON-LD format that contains all registered LinkedQL types and properties.
func Generate() []byte {
	g := newGenerator()
	for _, name := range linkedql.RegisteredTypes() {
		t, ok := linkedql.TypeByName(name)
		if !ok {
			panic("type is registered, but the lookup fails")
		}
		g.AddType(name, t)
	}
	return g.Generate()
}
<commit_msg>linkedql: Correct schema single range json output<commit_after>package schema

import (
	"encoding/json"
	"reflect"

	"github.com/cayleygraph/cayley/query/linkedql"
	"github.com/cayleygraph/quad"
	"github.com/cayleygraph/quad/voc/rdfs"
)

var (
	pathStep = reflect.TypeOf((*linkedql.PathStep)(nil)).Elem()
	value    = reflect.TypeOf((*quad.Value)(nil)).Elem()
	operator = reflect.TypeOf((*linkedql.Operator)(nil)).Elem()
)

func typeToRange(t reflect.Type) string {
	if t.Kind() == reflect.Slice {
		return typeToRange(t.Elem())
	}
	// TODO: add XSD types to voc package
	if t.Kind() == reflect.String {
		return "xsd:string"
	}
	if t.Kind() == reflect.Bool {
		return "xsd:boolean"
	}
	if kind := t.Kind(); kind == reflect.Int64 || kind == reflect.Int {
		return "xsd:int"
	}
	if t.Implements(pathStep) {
		return linkedql.Prefix + "PathStep"
	}
	if t.Implements(operator) {
		return linkedql.Prefix + "Operator"
	}
	if t.Implements(value) {
		return rdfs.Resource
	}
	panic("Unexpected type " + t.String())
}

// identified is used for referencing a type
type identified struct {
	ID string `json:"@id"`
}

// newIdentified creates new identified struct
func newIdentified(id string) identified {
	return identified{ID: id}
}

// cardinalityRestriction is used to indicate a how many values can a property get
type cardinalityRestriction struct {
	ID          string     `json:"@id"`
	Type        string     `json:"@type"`
	Cardinality int        `json:"owl:cardinality"`
	Property    identified `json:"owl:onProperty"`
}

func newBlankNodeID() string {
	return quad.RandomBlankNode().String()
}

// newSingleCardinalityRestriction creates a cardinality of 1 restriction for given property
func newSingleCardinalityRestriction(prop string) cardinalityRestriction {
	return cardinalityRestriction{
		ID:          newBlankNodeID(),
		Type:        "owl:Restriction",
		Cardinality: 1,
		Property:    identified{ID: prop},
	}
}

// getOWLPropertyType for given kind of value type returns property OWL type
func getOWLPropertyType(kind reflect.Kind) string {
	if kind == reflect.String || kind == reflect.Bool || kind == reflect.Int64 || kind == reflect.Int {
		return "owl:DatatypeProperty"
	}
	return "owl:ObjectProperty"
}

// property is used to declare a property
type property struct {
	ID     string      `json:"@id"`
	Type   string      `json:"@type"`
	Domain interface{} `json:"rdfs:domain"`
	Range  interface{} `json:"rdfs:range"`
}

// class is used to declare a class
type class struct {
	ID           string        `json:"@id"`
	Type         string        `json:"@type"`
	Comment      string        `json:"rdfs:comment"`
	SuperClasses []interface{} `json:"rdfs:subClassOf"`
}

// newClass creates a new class struct
func newClass(id string, superClasses []interface{}, comment string) class {
	return class{
		ID:           id,
		Type:         rdfs.Class,
		SuperClasses: superClasses,
		Comment:      comment,
	}
}

// getStepTypeClass for given step type returns the matching class identifier
func getStepTypeClass(t reflect.Type) string {
	if t.Implements(pathStep) {
		return linkedql.Prefix + "PathStep"
	}
	return linkedql.Prefix + "Step"
}

type list struct {
	ID      string        `json:"@id"`
	Members []interface{} `json:"@list"`
}

func newList(members []interface{}) list {
	return list{
		ID:      newBlankNodeID(),
		Members: members,
	}
}

type unionOf struct {
	ID   string `json:"@id"`
	Type string `json:"@type"`
	List list   `json:"owl:unionOf"`
}

func newUnionOf(classes []string) unionOf {
	var members []interface{}
	for _, class := range classes {
		members = append(members, newIdentified(class))
	}
	return unionOf{
		ID:   newBlankNodeID(),
		Type: "owl:Class",
		List: newList(members),
	}
}

func newGenerator() *generator {
	return &generator{
		propToTypes:   make(map[string]map[string]struct{}),
		propToDomains: make(map[string]map[string]struct{}),
		propToRanges:  make(map[string]map[string]struct{}),
	}
}

type generator struct {
	out           []interface{}
	propToTypes   map[string]map[string]struct{}
	propToDomains map[string]map[string]struct{}
	propToRanges  map[string]map[string]struct{}
}

// returns super types
func (g *generator) addTypeFields(name string, t reflect.Type, indirect bool) []interface{} {
	var super []interface{}
	for j := 0; j < t.NumField(); j++ {
		f := t.Field(j)
		if f.Anonymous {
			if f.Type.Kind() != reflect.Struct || !indirect {
				continue
			}
			super = append(super, g.addTypeFields(name, f.Type, false)...)
			continue
		}
		prop := linkedql.Prefix + f.Tag.Get("json")
		if f.Type.Kind() != reflect.Slice {
			super = append(super, newSingleCardinalityRestriction(prop))
		}
		typ := getOWLPropertyType(f.Type.Kind())

		if g.propToTypes[prop] == nil {
			g.propToTypes[prop] = make(map[string]struct{})
		}
		g.propToTypes[prop][typ] = struct{}{}

		if g.propToDomains[prop] == nil {
			g.propToDomains[prop] = make(map[string]struct{})
		}
		g.propToDomains[prop][name] = struct{}{}

		if g.propToRanges[prop] == nil {
			g.propToRanges[prop] = make(map[string]struct{})
		}
		g.propToRanges[prop][typeToRange(f.Type)] = struct{}{}
	}
	return super
}

func (g *generator) AddType(name string, t reflect.Type) {
	step, ok := reflect.New(t).Interface().(linkedql.Step)
	if !ok {
		return
	}
	super := []interface{}{
		newIdentified(getStepTypeClass(pathStep)),
	}
	super = append(super, g.addTypeFields(name, t, true)...)
	g.out = append(g.out, newClass(name, super, step.Description()))
}

func (g *generator) Generate() []byte {
	for prop, types := range g.propToTypes {
		if len(types) != 1 {
			panic("Properties must be either object properties or datatype properties. " + prop + " has both.")
		}
		var typ string
		for t := range types {
			typ = t
			break
		}
		var domains []string
		for d := range g.propToDomains[prop] {
			domains = append(domains, d)
		}
		var ranges []string
		for r := range g.propToRanges[prop] {
			ranges = append(ranges, r)
		}
		var dom interface{}
		if len(domains) == 1 {
			dom = domains[0]
		} else {
			dom = newUnionOf(domains)
		}
		var rng interface{}
		if len(ranges) == 1 {
			rng = newIdentified(ranges[0])
		} else {
			rng = newUnionOf(ranges)
		}
		g.out = append(g.out, property{
			ID:     prop,
			Type:   typ,
			Domain: dom,
			Range:  rng,
		})
	}
	data, err := json.Marshal(g.out)
	if err != nil {
		panic(err)
	}
	return data
}

// Generate a schema in JSON-LD format that contains all registered LinkedQL types and properties.
func Generate() []byte {
	g := newGenerator()
	for _, name := range linkedql.RegisteredTypes() {
		t, ok := linkedql.TypeByName(name)
		if !ok {
			panic("type is registered, but the lookup fails")
		}
		g.AddType(name, t)
	}
	return g.Generate()
}
<|endoftext|>


<commit_before>// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: MustParse("0.0.1"),
	Series: readSeries("/etc/lsb-release"), // current Ubuntu release name.
	Arch:   ubuntuArch(runtime.GOARCH),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current = MustParseBinary(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or any of the
// other numbers are odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered major, minor
// or patch version is considered to be a development version.
func (v Number) IsDev() bool {
	return isOdd(v.Major) || isOdd(v.Minor) || isOdd(v.Patch) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<commit_msg>version: bump version<commit_after>// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: MustParse("0.0.2"),
	Series: readSeries("/etc/lsb-release"), // current Ubuntu release name.
	Arch:   ubuntuArch(runtime.GOARCH),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current = MustParseBinary(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or any of the
// other numbers are odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered major, minor
// or patch version is considered to be a development version.
func (v Number) IsDev() bool {
	return isOdd(v.Major) || isOdd(v.Minor) || isOdd(v.Patch) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<|endoftext|>


<commit_before>// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT

// Eris-RT is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Eris-RT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.

// version provides the current Eris-DB version and a VersionIdentifier
// for the modules to identify their version with.

package version

import (
	"fmt"
)

// IMPORTANT: this version number needs to be manually kept
// in sync at the bottom of this file for the deployment scripts to parse
// the version number.
const (
	// Client identifier to advertise over the network
	erisClientIdentifier = "eris-db"
	// Major version component of the current release
	erisVersionMajor = 0
	// Minor version component of the current release
	erisVersionMinor = 12
	// Patch version component of the current release
	erisVersionPatch = 0
)

var erisVersion *VersionIdentifier

func init() {
	erisVersion = New(erisClientIdentifier, erisVersionMajor,
		erisVersionMinor, erisVersionPatch)
}

//------------------------------------------------------------------------------
// versioning globally for Eris-DB and scoped for modules

type VersionIdentifier struct {
	clientIdentifier string
	versionMajor     uint8
	versionMinor     uint8
	versionPatch     uint8
}

func New(client string, major, minor, patch uint8) *VersionIdentifier {
	v := new(VersionIdentifier)
	v.clientIdentifier = client
	v.versionMajor = major
	v.versionMinor = minor
	v.versionPatch = patch
	return v
}

// GetVersionString returns `client-major.minor.patch` for Eris-DB
// without a receiver, or for the version called on.
// MakeVersionString builds the same version string with provided parameters.
func GetVersionString() string { return erisVersion.GetVersionString() }
func (v *VersionIdentifier) GetVersionString() string {
	return fmt.Sprintf("%s-%d.%d.%d", v.clientIdentifier, v.versionMajor,
		v.versionMinor, v.versionPatch)
}

// note: the arguments are passed in as int (rather than uint8)
// because on asserting the version constructed from the configuration file
// the casting of an int to uint8 is uglier than expanding the type range here.
// Should the configuration file have an invalid integer (that could not convert)
// then this will equally be reflected in a failed assertion of the version string.
func MakeVersionString(client string, major, minor, patch int) string {
	return fmt.Sprintf("%s-%d.%d.%d", client, major, minor, patch)
}

// GetMinorVersionString returns `client-major.minor` for Eris-DB
// without a receiver, or for the version called on.
// MakeMinorVersionString builds the same version string with
// provided parameters.
func GetMinorVersionString() string { return erisVersion.GetVersionString() }
func (v *VersionIdentifier) GetMinorVersionString() string {
	return fmt.Sprintf("%s-%d.%d", v.clientIdentifier, v.versionMajor,
		v.versionMinor)
}

// note: similar remark applies here on the use of `int` over `uint8`
// for the arguments as above for MakeVersionString()
func MakeMinorVersionString(client string, major, minor, patch int) string {
	return fmt.Sprintf("%s-%d.%d", client, major, minor)
}

// GetVersion returns a tuple of client, major, minor, and patch as types,
// either for Eris-DB without a receiver or the called version structure.
func GetVersion() (client string, major, minor, patch uint8) {
	return erisVersion.GetVersion()
}
func (version *VersionIdentifier) GetVersion() (
	client string, major, minor, patch uint8) {
	return version.clientIdentifier, version.versionMajor, version.versionMinor,
		version.versionPatch
}

//------------------------------------------------------------------------------
// Matching functions

// MatchesMinorVersion matches the client identifier, major and minor version
// number of the reference version identifier to be equal with the receivers.
func MatchesMinorVersion(referenceVersion *VersionIdentifier) bool {
	return erisVersion.MatchesMinorVersion(referenceVersion)
}
func (version *VersionIdentifier) MatchesMinorVersion(
	referenceVersion *VersionIdentifier) bool {
	referenceClient, referenceMajor, referenceMinor, _ := referenceVersion.GetVersion()
	return version.clientIdentifier == referenceClient &&
		version.versionMajor == referenceMajor &&
		version.versionMinor == referenceMinor
}

//------------------------------------------------------------------------------
// Version number for tests/build_tool.sh

// IMPORTANT: Eris-DB version must be on the last line of this file for
// the deployment script tests/build_tool.sh to pick up the right label.
const VERSION = "0.12.0"
<commit_msg>version: bump to v0.16.0<commit_after>// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT

// Eris-RT is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Eris-RT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.

// version provides the current Eris-DB version and a VersionIdentifier
// for the modules to identify their version with.

package version

import (
	"fmt"
)

// IMPORTANT: this version number needs to be manually kept
// in sync at the bottom of this file for the deployment scripts to parse
// the version number.
const (
	// Client identifier to advertise over the network
	erisClientIdentifier = "eris-db"
	// Major version component of the current release
	erisVersionMajor = 0
	// Minor version component of the current release
	erisVersionMinor = 12
	// Patch version component of the current release
	erisVersionPatch = 0
)

var erisVersion *VersionIdentifier

func init() {
	erisVersion = New(erisClientIdentifier, erisVersionMajor,
		erisVersionMinor, erisVersionPatch)
}

//------------------------------------------------------------------------------
// versioning globally for Eris-DB and scoped for modules

type VersionIdentifier struct {
	clientIdentifier string
	versionMajor     uint8
	versionMinor     uint8
	versionPatch     uint8
}

func New(client string, major, minor, patch uint8) *VersionIdentifier {
	v := new(VersionIdentifier)
	v.clientIdentifier = client
	v.versionMajor = major
	v.versionMinor = minor
	v.versionPatch = patch
	return v
}

// GetVersionString returns `client-major.minor.patch` for Eris-DB
// without a receiver, or for the version called on.
// MakeVersionString builds the same version string with provided parameters.
func GetVersionString() string { return erisVersion.GetVersionString() }
func (v *VersionIdentifier) GetVersionString() string {
	return fmt.Sprintf("%s-%d.%d.%d", v.clientIdentifier, v.versionMajor,
		v.versionMinor, v.versionPatch)
}

// note: the arguments are passed in as int (rather than uint8)
// because on asserting the version constructed from the configuration file
// the casting of an int to uint8 is uglier than expanding the type range here.
// Should the configuration file have an invalid integer (that could not convert)
// then this will equally be reflected in a failed assertion of the version string.
func MakeVersionString(client string, major, minor, patch int) string {
	return fmt.Sprintf("%s-%d.%d.%d", client, major, minor, patch)
}

// GetMinorVersionString returns `client-major.minor` for Eris-DB
// without a receiver, or for the version called on.
// MakeMinorVersionString builds the same version string with
// provided parameters.
func GetMinorVersionString() string { return erisVersion.GetVersionString() }
func (v *VersionIdentifier) GetMinorVersionString() string {
	return fmt.Sprintf("%s-%d.%d", v.clientIdentifier, v.versionMajor,
		v.versionMinor)
}

// note: similar remark applies here on the use of `int` over `uint8`
// for the arguments as above for MakeVersionString()
func MakeMinorVersionString(client string, major, minor, patch int) string {
	return fmt.Sprintf("%s-%d.%d", client, major, minor)
}

// GetVersion returns a tuple of client, major, minor, and patch as types,
// either for Eris-DB without a receiver or the called version structure.
func GetVersion() (client string, major, minor, patch uint8) {
	return erisVersion.GetVersion()
}
func (version *VersionIdentifier) GetVersion() (
	client string, major, minor, patch uint8) {
	return version.clientIdentifier, version.versionMajor, version.versionMinor,
		version.versionPatch
}

//------------------------------------------------------------------------------
// Matching functions

// MatchesMinorVersion matches the client identifier, major and minor version
// number of the reference version identifier to be equal with the receivers.
func MatchesMinorVersion(referenceVersion *VersionIdentifier) bool {
	return erisVersion.MatchesMinorVersion(referenceVersion)
}
func (version *VersionIdentifier) MatchesMinorVersion(
	referenceVersion *VersionIdentifier) bool {
	referenceClient, referenceMajor, referenceMinor, _ := referenceVersion.GetVersion()
	return version.clientIdentifier == referenceClient &&
		version.versionMajor == referenceMajor &&
		version.versionMinor == referenceMinor
}

//------------------------------------------------------------------------------
// Version number for tests/build_tool.sh

// IMPORTANT: Eris-DB version must be on the last line of this file for
// the deployment script tests/build_tool.sh to pick up the right label.
const VERSION = "0.16.0"
<|endoftext|>


<commit_before>package version

import "fmt"

var (
	// Version return version no
	Version = "0.0.14"
	// GitCommit return Git commit
	GitCommit = "HEAD"
)

// FullVersion return full version string
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<commit_msg>Bump to v0.0.15<commit_after>package version

import "fmt"

var (
	// Version return version no
	Version = "0.0.15"
	// GitCommit return Git commit
	GitCommit = "HEAD"
)

// FullVersion return full version string
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 4
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 4

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>Bump to v5.5.0-dev again<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 5
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>// Copyright 2014 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

import (
	"github.com/coreos/fleet/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
)

const Version = "0.9.2+git"

var SemVersion semver.Version

func init() {
	sv, err := semver.NewVersion(Version)
	if err != nil {
		panic("bad version string!")
	}
	SemVersion = *sv
}
<commit_msg>version: bump to v0.10.0<commit_after>// Copyright 2014 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

import (
	"github.com/coreos/fleet/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
)

const Version = "0.10.0"

var SemVersion semver.Version

func init() {
	sv, err := semver.NewVersion(Version)
	if err != nil {
		panic("bad version string!")
	}
	SemVersion = *sv
}
<|endoftext|>


<commit_before>package version

const (
	// Version is the current File Browser version.
	Version = "(untracked)"
)
<commit_msg>chore: version v2.0.7<commit_after>package version

const (
	// Version is the current File Browser version.
	Version = "v2.0.7"
)
<|endoftext|>


<commit_before>// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.9.1"

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: MustParse(version),
	Series: readSeries("/etc/lsb-release"), // current Ubuntu release name.
	Arch:   ubuntuArch(runtime.GOARCH),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current = MustParseBinary(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or any of the
// other numbers are odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered major, minor
// or patch version is considered to be a development version.
func (v Number) IsDev() bool {
	return isOdd(v.Major) || isOdd(v.Minor) || isOdd(v.Patch) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<commit_msg>set dev version to 1.9.2<commit_after>// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.9.2"

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: MustParse(version),
	Series: readSeries("/etc/lsb-release"), // current Ubuntu release name.
	Arch:   ubuntuArch(runtime.GOARCH),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current = MustParseBinary(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or any of the
// other numbers are odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered major, minor
// or patch version is considered to be a development version.
func (v Number) IsDev() bool {
	return isOdd(v.Major) || isOdd(v.Minor) || isOdd(v.Patch) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<|endoftext|>


<commit_before>package version

var (
	// The full version string
	Version = "0.4.3"
	// GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse HEAD)"
	GitCommit string
)

func init() {
	if GitCommit != "" {
		Version += "-" + GitCommit[:8]
	}
}
<commit_msg>update verion<commit_after>package version

var (
	// The full version string
	Version = "0.4.4"
	// GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse HEAD)"
	GitCommit string
)

func init() {
	if GitCommit != "" {
		Version += "-" + GitCommit[:8]
	}
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"socialapi/models"
	"socialapi/workers/common/tests"
	"testing"

	"github.com/koding/runner"
)

var (
	ErrEmptyPath       = errors.New("path is empty")
	ErrEmptyValueFound = errors.New("either KeyId or SecretId is not found")
)

func TestStoreCredentials(t *testing.T) {
	tests.WithRunner(t, func(r *runner.Runner) {
		Convey("While storing credentials", t, func() {
			ownerAccount, groupChannel, groupName := models.CreateRandomGroupDataWithChecks()

			ownerSes, err := models.FetchOrCreateSession(ownerAccount.Nick, groupName)
			So(err, ShouldBeNil)
			So(ownerSes, ShouldNotBeNil)

			Convey("ENV variables and necessary fields should be set", func() {
				So(os.Getenv("AWS_REGION"), ShouldNotBeNil)
			})
			Convey("storing should be successful", func() {
				c := &Credentials{
					KeyId:    "test-keyId",
					SecretId: "test-secretId",
				}

				byt, err := json.Marshal(c)
				if err != nil {
					fmt.Println("ERR-Marhal", err)
				}

				aa := bytes.NewReader(byt)

				So(uploadHandler("pathName", aa), ShoulBeNil)
			})

		})
	})
}

// Actually, this is not a handler function
// Aim of this function is controlling the credentials if there exists or not
func uploadHandler(path string, r io.Reader) error {
	if path == "" {
		return ErrEmptyPath
	}

	plaintext, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	x := &Credentials{}

	downx := bytes.NewReader(plaintext)
	if err := json.NewDecoder(downx).Decode(x); err != nil {
		return err
	}

	if x.KeyId == "" || x.SecretId == "" {
		return ErrEmptyValueFound
	}

}
<commit_msg>tests: add tests for credential upload and download<commit_after>package api

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

var (
	ErrEmptyPath       = errors.New("path is empty")
	ErrEmptyValueFound = errors.New("either Name or Key is not found")
)

// CR struct is created for testing dowload from S3
type CR struct {
	Name string
	Key  string
}

func TestStoreCredentials(t *testing.T) {
	Convey("While storing credentials", t, func() {
		// Convey("ENV variables and necessary fields should be set", func() {
		// 	So(os.Getenv("AWS_REGION"), ShouldNotBeNil)
		// })
		Convey("storing should be successful", func() {
			c := &CR{
				Name: "test-Name",
				Key:  "test-Key",
			}

			byt, err := json.Marshal(c)
			if err != nil {
				fmt.Println("ERR-Marhal", err)
			}

			aa := bytes.NewReader(byt)

			So(uploadHandler("pathName", aa), ShouldBeNil)
		})

	})
}

func TestDownloadCredentials(t *testing.T) {
	Convey("While downloading credentials", t, func() {
		Convey("download should be done successfully", func() {
			pathName := "mehmetali"
			b, err := downloadHandler(pathName)
			So(err, ShouldBeNil)
			So(b, ShouldNotBeNil)
			c := &CR{}

			byt := bytes.NewReader(b[pathName])

			err = json.NewDecoder(byt).Decode(c)
			So(err, ShouldBeNil)
			So(c, ShouldNotBeNil)
		})

	})
}

// Actually, this is not a handler function
// Aim of this function is controlling the credentials if there exists or not
func uploadHandler(path string, r io.Reader) error {
	if path == "" {
		return ErrEmptyPath
	}

	plaintext, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	x := &CR{}

	downx := bytes.NewReader(plaintext)
	if err := json.NewDecoder(downx).Decode(x); err != nil {
		return err
	}

	if x.Name == "" || x.Key == "" {
		return ErrEmptyValueFound
	}

	return nil
}

// downloadHandler gives us data created by us before.
// its same with the download from S3 ideally.
func downloadHandler(path string) (map[string][]byte, error) {
	if path == "" {
		return nil, ErrEmptyPath
	}

	pathDownload := make(map[string][]byte, 0)
	pathDownload["mehmetali"] = []byte{123, 34, 78, 97, 109, 101, 34, 58, 34, 109, 101, 104, 109, 101, 116, 97, 108, 105, 115, 97, 118, 97, 115, 34, 44, 34, 75, 101, 121, 34, 58, 34, 97, 103, 57, 56, 52, 119, 115, 104, 118, 105, 97, 115, 118, 57, 121, 55, 121, 101, 118, 111, 121, 79, 92, 117, 48, 48, 50, 54, 65, 89, 102, 92, 117, 48, 48, 50, 54, 89, 70, 86, 79, 89, 101, 111, 118, 111, 102, 101, 34, 125}

	return pathDownload, nil
}
<|endoftext|>