github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/cmd/networkdb-test/dbclient/ndbClient.go (about)

     1  package dbclient
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"net"
     9  	"net/http"
    10  	"os"
    11  	"regexp"
    12  	"strconv"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/sirupsen/logrus"
    17  )
    18  
    19  var servicePort string
    20  
    21  const totalWrittenKeys string = "totalKeys"
    22  
    23  type resultTuple struct {
    24  	id     string
    25  	result int
    26  }
    27  
    28  func httpGetFatalError(ip, port, path string) {
    29  	body, err := httpGet(ip, port, path)
    30  	if err != nil || !strings.Contains(string(body), "OK") {
    31  		log.Fatalf("[%s] error %s %s", path, err, body)
    32  	}
    33  }
    34  
    35  func httpGet(ip, port, path string) ([]byte, error) {
    36  	resp, err := http.Get("http://" + ip + ":" + port + path)
    37  	if err != nil {
    38  		logrus.Errorf("httpGet error:%s", err)
    39  		return nil, err
    40  	}
    41  	defer resp.Body.Close()
    42  	body, err := io.ReadAll(resp.Body)
    43  	return body, err
    44  }
    45  
    46  func joinCluster(ip, port string, members []string, doneCh chan resultTuple) {
    47  	httpGetFatalError(ip, port, "/join?members="+strings.Join(members, ","))
    48  
    49  	if doneCh != nil {
    50  		doneCh <- resultTuple{id: ip, result: 0}
    51  	}
    52  }
    53  
    54  func joinNetwork(ip, port, network string, doneCh chan resultTuple) {
    55  	httpGetFatalError(ip, port, "/joinnetwork?nid="+network)
    56  
    57  	if doneCh != nil {
    58  		doneCh <- resultTuple{id: ip, result: 0}
    59  	}
    60  }
    61  
    62  func leaveNetwork(ip, port, network string, doneCh chan resultTuple) {
    63  	httpGetFatalError(ip, port, "/leavenetwork?nid="+network)
    64  
    65  	if doneCh != nil {
    66  		doneCh <- resultTuple{id: ip, result: 0}
    67  	}
    68  }
    69  
    70  func writeTableKey(ip, port, networkName, tableName, key string) {
    71  	createPath := "/createentry?unsafe&nid=" + networkName + "&tname=" + tableName + "&value=v&key="
    72  	httpGetFatalError(ip, port, createPath+key)
    73  }
    74  
    75  func deleteTableKey(ip, port, networkName, tableName, key string) {
    76  	deletePath := "/deleteentry?nid=" + networkName + "&tname=" + tableName + "&key="
    77  	httpGetFatalError(ip, port, deletePath+key)
    78  }
    79  
    80  func clusterPeersNumber(ip, port string, doneCh chan resultTuple) {
    81  	body, err := httpGet(ip, port, "/clusterpeers")
    82  
    83  	if err != nil {
    84  		logrus.Errorf("clusterPeers %s there was an error: %s", ip, err)
    85  		doneCh <- resultTuple{id: ip, result: -1}
    86  		return
    87  	}
    88  	peersRegexp := regexp.MustCompile(`total entries: ([0-9]+)`)
    89  	peersNum, _ := strconv.Atoi(peersRegexp.FindStringSubmatch(string(body))[1])
    90  
    91  	doneCh <- resultTuple{id: ip, result: peersNum}
    92  }
    93  
    94  func networkPeersNumber(ip, port, networkName string, doneCh chan resultTuple) {
    95  	body, err := httpGet(ip, port, "/networkpeers?nid="+networkName)
    96  
    97  	if err != nil {
    98  		logrus.Errorf("networkPeersNumber %s there was an error: %s", ip, err)
    99  		doneCh <- resultTuple{id: ip, result: -1}
   100  		return
   101  	}
   102  	peersRegexp := regexp.MustCompile(`total entries: ([0-9]+)`)
   103  	peersNum, _ := strconv.Atoi(peersRegexp.FindStringSubmatch(string(body))[1])
   104  
   105  	doneCh <- resultTuple{id: ip, result: peersNum}
   106  }
   107  
   108  func dbTableEntriesNumber(ip, port, networkName, tableName string, doneCh chan resultTuple) {
   109  	body, err := httpGet(ip, port, "/gettable?nid="+networkName+"&tname="+tableName)
   110  
   111  	if err != nil {
   112  		logrus.Errorf("tableEntriesNumber %s there was an error: %s", ip, err)
   113  		doneCh <- resultTuple{id: ip, result: -1}
   114  		return
   115  	}
   116  	elementsRegexp := regexp.MustCompile(`total entries: ([0-9]+)`)
   117  	entriesNum, _ := strconv.Atoi(elementsRegexp.FindStringSubmatch(string(body))[1])
   118  	doneCh <- resultTuple{id: ip, result: entriesNum}
   119  }
   120  
   121  func dbQueueLength(ip, port, networkName string, doneCh chan resultTuple) {
   122  	body, err := httpGet(ip, port, "/networkstats?nid="+networkName)
   123  
   124  	if err != nil {
   125  		logrus.Errorf("queueLength %s there was an error: %s", ip, err)
   126  		doneCh <- resultTuple{id: ip, result: -1}
   127  		return
   128  	}
   129  	elementsRegexp := regexp.MustCompile(`qlen: ([0-9]+)`)
   130  	entriesNum, _ := strconv.Atoi(elementsRegexp.FindStringSubmatch(string(body))[1])
   131  	doneCh <- resultTuple{id: ip, result: entriesNum}
   132  }
   133  
   134  func clientWatchTable(ip, port, networkName, tableName string, doneCh chan resultTuple) {
   135  	httpGetFatalError(ip, port, "/watchtable?nid="+networkName+"&tname="+tableName)
   136  	if doneCh != nil {
   137  		doneCh <- resultTuple{id: ip, result: 0}
   138  	}
   139  }
   140  
   141  func clientTableEntriesNumber(ip, port, networkName, tableName string, doneCh chan resultTuple) {
   142  	body, err := httpGet(ip, port, "/watchedtableentries?nid="+networkName+"&tname="+tableName)
   143  
   144  	if err != nil {
   145  		logrus.Errorf("clientTableEntriesNumber %s there was an error: %s", ip, err)
   146  		doneCh <- resultTuple{id: ip, result: -1}
   147  		return
   148  	}
   149  	elementsRegexp := regexp.MustCompile(`total elements: ([0-9]+)`)
   150  	entriesNum, _ := strconv.Atoi(elementsRegexp.FindStringSubmatch(string(body))[1])
   151  	doneCh <- resultTuple{id: ip, result: entriesNum}
   152  }
   153  
   154  func writeKeysNumber(ip, port, networkName, tableName, key string, number int, doneCh chan resultTuple) {
   155  	x := 0
   156  	for ; x < number; x++ {
   157  		k := key + strconv.Itoa(x)
   158  		// write key
   159  		writeTableKey(ip, port, networkName, tableName, k)
   160  	}
   161  	doneCh <- resultTuple{id: ip, result: x}
   162  }
   163  
   164  func deleteKeysNumber(ip, port, networkName, tableName, key string, number int, doneCh chan resultTuple) {
   165  	x := 0
   166  	for ; x < number; x++ {
   167  		k := key + strconv.Itoa(x)
   168  		// write key
   169  		deleteTableKey(ip, port, networkName, tableName, k)
   170  	}
   171  	doneCh <- resultTuple{id: ip, result: x}
   172  }
   173  
   174  func writeUniqueKeys(ctx context.Context, ip, port, networkName, tableName, key string, doneCh chan resultTuple) {
   175  	for x := 0; ; x++ {
   176  		select {
   177  		case <-ctx.Done():
   178  			doneCh <- resultTuple{id: ip, result: x}
   179  			return
   180  		default:
   181  			k := key + strconv.Itoa(x)
   182  			// write key
   183  			writeTableKey(ip, port, networkName, tableName, k)
   184  			// give time to send out key writes
   185  			time.Sleep(100 * time.Millisecond)
   186  		}
   187  	}
   188  }
   189  
   190  func writeDeleteUniqueKeys(ctx context.Context, ip, port, networkName, tableName, key string, doneCh chan resultTuple) {
   191  	for x := 0; ; x++ {
   192  		select {
   193  		case <-ctx.Done():
   194  			doneCh <- resultTuple{id: ip, result: x}
   195  			return
   196  		default:
   197  			k := key + strconv.Itoa(x)
   198  			// write key
   199  			writeTableKey(ip, port, networkName, tableName, k)
   200  			// give time to send out key writes
   201  			time.Sleep(100 * time.Millisecond)
   202  			// delete key
   203  			deleteTableKey(ip, port, networkName, tableName, k)
   204  		}
   205  	}
   206  }
   207  
   208  func writeDeleteLeaveJoin(ctx context.Context, ip, port, networkName, tableName, key string, doneCh chan resultTuple) {
   209  	for x := 0; ; x++ {
   210  		select {
   211  		case <-ctx.Done():
   212  			doneCh <- resultTuple{id: ip, result: x}
   213  			return
   214  		default:
   215  			k := key + strconv.Itoa(x)
   216  			// write key
   217  			writeTableKey(ip, port, networkName, tableName, k)
   218  			time.Sleep(100 * time.Millisecond)
   219  			// delete key
   220  			deleteTableKey(ip, port, networkName, tableName, k)
   221  			// give some time
   222  			time.Sleep(100 * time.Millisecond)
   223  			// leave network
   224  			leaveNetwork(ip, port, networkName, nil)
   225  			// join network
   226  			joinNetwork(ip, port, networkName, nil)
   227  		}
   228  	}
   229  }
   230  
   231  func ready(ip, port string, doneCh chan resultTuple) {
   232  	for {
   233  		body, err := httpGet(ip, port, "/ready")
   234  		if err != nil || !strings.Contains(string(body), "OK") {
   235  			time.Sleep(500 * time.Millisecond)
   236  			continue
   237  		}
   238  		// success
   239  		break
   240  	}
   241  	// notify the completion
   242  	doneCh <- resultTuple{id: ip, result: 0}
   243  }
   244  
   245  func checkTable(ctx context.Context, ips []string, port, networkName, tableName string, expectedEntries int, fn func(string, string, string, string, chan resultTuple)) (opTime time.Duration) {
   246  	startTime := time.Now().UnixNano()
   247  	var successTime int64
   248  
   249  	// Loop for 2 minutes to guarantee that the result is stable
   250  	for {
   251  		select {
   252  		case <-ctx.Done():
   253  			// Validate test success, if the time is set means that all the tables are empty
   254  			if successTime != 0 {
   255  				opTime = time.Duration(successTime-startTime) / time.Millisecond
   256  				logrus.Infof("Check table passed, the cluster converged in %d msec", opTime)
   257  				return
   258  			}
   259  			log.Fatal("Test failed, there is still entries in the tables of the nodes")
   260  		default:
   261  			logrus.Infof("Checking table %s expected %d", tableName, expectedEntries)
   262  			doneCh := make(chan resultTuple, len(ips))
   263  			for _, ip := range ips {
   264  				go fn(ip, servicePort, networkName, tableName, doneCh)
   265  			}
   266  
   267  			nodesWithCorrectEntriesNum := 0
   268  			for i := len(ips); i > 0; i-- {
   269  				tableEntries := <-doneCh
   270  				logrus.Infof("Node %s has %d entries", tableEntries.id, tableEntries.result)
   271  				if tableEntries.result == expectedEntries {
   272  					nodesWithCorrectEntriesNum++
   273  				}
   274  			}
   275  			close(doneCh)
   276  			if nodesWithCorrectEntriesNum == len(ips) {
   277  				if successTime == 0 {
   278  					successTime = time.Now().UnixNano()
   279  					logrus.Infof("Success after %d msec", time.Duration(successTime-startTime)/time.Millisecond)
   280  				}
   281  			} else {
   282  				successTime = 0
   283  			}
   284  			time.Sleep(10 * time.Second)
   285  		}
   286  	}
   287  }
   288  
   289  func waitWriters(parallelWriters int, mustWrite bool, doneCh chan resultTuple) map[string]int {
   290  	var totalKeys int
   291  	resultTable := make(map[string]int)
   292  	for i := 0; i < parallelWriters; i++ {
   293  		logrus.Infof("Waiting for %d workers", parallelWriters-i)
   294  		workerReturn := <-doneCh
   295  		totalKeys += workerReturn.result
   296  		if mustWrite && workerReturn.result == 0 {
   297  			log.Fatalf("The worker %s did not write any key %d == 0", workerReturn.id, workerReturn.result)
   298  		}
   299  		if !mustWrite && workerReturn.result != 0 {
   300  			log.Fatalf("The worker %s was supposed to return 0 instead %d != 0", workerReturn.id, workerReturn.result)
   301  		}
   302  		if mustWrite {
   303  			resultTable[workerReturn.id] = workerReturn.result
   304  			logrus.Infof("The worker %s wrote %d keys", workerReturn.id, workerReturn.result)
   305  		}
   306  	}
   307  	resultTable[totalWrittenKeys] = totalKeys
   308  	return resultTable
   309  }
   310  
   311  // ready
   312  func doReady(ips []string) {
   313  	doneCh := make(chan resultTuple, len(ips))
   314  	// check all the nodes
   315  	for _, ip := range ips {
   316  		go ready(ip, servicePort, doneCh)
   317  	}
   318  	// wait for the readiness of all nodes
   319  	for i := len(ips); i > 0; i-- {
   320  		<-doneCh
   321  	}
   322  	close(doneCh)
   323  }
   324  
   325  // join
   326  func doJoin(ips []string) {
   327  	doneCh := make(chan resultTuple, len(ips))
   328  	// check all the nodes
   329  	for i, ip := range ips {
   330  		members := append([]string(nil), ips[:i]...)
   331  		members = append(members, ips[i+1:]...)
   332  		go joinCluster(ip, servicePort, members, doneCh)
   333  	}
   334  	// wait for the readiness of all nodes
   335  	for i := len(ips); i > 0; i-- {
   336  		<-doneCh
   337  	}
   338  	close(doneCh)
   339  }
   340  
   341  // cluster-peers expectedNumberPeers maxRetry
   342  func doClusterPeers(ips []string, args []string) {
   343  	doneCh := make(chan resultTuple, len(ips))
   344  	expectedPeers, _ := strconv.Atoi(args[0])
   345  	maxRetry, _ := strconv.Atoi(args[1])
   346  	for retry := 0; retry < maxRetry; retry++ {
   347  		// check all the nodes
   348  		for _, ip := range ips {
   349  			go clusterPeersNumber(ip, servicePort, doneCh)
   350  		}
   351  		var failed bool
   352  		// wait for the readiness of all nodes
   353  		for i := len(ips); i > 0; i-- {
   354  			node := <-doneCh
   355  			if node.result != expectedPeers {
   356  				failed = true
   357  				if retry == maxRetry-1 {
   358  					log.Fatalf("Expected peers from %s mismatch %d != %d", node.id, expectedPeers, node.result)
   359  				} else {
   360  					logrus.Warnf("Expected peers from %s mismatch %d != %d", node.id, expectedPeers, node.result)
   361  				}
   362  				time.Sleep(1 * time.Second)
   363  			}
   364  		}
   365  		// check if needs retry
   366  		if !failed {
   367  			break
   368  		}
   369  	}
   370  	close(doneCh)
   371  }
   372  
   373  // join-network networkName
   374  func doJoinNetwork(ips []string, args []string) {
   375  	doneCh := make(chan resultTuple, len(ips))
   376  	// check all the nodes
   377  	for _, ip := range ips {
   378  		go joinNetwork(ip, servicePort, args[0], doneCh)
   379  	}
   380  	// wait for the readiness of all nodes
   381  	for i := len(ips); i > 0; i-- {
   382  		<-doneCh
   383  	}
   384  	close(doneCh)
   385  }
   386  
   387  // leave-network networkName
   388  func doLeaveNetwork(ips []string, args []string) {
   389  	doneCh := make(chan resultTuple, len(ips))
   390  	// check all the nodes
   391  	for _, ip := range ips {
   392  		go leaveNetwork(ip, servicePort, args[0], doneCh)
   393  	}
   394  	// wait for the readiness of all nodes
   395  	for i := len(ips); i > 0; i-- {
   396  		<-doneCh
   397  	}
   398  	close(doneCh)
   399  }
   400  
   401  // network-peers networkName expectedNumberPeers maxRetry
   402  func doNetworkPeers(ips []string, args []string) {
   403  	doneCh := make(chan resultTuple, len(ips))
   404  	networkName := args[0]
   405  	expectedPeers, _ := strconv.Atoi(args[1])
   406  	maxRetry, _ := strconv.Atoi(args[2])
   407  	for retry := 0; retry < maxRetry; retry++ {
   408  		// check all the nodes
   409  		for _, ip := range ips {
   410  			go networkPeersNumber(ip, servicePort, networkName, doneCh)
   411  		}
   412  		var failed bool
   413  		// wait for the readiness of all nodes
   414  		for i := len(ips); i > 0; i-- {
   415  			node := <-doneCh
   416  			if node.result != expectedPeers {
   417  				failed = true
   418  				if retry == maxRetry-1 {
   419  					log.Fatalf("Expected peers from %s mismatch %d != %d", node.id, expectedPeers, node.result)
   420  				} else {
   421  					logrus.Warnf("Expected peers from %s mismatch %d != %d", node.id, expectedPeers, node.result)
   422  				}
   423  				time.Sleep(1 * time.Second)
   424  			}
   425  		}
   426  		// check if needs retry
   427  		if !failed {
   428  			break
   429  		}
   430  	}
   431  	close(doneCh)
   432  }
   433  
   434  // network-stats-queue networkName <gt/lt> queueSize
   435  func doNetworkStatsQueue(ips []string, args []string) {
   436  	doneCh := make(chan resultTuple, len(ips))
   437  	networkName := args[0]
   438  	comparison := args[1]
   439  	size, _ := strconv.Atoi(args[2])
   440  
   441  	// check all the nodes
   442  	for _, ip := range ips {
   443  		go dbQueueLength(ip, servicePort, networkName, doneCh)
   444  	}
   445  
   446  	var avgQueueSize int
   447  	// wait for the readiness of all nodes
   448  	for i := len(ips); i > 0; i-- {
   449  		node := <-doneCh
   450  		switch comparison {
   451  		case "lt":
   452  			if node.result > size {
   453  				log.Fatalf("Expected queue size from %s to be %d < %d", node.id, node.result, size)
   454  			}
   455  		case "gt":
   456  			if node.result < size {
   457  				log.Fatalf("Expected queue size from %s to be %d > %d", node.id, node.result, size)
   458  			}
   459  		default:
   460  			log.Fatal("unknown comparison operator")
   461  		}
   462  		avgQueueSize += node.result
   463  	}
   464  	close(doneCh)
   465  	avgQueueSize /= len(ips)
   466  	fmt.Fprintf(os.Stderr, "doNetworkStatsQueue succeeded with avg queue:%d", avgQueueSize)
   467  }
   468  
   469  // write-keys networkName tableName parallelWriters numberOfKeysEach
   470  func doWriteKeys(ips []string, args []string) {
   471  	networkName := args[0]
   472  	tableName := args[1]
   473  	parallelWriters, _ := strconv.Atoi(args[2])
   474  	numberOfKeys, _ := strconv.Atoi(args[3])
   475  
   476  	doneCh := make(chan resultTuple, parallelWriters)
   477  	// Enable watch of tables from clients
   478  	for i := 0; i < parallelWriters; i++ {
   479  		go clientWatchTable(ips[i], servicePort, networkName, tableName, doneCh)
   480  	}
   481  	waitWriters(parallelWriters, false, doneCh)
   482  
   483  	// Start parallel writers that will create and delete unique keys
   484  	defer close(doneCh)
   485  	for i := 0; i < parallelWriters; i++ {
   486  		key := "key-" + strconv.Itoa(i) + "-"
   487  		logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i])
   488  		go writeKeysNumber(ips[i], servicePort, networkName, tableName, key, numberOfKeys, doneCh)
   489  	}
   490  
   491  	// Sync with all the writers
   492  	keyMap := waitWriters(parallelWriters, true, doneCh)
   493  	logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys])
   494  
   495  	// check table entries for 2 minutes
   496  	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
   497  	opTime := checkTable(ctx, ips, servicePort, networkName, tableName, keyMap[totalWrittenKeys], dbTableEntriesNumber)
   498  	cancel()
   499  	fmt.Fprintf(os.Stderr, "doWriteKeys succeeded in %d msec", opTime)
   500  }
   501  
   502  // delete-keys networkName tableName parallelWriters numberOfKeysEach
   503  func doDeleteKeys(ips []string, args []string) {
   504  	networkName := args[0]
   505  	tableName := args[1]
   506  	parallelWriters, _ := strconv.Atoi(args[2])
   507  	numberOfKeys, _ := strconv.Atoi(args[3])
   508  
   509  	doneCh := make(chan resultTuple, parallelWriters)
   510  	// Enable watch of tables from clients
   511  	for i := 0; i < parallelWriters; i++ {
   512  		go clientWatchTable(ips[i], servicePort, networkName, tableName, doneCh)
   513  	}
   514  	waitWriters(parallelWriters, false, doneCh)
   515  
   516  	// Start parallel writers that will create and delete unique keys
   517  	defer close(doneCh)
   518  	for i := 0; i < parallelWriters; i++ {
   519  		key := "key-" + strconv.Itoa(i) + "-"
   520  		logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i])
   521  		go deleteKeysNumber(ips[i], servicePort, networkName, tableName, key, numberOfKeys, doneCh)
   522  	}
   523  
   524  	// Sync with all the writers
   525  	keyMap := waitWriters(parallelWriters, true, doneCh)
   526  	logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys])
   527  
   528  	// check table entries for 2 minutes
   529  	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
   530  	opTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber)
   531  	cancel()
   532  	fmt.Fprintf(os.Stderr, "doDeletekeys succeeded in %d msec", opTime)
   533  }
   534  
   535  // write-delete-unique-keys networkName tableName numParallelWriters writeTimeSec
   536  func doWriteDeleteUniqueKeys(ips []string, args []string) {
   537  	networkName := args[0]
   538  	tableName := args[1]
   539  	parallelWriters, _ := strconv.Atoi(args[2])
   540  	writeTimeSec, _ := strconv.Atoi(args[3])
   541  
   542  	doneCh := make(chan resultTuple, parallelWriters)
   543  	// Enable watch of tables from clients
   544  	for i := 0; i < parallelWriters; i++ {
   545  		go clientWatchTable(ips[i], servicePort, networkName, tableName, doneCh)
   546  	}
   547  	waitWriters(parallelWriters, false, doneCh)
   548  
   549  	// Start parallel writers that will create and delete unique keys
   550  	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second)
   551  	for i := 0; i < parallelWriters; i++ {
   552  		key := "key-" + strconv.Itoa(i) + "-"
   553  		logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i])
   554  		go writeDeleteUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh)
   555  	}
   556  
   557  	// Sync with all the writers
   558  	keyMap := waitWriters(parallelWriters, true, doneCh)
   559  	cancel()
   560  	logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys])
   561  
   562  	// check table entries for 2 minutes
   563  	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute)
   564  	opDBTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber)
   565  	cancel()
   566  	ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
   567  	opClientTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, clientTableEntriesNumber)
   568  	cancel()
   569  	fmt.Fprintf(os.Stderr, "doWriteDeleteUniqueKeys succeeded in %d msec and client %d msec", opDBTime, opClientTime)
   570  }
   571  
   572  // write-unique-keys networkName tableName numParallelWriters writeTimeSec
   573  func doWriteUniqueKeys(ips []string, args []string) {
   574  	networkName := args[0]
   575  	tableName := args[1]
   576  	parallelWriters, _ := strconv.Atoi(args[2])
   577  	writeTimeSec, _ := strconv.Atoi(args[3])
   578  
   579  	doneCh := make(chan resultTuple, parallelWriters)
   580  	// Enable watch of tables from clients
   581  	for i := 0; i < parallelWriters; i++ {
   582  		go clientWatchTable(ips[i], servicePort, networkName, tableName, doneCh)
   583  	}
   584  	waitWriters(parallelWriters, false, doneCh)
   585  
   586  	// Start parallel writers that will create and delete unique keys
   587  	defer close(doneCh)
   588  	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second)
   589  	for i := 0; i < parallelWriters; i++ {
   590  		key := "key-" + strconv.Itoa(i) + "-"
   591  		logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i])
   592  		go writeUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh)
   593  	}
   594  
   595  	// Sync with all the writers
   596  	keyMap := waitWriters(parallelWriters, true, doneCh)
   597  	cancel()
   598  	logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys])
   599  
   600  	// check table entries for 2 minutes
   601  	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute)
   602  	opTime := checkTable(ctx, ips, servicePort, networkName, tableName, keyMap[totalWrittenKeys], dbTableEntriesNumber)
   603  	cancel()
   604  	fmt.Fprintf(os.Stderr, "doWriteUniqueKeys succeeded in %d msec", opTime)
   605  }
   606  
   607  // write-delete-leave-join networkName tableName numParallelWriters writeTimeSec
   608  func doWriteDeleteLeaveJoin(ips []string, args []string) {
   609  	networkName := args[0]
   610  	tableName := args[1]
   611  	parallelWriters, _ := strconv.Atoi(args[2])
   612  	writeTimeSec, _ := strconv.Atoi(args[3])
   613  
   614  	// Start parallel writers that will create and delete unique keys
   615  	doneCh := make(chan resultTuple, parallelWriters)
   616  	defer close(doneCh)
   617  	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second)
   618  	for i := 0; i < parallelWriters; i++ {
   619  		key := "key-" + strconv.Itoa(i) + "-"
   620  		logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i])
   621  		go writeDeleteLeaveJoin(ctx, ips[i], servicePort, networkName, tableName, key, doneCh)
   622  	}
   623  
   624  	// Sync with all the writers
   625  	keyMap := waitWriters(parallelWriters, true, doneCh)
   626  	cancel()
   627  	logrus.Infof("Written a total of %d keys on the cluster", keyMap["totalKeys"])
   628  
   629  	// check table entries for 2 minutes
   630  	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute)
   631  	opTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber)
   632  	cancel()
   633  	fmt.Fprintf(os.Stderr, "doWriteDeleteLeaveJoin succeeded in %d msec", opTime)
   634  }
   635  
   636  // write-delete-wait-leave-join networkName tableName numParallelWriters writeTimeSec
   637  func doWriteDeleteWaitLeaveJoin(ips []string, args []string) {
   638  	networkName := args[0]
   639  	tableName := args[1]
   640  	parallelWriters, _ := strconv.Atoi(args[2])
   641  	writeTimeSec, _ := strconv.Atoi(args[3])
   642  
   643  	// Start parallel writers that will create and delete unique keys
   644  	doneCh := make(chan resultTuple, parallelWriters)
   645  	defer close(doneCh)
   646  	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second)
   647  	for i := 0; i < parallelWriters; i++ {
   648  		key := "key-" + strconv.Itoa(i) + "-"
   649  		logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i])
   650  		go writeDeleteUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh)
   651  	}
   652  
   653  	// Sync with all the writers
   654  	keyMap := waitWriters(parallelWriters, true, doneCh)
   655  	cancel()
   656  	logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys])
   657  
   658  	// The writers will leave the network
   659  	for i := 0; i < parallelWriters; i++ {
   660  		logrus.Infof("worker leaveNetwork: %d on IP:%s", i, ips[i])
   661  		go leaveNetwork(ips[i], servicePort, networkName, doneCh)
   662  	}
   663  	waitWriters(parallelWriters, false, doneCh)
   664  
   665  	// Give some time
   666  	time.Sleep(100 * time.Millisecond)
   667  
   668  	// The writers will join the network
   669  	for i := 0; i < parallelWriters; i++ {
   670  		logrus.Infof("worker joinNetwork: %d on IP:%s", i, ips[i])
   671  		go joinNetwork(ips[i], servicePort, networkName, doneCh)
   672  	}
   673  	waitWriters(parallelWriters, false, doneCh)
   674  
   675  	// check table entries for 2 minutes
   676  	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute)
   677  	opTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber)
   678  	cancel()
   679  	fmt.Fprintf(os.Stderr, "doWriteDeleteWaitLeaveJoin succeeded in %d msec", opTime)
   680  }
   681  
   682  // write-wait-leave networkName tableName numParallelWriters writeTimeSec
   683  func doWriteWaitLeave(ips []string, args []string) {
   684  	networkName := args[0]
   685  	tableName := args[1]
   686  	parallelWriters, _ := strconv.Atoi(args[2])
   687  	writeTimeSec, _ := strconv.Atoi(args[3])
   688  
   689  	// Start parallel writers that will create and delete unique keys
   690  	doneCh := make(chan resultTuple, parallelWriters)
   691  	defer close(doneCh)
   692  	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second)
   693  	for i := 0; i < parallelWriters; i++ {
   694  		key := "key-" + strconv.Itoa(i) + "-"
   695  		logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i])
   696  		go writeUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh)
   697  	}
   698  
   699  	// Sync with all the writers
   700  	keyMap := waitWriters(parallelWriters, true, doneCh)
   701  	cancel()
   702  	logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys])
   703  
   704  	// The writers will leave the network
   705  	for i := 0; i < parallelWriters; i++ {
   706  		logrus.Infof("worker leaveNetwork: %d on IP:%s", i, ips[i])
   707  		go leaveNetwork(ips[i], servicePort, networkName, doneCh)
   708  	}
   709  	waitWriters(parallelWriters, false, doneCh)
   710  
   711  	// check table entries for 2 minutes
   712  	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute)
   713  	opTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber)
   714  	cancel()
   715  	fmt.Fprintf(os.Stderr, "doWriteLeaveJoin succeeded in %d msec", opTime)
   716  }
   717  
   718  // write-wait-leave-join networkName tableName numParallelWriters writeTimeSec numParallelLeaver
   719  func doWriteWaitLeaveJoin(ips []string, args []string) {
   720  	networkName := args[0]
   721  	tableName := args[1]
   722  	parallelWriters, _ := strconv.Atoi(args[2])
   723  	writeTimeSec, _ := strconv.Atoi(args[3])
   724  	parallelLeaver, _ := strconv.Atoi(args[4])
   725  
   726  	// Start parallel writers that will create and delete unique keys
   727  	doneCh := make(chan resultTuple, parallelWriters)
   728  	defer close(doneCh)
   729  	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second)
   730  	for i := 0; i < parallelWriters; i++ {
   731  		key := "key-" + strconv.Itoa(i) + "-"
   732  		logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i])
   733  		go writeUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh)
   734  	}
   735  
   736  	// Sync with all the writers
   737  	keyMap := waitWriters(parallelWriters, true, doneCh)
   738  	cancel()
   739  	logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys])
   740  
   741  	keysExpected := keyMap[totalWrittenKeys]
   742  	// The Leavers will leave the network
   743  	for i := 0; i < parallelLeaver; i++ {
   744  		logrus.Infof("worker leaveNetwork: %d on IP:%s", i, ips[i])
   745  		go leaveNetwork(ips[i], servicePort, networkName, doneCh)
   746  		// Once a node leave all the keys written previously will be deleted, so the expected keys will consider that as removed
   747  		keysExpected -= keyMap[ips[i]]
   748  	}
   749  	waitWriters(parallelLeaver, false, doneCh)
   750  
   751  	// Give some time
   752  	time.Sleep(100 * time.Millisecond)
   753  
   754  	// The writers will join the network
   755  	for i := 0; i < parallelLeaver; i++ {
   756  		logrus.Infof("worker joinNetwork: %d on IP:%s", i, ips[i])
   757  		go joinNetwork(ips[i], servicePort, networkName, doneCh)
   758  	}
   759  	waitWriters(parallelLeaver, false, doneCh)
   760  
   761  	// check table entries for 2 minutes
   762  	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute)
   763  	opTime := checkTable(ctx, ips, servicePort, networkName, tableName, keysExpected, dbTableEntriesNumber)
   764  	cancel()
   765  	fmt.Fprintf(os.Stderr, "doWriteWaitLeaveJoin succeeded in %d msec", opTime)
   766  }
   767  
   768  var cmdArgChec = map[string]int{
   769  	"debug":                    0,
   770  	"fail":                     0,
   771  	"ready":                    2,
   772  	"join":                     2,
   773  	"leave":                    2,
   774  	"join-network":             3,
   775  	"leave-network":            3,
   776  	"cluster-peers":            5,
   777  	"network-peers":            5,
   778  	"write-delete-unique-keys": 7,
   779  }
   780  
   781  // Client is a client
   782  func Client(args []string) {
   783  	logrus.Infof("[CLIENT] Starting with arguments %v", args)
   784  	command := args[0]
   785  
   786  	if len(args) < cmdArgChec[command] {
   787  		log.Fatalf("Command %s requires %d arguments, passed %d, aborting...", command, cmdArgChec[command], len(args))
   788  	}
   789  
   790  	switch command {
   791  	case "debug":
   792  		time.Sleep(1 * time.Hour)
   793  		os.Exit(0)
   794  	case "fail":
   795  		log.Fatalf("Test error condition with message: error error error")
   796  	}
   797  
   798  	serviceName := args[1]
   799  	ips, _ := net.LookupHost("tasks." + serviceName)
   800  	logrus.Infof("got the ips %v", ips)
   801  	if len(ips) == 0 {
   802  		log.Fatalf("Cannot resolve any IP for the service tasks.%s", serviceName)
   803  	}
   804  	servicePort = args[2]
   805  	commandArgs := args[3:]
   806  	logrus.Infof("Executing %s with args:%v", command, commandArgs)
   807  	switch command {
   808  	case "ready":
   809  		doReady(ips)
   810  	case "join":
   811  		doJoin(ips)
   812  	case "leave":
   813  
   814  	case "cluster-peers":
   815  		// cluster-peers maxRetry
   816  		doClusterPeers(ips, commandArgs)
   817  
   818  	case "join-network":
   819  		// join-network networkName
   820  		doJoinNetwork(ips, commandArgs)
   821  	case "leave-network":
   822  		// leave-network networkName
   823  		doLeaveNetwork(ips, commandArgs)
   824  	case "network-peers":
   825  		// network-peers networkName expectedNumberPeers maxRetry
   826  		doNetworkPeers(ips, commandArgs)
   827  		//	case "network-stats-entries":
   828  		//		// network-stats-entries networkName maxRetry
   829  		//		doNetworkPeers(ips, commandArgs)
   830  	case "network-stats-queue":
   831  		// network-stats-queue networkName <lt/gt> queueSize
   832  		doNetworkStatsQueue(ips, commandArgs)
   833  
   834  	case "write-keys":
   835  		// write-keys networkName tableName parallelWriters numberOfKeysEach
   836  		doWriteKeys(ips, commandArgs)
   837  	case "delete-keys":
   838  		// delete-keys networkName tableName parallelWriters numberOfKeysEach
   839  		doDeleteKeys(ips, commandArgs)
   840  	case "write-unique-keys":
   841  		// write-delete-unique-keys networkName tableName numParallelWriters writeTimeSec
   842  		doWriteUniqueKeys(ips, commandArgs)
   843  	case "write-delete-unique-keys":
   844  		// write-delete-unique-keys networkName tableName numParallelWriters writeTimeSec
   845  		doWriteDeleteUniqueKeys(ips, commandArgs)
   846  	case "write-delete-leave-join":
   847  		// write-delete-leave-join networkName tableName numParallelWriters writeTimeSec
   848  		doWriteDeleteLeaveJoin(ips, commandArgs)
   849  	case "write-delete-wait-leave-join":
   850  		// write-delete-wait-leave-join networkName tableName numParallelWriters writeTimeSec
   851  		doWriteDeleteWaitLeaveJoin(ips, commandArgs)
   852  	case "write-wait-leave":
   853  		// write-wait-leave networkName tableName numParallelWriters writeTimeSec
   854  		doWriteWaitLeave(ips, commandArgs)
   855  	case "write-wait-leave-join":
   856  		// write-wait-leave networkName tableName numParallelWriters writeTimeSec
   857  		doWriteWaitLeaveJoin(ips, commandArgs)
   858  	default:
   859  		log.Fatalf("Command %s not recognized", command)
   860  	}
   861  }