Пример #1
0
func interactiveSplitDiff(wr *wrangler.Wrangler, w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		httpError(w, "cannot parse form: %s", err)
		return
	}
	keyspace := r.FormValue("keyspace")
	shard := r.FormValue("shard")

	if keyspace == "" || shard == "" {
		// display the list of possible shards to chose from
		result := make(map[string]interface{})
		shards, err := shardsWithSources(wr)
		if err != nil {
			result["Error"] = err.Error()
		} else {
			result["Shards"] = shards
		}

		executeTemplate(w, splitDiffTemplate, result)
	} else {
		// start the diff job
		wrk := worker.NewSplitDiffWorker(wr, *cell, keyspace, shard)
		if _, err := setAndStartWorker(wrk); err != nil {
			httpError(w, "cannot set worker: %s", err)
			return
		}

		http.Redirect(w, r, servenv.StatusURLPath(), http.StatusTemporaryRedirect)
	}
}
Пример #2
0
func interactiveSplitDiff(ctx context.Context, wr *wrangler.Wrangler, w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		httpError(w, "cannot parse form: %s", err)
		return
	}
	keyspace := r.FormValue("keyspace")
	shard := r.FormValue("shard")

	if keyspace == "" || shard == "" {
		// display the list of possible shards to chose from
		result := make(map[string]interface{})
		shards, err := shardsWithSources(ctx, wr)
		if err != nil {
			result["Error"] = err.Error()
		} else {
			result["Shards"] = shards
		}

		executeTemplate(w, splitDiffTemplate, result)
		return
	}

	submitButtonValue := r.FormValue("submit")
	if submitButtonValue == "" {
		// display the input form
		result := make(map[string]interface{})
		result["Keyspace"] = keyspace
		result["Shard"] = shard
		executeTemplate(w, splitDiffTemplate2, result)
		return
	}

	// Process input form.
	excludeTables := r.FormValue("excludeTables")
	var excludeTableArray []string
	if excludeTables != "" {
		excludeTableArray = strings.Split(excludeTables, ",")
	}

	// start the diff job
	wrk := worker.NewSplitDiffWorker(wr, *cell, keyspace, shard, excludeTableArray)
	if _, err := setAndStartWorker(wrk); err != nil {
		httpError(w, "cannot set worker: %s", err)
		return
	}

	http.Redirect(w, r, servenv.StatusURLPath(), http.StatusTemporaryRedirect)
}
Пример #3
0
func interactiveVerticalSplitClone(ctx context.Context, wr *wrangler.Wrangler, w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		httpError(w, "cannot parse form: %s", err)
		return
	}

	keyspace := r.FormValue("keyspace")
	if keyspace == "" {
		// display the list of possible keyspaces to choose from
		result := make(map[string]interface{})
		keyspaces, err := keyspacesWithServedFrom(ctx, wr)
		if err != nil {
			result["Error"] = err.Error()
		} else {
			result["Keyspaces"] = keyspaces
		}

		executeTemplate(w, verticalSplitCloneTemplate, result)
		return
	}

	tables := r.FormValue("tables")
	if tables == "" {
		// display the input form
		result := make(map[string]interface{})
		result["Keyspace"] = keyspace
		result["DefaultSourceReaderCount"] = fmt.Sprintf("%v", defaultSourceReaderCount)
		result["DefaultDestinationPackCount"] = fmt.Sprintf("%v", defaultDestinationPackCount)
		result["DefaultMinTableSizeForSplit"] = fmt.Sprintf("%v", defaultMinTableSizeForSplit)
		result["DefaultDestinationWriterCount"] = fmt.Sprintf("%v", defaultDestinationWriterCount)
		executeTemplate(w, verticalSplitCloneTemplate2, result)
		return
	}
	tableArray := strings.Split(tables, ",")

	// get other parameters
	strategy := r.FormValue("strategy")
	sourceReaderCountStr := r.FormValue("sourceReaderCount")
	sourceReaderCount, err := strconv.ParseInt(sourceReaderCountStr, 0, 64)
	if err != nil {
		httpError(w, "cannot parse sourceReaderCount: %s", err)
		return
	}
	destinationPackCountStr := r.FormValue("destinationPackCount")
	destinationPackCount, err := strconv.ParseInt(destinationPackCountStr, 0, 64)
	if err != nil {
		httpError(w, "cannot parse destinationPackCount: %s", err)
		return
	}
	minTableSizeForSplitStr := r.FormValue("minTableSizeForSplit")
	minTableSizeForSplit, err := strconv.ParseInt(minTableSizeForSplitStr, 0, 64)
	if err != nil {
		httpError(w, "cannot parse minTableSizeForSplit: %s", err)
		return
	}
	destinationWriterCountStr := r.FormValue("destinationWriterCount")
	destinationWriterCount, err := strconv.ParseInt(destinationWriterCountStr, 0, 64)
	if err != nil {
		httpError(w, "cannot parse destinationWriterCount: %s", err)
		return
	}

	// start the clone job
	wrk, err := worker.NewVerticalSplitCloneWorker(wr, *cell, keyspace, "0", tableArray, strategy, int(sourceReaderCount), int(destinationPackCount), uint64(minTableSizeForSplit), int(destinationWriterCount))
	if err != nil {
		httpError(w, "cannot create worker: %v", err)
	}
	if _, err := setAndStartWorker(wrk); err != nil {
		httpError(w, "cannot set worker: %s", err)
		return
	}

	http.Redirect(w, r, servenv.StatusURLPath(), http.StatusTemporaryRedirect)
}
Пример #4
0
// InitStatusHandling installs webserver handlers for global actions like /status, /reset and /cancel.
func (wi *Instance) InitStatusHandling() {
	// code to serve /status
	workerTemplate := mustParseTemplate("worker", workerStatusHTML)
	http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
		if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil {
			acl.SendError(w, err)
			return
		}

		wi.currentWorkerMutex.Lock()
		wrk := wi.currentWorker
		logger := wi.currentMemoryLogger
		ctx := wi.currentContext
		err := wi.lastRunError
		wi.currentWorkerMutex.Unlock()

		data := make(map[string]interface{})
		if wrk != nil {
			status := template.HTML("Current worker:<br>\n") + wrk.StatusAsHTML()
			if ctx == nil {
				data["Done"] = true
				if err != nil {
					status += template.HTML(fmt.Sprintf("<br>\nEnded with an error: %v<br>\n", err))
				}
			}
			data["Status"] = status
			if logger != nil {
				data["Logs"] = template.HTML(strings.Replace(logger.String(), "\n", "</br>\n", -1))
			} else {
				data["Logs"] = template.HTML("See console for logs</br>\n")
			}
		}
		executeTemplate(w, workerTemplate, data)
	})

	// add the section in status that does auto-refresh of status div
	servenv.AddStatusPart("Worker Status", workerStatusPartHTML, func() interface{} {
		return nil
	})

	// reset handler
	http.HandleFunc("/reset", func(w http.ResponseWriter, r *http.Request) {
		if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil {
			acl.SendError(w, err)
			return
		}

		if err := wi.Reset(); err != nil {
			httpError(w, err.Error(), nil)
		} else {
			// No worker currently running, we go to the menu.
			http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
		}
	})

	// cancel handler
	http.HandleFunc("/cancel", func(w http.ResponseWriter, r *http.Request) {
		if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil {
			acl.SendError(w, err)
			return
		}

		wi.currentWorkerMutex.Lock()

		// no worker, or not running, we go to the menu
		if wi.currentWorker == nil || wi.currentCancelFunc == nil {
			wi.currentWorkerMutex.Unlock()
			http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
			return
		}

		// otherwise, cancel the running worker and go back to the status page
		cancel := wi.currentCancelFunc
		wi.currentWorkerMutex.Unlock()
		cancel()
		http.Redirect(w, r, servenv.StatusURLPath(), http.StatusTemporaryRedirect)

	})
}
Пример #5
0
// InitInteractiveMode installs webserver handlers for each known command.
func (wi *Instance) InitInteractiveMode() {
	indexTemplate := mustParseTemplate("index", indexHTML)
	subIndexTemplate := mustParseTemplate("subIndex", subIndexHTML)

	// toplevel menu
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil {
			acl.SendError(w, err)
			return
		}

		executeTemplate(w, indexTemplate, commands)
	})

	// command group menus
	for _, cg := range commands {
		// keep a local copy of the Command pointer for the
		// closure.
		pcg := cg
		http.HandleFunc("/"+cg.Name, func(w http.ResponseWriter, r *http.Request) {
			if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil {
				acl.SendError(w, err)
				return
			}

			executeTemplate(w, subIndexTemplate, pcg)
		})

		for _, c := range cg.Commands {
			// keep a local copy of the Command pointer for the closure.
			pc := c
			http.HandleFunc("/"+cg.Name+"/"+c.Name, func(w http.ResponseWriter, r *http.Request) {
				if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil {
					acl.SendError(w, err)
					return
				}

				wrk, template, data, err := pc.Interactive(wi.backgroundContext, wi, wi.wr, w, r)
				if err != nil {
					httpError(w, "%s", err)
				} else if template != nil && data != nil {
					executeTemplate(w, template, data)
					return
				}

				if wrk == nil {
					httpError(w, "Internal server error. Command: %s did not return correct response.", c.Name)
					return
				}

				if _, err := wi.setAndStartWorker(wrk, wi.wr); err != nil {
					httpError(w, "Could not set %s worker: %s", c.Name, err)
					return
				}
				http.Redirect(w, r, servenv.StatusURLPath(), http.StatusTemporaryRedirect)
			})
		}
	}

	log.Infof("Interactive mode ready")
}
Пример #6
0
func interactiveSplitClone(wr *wrangler.Wrangler, w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		httpError(w, "cannot parse form: %s", err)
		return
	}

	keyspace := r.FormValue("keyspace")
	shard := r.FormValue("shard")
	if keyspace == "" || shard == "" {
		// display the list of possible splits to choose from
		// (just find all the overlapping guys)
		result := make(map[string]interface{})
		choices, err := keyspacesWithOverlappingShards(wr)
		if err != nil {
			result["Error"] = err.Error()
		} else {
			result["Choices"] = choices
		}

		executeTemplate(w, splitCloneTemplate, result)
		return
	}

	sourceReaderCountStr := r.FormValue("sourceReaderCount")
	if sourceReaderCountStr == "" {
		// display the input form
		result := make(map[string]interface{})
		result["Keyspace"] = keyspace
		result["Shard"] = shard
		result["DefaultSourceReaderCount"] = fmt.Sprintf("%v", defaultSourceReaderCount)
		result["DefaultMinTableSizeForSplit"] = fmt.Sprintf("%v", defaultMinTableSizeForSplit)
		result["DefaultDestinationWriterCount"] = fmt.Sprintf("%v", defaultDestinationWriterCount)
		executeTemplate(w, splitCloneTemplate2, result)
		return
	}

	// get other parameters
	excludeTables := r.FormValue("excludeTables")
	excludeTableArray := strings.Split(excludeTables, ",")
	strategy := r.FormValue("strategy")
	sourceReaderCount, err := strconv.ParseInt(sourceReaderCountStr, 0, 64)
	if err != nil {
		httpError(w, "cannot parse sourceReaderCount: %s", err)
		return
	}
	minTableSizeForSplitStr := r.FormValue("minTableSizeForSplit")
	minTableSizeForSplit, err := strconv.ParseInt(minTableSizeForSplitStr, 0, 64)
	if err != nil {
		httpError(w, "cannot parse minTableSizeForSplit: %s", err)
		return
	}
	destinationWriterCountStr := r.FormValue("destinationWriterCount")
	destinationWriterCount, err := strconv.ParseInt(destinationWriterCountStr, 0, 64)
	if err != nil {
		httpError(w, "cannot parse destinationWriterCount: %s", err)
		return
	}

	// start the clone job
	wrk := worker.NewSplitCloneWorker(wr, *cell, keyspace, shard, excludeTableArray, strategy, int(sourceReaderCount), uint64(minTableSizeForSplit), int(destinationWriterCount))
	if _, err := setAndStartWorker(wrk); err != nil {
		httpError(w, "cannot set worker: %s", err)
		return
	}

	http.Redirect(w, r, servenv.StatusURLPath(), http.StatusTemporaryRedirect)
}