Example #1
0
func TestDo(t *testing.T) {
	db := setUpDatabase(t)
	defer tearDownDatabase(db, t)

	localCred := testCred

	// Wrong host
	_, err := couch.Do("http://127.0.0.1:598/couch_test_go/_compact", "POST", localCred, nil, nil)
	if err == nil {
		t.Fatal("Wrong host should return error")
	}

	// Wrong db name
	_, err = couch.Do("http://127.0.0.1:5984/couch_WRONG_go/_compact", "POST", localCred, nil, nil)
	if err == nil {
		t.Fatal("Wrong db name should return error")
	}

	// Wrong API
	_, err = couch.Do("http://127.0.0.1:5984/couch_test_go/_coooompact", "POST", localCred, nil, nil)
	if err == nil {
		t.Fatal("Wrong API call should return error")
	}

	// Anything
	_, err = couch.Do("http://127.0.0.1:5984/couch_test_go/_compact", "POST", localCred, nil, nil)
	if err != nil {
		t.Fatal(err)
	}
}
Example #2
0
// check if couchdb server is online, if not it will wait for max retries
// @param server - couch.Server - couchdb server to check
// @param max_retries - int - how many times we should try connect to server
// @param wait_time - int - how long wait for next check (in milisec)
func CheckServer(server *couch.Server, max_retries int, wait_time int) error {
	// set max retires
	retries := max_retries
	// test server, "infinite" loop
	for {
		// send request to server
		_, err := couch.Do(server.URL(), "GET", server.Cred(), nil, nil)
		//server is OK,
		if err == nil {
			// connection successful, return nil
			return nil
		} else if retries <= 0 {
			// we reached max retry attempts, end with error
			return errors.New("couchdb_cntrol: check server: cannot connect to server " + server.URL() + ", attempts: " + strconv.Itoa(max_retries))
		} else {
			// server is not responding, try again after a while
			time.Sleep(time.Millisecond * time.Duration(wait_time))
		}
		// reduce retry count
		retries--
	}
}
Example #3
0
// setup continuous replication between all pods in couchdb cluster
// first it will cancel any replication for all pods
// then it will reinit circle continuous replication between all pods
// requirement -> replicas > 1 !!
// @param cluster - CouchdbCluster struct - cluster where setup replication
func (cluster *CouchdbCluster) SetupReplication(databases []string) error {
	DebugLog("couchdb_control: setup: _replication: Replication setup for all PODS, dbs to replicate:")
	DebugLog(databases)
	// check fi all pods are ready and in running state
	err := cluster.CheckAllCouchdbPods()
	if err != nil {
		ErrorLog("couchdb_control: setup_replication: check all pods error")
		return err
	}
	// create couchdb admin credentials
	credentials := couch.NewCredentials(cluster.Username, cluster.Password)
	// get all pods
	podSvcList, err := cluster.GetAllPodServices()
	if err != nil {
		ErrorLog("couchdb_control: setup_replication: check all pods error")
		return err
	}
	podSvcs := *podSvcList
	DebugLog("couchdb_control: setup_replication: interate throught all pod services")
	// iterate through all pods
	for i := 0; i < len(podSvcs); i++ {
		// index of next pod
		j := (i + 1) % len(podSvcs)
		DebugLog("couchdb_control: setup replication: pod: " + podSvcs[i].Name + "," + podSvcs[i].Spec.ClusterIP)

		// primary - replicate FROM
		server1 := couch.NewServer("http://"+podSvcs[i].Spec.ClusterIP+":"+COUCHDB_PORT_STRING, credentials)
		// check server1
		if err := CheckServer(server1, MAX_RETRIES, RETRY_WAIT_TIME); err != nil {
			// failed to connect to server after all retries, fail replication
			ErrorLog("couchdb_control: setupReplication: failed to connect to server1, pod:" + podSvcs[i].Name)
			ErrorLog(err)
			return err
		}
		// secondary - replicate TO
		server2 := couch.NewServer("http://"+podSvcs[j].Spec.ClusterIP+":"+COUCHDB_PORT_STRING, credentials)
		if err := CheckServer(server2, MAX_RETRIES, RETRY_WAIT_TIME); err != nil {
			// failed to connect to server after all retries, fail replication
			ErrorLog("couchdb_control: setupReplication: failed to connect to server2, pod:" + podSvcs[j].Name)
			ErrorLog(err)
			return err
		}

		// set replication between two pods for all listed databases
		for _, db := range databases {
			// db1 server1
			db1 := server1.Database(db)
			db1.Create()
			// db1  server2
			db2 := server2.Database(db)
			db2.Create()

			// REPLICATION CHOOSE ONLY ONE
			// 1) using _replicate
			// 2) using _replicator

			// replication struct, use headless service name for replication target
			replicator := CouchdbReplicator{Id: "replicate_" + db,
				Continuous: true, Source: db1.URL(),
				Target: "http://" + cluster.Username + ":" + cluster.Password + "@" + podSvcs[j].Spec.ClusterIP + ":" + COUCHDB_PORT_STRING + "/" + db}

			// 1)
			// continuous replication , saves to "_replicate"
			// limits:  anything in _replication is lost when db is restarted

			// DELETE old replication, if any found
			// cannot by done without saving information or without server restart
			// restart server1 and wait until its online, should be fast
			//couch.Do(server1.URL()+"/_restart", METHOD_POST, server1.Cred(), nil, nil)
			//CheckServer(server1, MAX_RETRIES, RETRY_WAIT_TIME)
			// setup replication
			//couch.Do(server1.URL()+"/_replicate", METHOD_POST, server1.Cred(), &replicator, nil)

			// 2)
			// continuous replication via "_replicator"
			// this replication survive restarts but fails replicate database "_users"

			if db == "_users" {
				// there is a bug with _replicator and db _users, we cannot replicate this DB
				continue
			}
			// delete old replication, if any found
			// get old replicator record
			oldReplicator := CouchdbReplicator{}
			couch.Do(server1.URL()+"/_replicator/"+"replicate_"+db, METHOD_GET, server1.Cred(), nil, &oldReplicator)
			//DebugLog(oldReplicator.Rev)
			// if valid replicator record found, delete it
			if oldReplicator.Rev != "" {
				server1.Database("_replicator").Delete("replicate_"+db, oldReplicator.Rev)
			}

			// setup new replication in _replicator db
			couch.Do(server1.URL()+"/_replicator", METHOD_POST, server1.Cred(), &replicator, nil)
		}
	}
	//DebugLog("finished replication configuration")

	// no errors
	return nil
}