3 Star 2 Fork 0

Gitee 极速下载/orchestrator

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/outbrain/orchestrator/
克隆/下载
cli.go 40.80 KB
一键复制 编辑 原始数据 按行查看 历史
shlomi-noach 提交于 2015-11-24 13:12 . GTID:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
/*
Copyright 2014 Outbrain 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 app
import (
"fmt"
"net"
"os"
"os/user"
"regexp"
"strings"
"github.com/outbrain/golib/log"
"github.com/outbrain/golib/util"
"github.com/outbrain/orchestrator/go/config"
"github.com/outbrain/orchestrator/go/db"
"github.com/outbrain/orchestrator/go/inst"
"github.com/outbrain/orchestrator/go/logic"
"github.com/outbrain/orchestrator/go/process"
)
var thisInstanceKey *inst.InstanceKey
var knownCommands []CliCommand
type CliCommand struct {
Command string
Section string
Description string
}
func registerCliCommand(command string, section string, description string) string {
knownCommands = append(knownCommands, CliCommand{Command: command, Section: section, Description: description})
return command
}
func commandsListing() string {
listing := []string{}
lastSection := ""
for _, cliCommand := range knownCommands {
if lastSection != cliCommand.Section {
lastSection = cliCommand.Section
listing = append(listing, fmt.Sprintf("%s:", cliCommand.Section))
}
commandListing := fmt.Sprintf("\t%-40s%s", cliCommand.Command, cliCommand.Description)
listing = append(listing, commandListing)
}
return strings.Join(listing, "\n")
}
func availableCommandsUsage() string {
return fmt.Sprintf(`Available commands (-c):
%+v
Run 'orchestrator' for full blown documentation
Usage for most commands:
orchestrator -c <command> [-i <instance.fqdn>[,<instance.fqdn>]* ] [-d <destination.fqdn>] [--verbose|--debug]
`, commandsListing())
}
func getClusterName(clusterAlias string, instanceKey *inst.InstanceKey) (clusterName string) {
var err error
if clusterAlias != "" {
clusterName, err = inst.ReadClusterByAlias(clusterAlias)
if err != nil {
log.Fatale(err)
}
} else {
// deduce cluster by instance
if instanceKey == nil {
instanceKey = thisInstanceKey
}
if instanceKey == nil {
log.Fatalf("Unable to get cluster instances: unresolved instance")
}
instance, _, err := inst.ReadInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
if instance == nil {
log.Fatalf("Instance not found: %+v", *instanceKey)
}
clusterName = instance.ClusterName
}
if clusterName == "" {
log.Fatalf("Unable to determine cluster name")
}
return clusterName
}
func assignThisInstanceKey() *inst.InstanceKey {
log.Debugf("Assuming instance is this machine, %+v", thisInstanceKey)
return thisInstanceKey
}
// Common code to deduce the instance's instanceKey if not defined.
func deduceInstanceKeyIfNeeded(instance string, instanceKey *inst.InstanceKey) *inst.InstanceKey {
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
return instanceKey
}
// CliWrapper is called from main and allows for the instance parameter
// to take multiple instance names separated by a comma or whitespace.
func CliWrapper(command string, strict bool, instances string, destination string, owner string, reason string, duration string, pattern string, clusterAlias string, pool string, hostnameFlag string) {
r := regexp.MustCompile(`[ ,\r\n\t]+`)
tokens := r.Split(instances, -1)
for _, instance := range tokens {
if instance != "" || len(tokens) == 1 {
Cli(command, strict, instance, destination, owner, reason, duration, pattern, clusterAlias, pool, hostnameFlag)
}
}
}
// Cli initiates a command line interface, executing requested command.
func Cli(command string, strict bool, instance string, destination string, owner string, reason string, duration string, pattern string, clusterAlias string, pool string, hostnameFlag string) {
if instance != "" && !strings.Contains(instance, ":") {
instance = fmt.Sprintf("%s:%d", instance, config.Config.DefaultInstancePort)
}
instanceKey, err := inst.ParseInstanceKey(instance)
if err != nil {
instanceKey = nil
}
rawInstanceKey, err := inst.NewRawInstanceKey(instance)
if err != nil {
rawInstanceKey = nil
}
if destination != "" && !strings.Contains(destination, ":") {
destination = fmt.Sprintf("%s:%d", destination, config.Config.DefaultInstancePort)
}
destinationKey, err := inst.ParseInstanceKey(destination)
if err != nil {
destinationKey = nil
}
if hostname, err := os.Hostname(); err == nil {
thisInstanceKey = &inst.InstanceKey{Hostname: hostname, Port: int(config.Config.DefaultInstancePort)}
}
postponedFunctionsContainer := inst.NewPostponedFunctionsContainer()
if len(owner) == 0 {
// get os username as owner
usr, err := user.Current()
if err != nil {
log.Fatale(err)
}
owner = usr.Username
}
inst.SetMaintenanceOwner(owner)
skipDatabaseCommands := false
switch command {
case "reset-internal-db-deployment":
skipDatabaseCommands = true
case "help":
skipDatabaseCommands = true
}
if !skipDatabaseCommands {
process.ContinuousRegistration(string(process.OrchestratorExecutionCliMode), command)
}
// begin commands
switch command {
// smart mode
case registerCliCommand("relocate", "Smart relocation", `Relocate a slave beneath another instance`), registerCliCommand("relocate-below", "Smart relocation", `Synonym to 'relocate', will be deprecated`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if destinationKey == nil {
log.Fatal("Cannot deduce destination:", destination)
}
_, err := inst.RelocateBelow(instanceKey, destinationKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), destinationKey.DisplayString()))
}
case registerCliCommand("relocate-slaves", "Smart relocation", `Relocates all or part of the slaves of a given instance under another instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if destinationKey == nil {
log.Fatal("Cannot deduce destination:", destination)
}
slaves, _, err, errs := inst.RelocateSlaves(instanceKey, destinationKey, pattern)
if err != nil {
log.Fatale(err)
} else {
for _, e := range errs {
log.Errore(e)
}
for _, slave := range slaves {
fmt.Println(slave.Key.DisplayString())
}
}
}
case registerCliCommand("regroup-slaves", "Smart relocation", `Given an instance, pick one of its slave and make it local master of its siblings`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
lostSlaves, equalSlaves, aheadSlaves, promotedSlave, err := inst.RegroupSlaves(instanceKey, false, func(candidateSlave *inst.Instance) { fmt.Println(candidateSlave.Key.DisplayString()) }, postponedFunctionsContainer)
postponedFunctionsContainer.InvokePostponed()
if promotedSlave == nil {
log.Fatalf("Could not regroup slaves of %+v; error: %+v", *instanceKey, err)
}
fmt.Println(fmt.Sprintf("%s lost: %d, trivial: %d, pseudo-gtid: %d",
promotedSlave.Key.DisplayString(), len(lostSlaves), len(equalSlaves), len(aheadSlaves)))
if err != nil {
log.Fatale(err)
}
}
// General replication commands
// move, binlog file:pos
case registerCliCommand("move-up", "Classic file:pos relocation", `Move a slave one level up the topology`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
instance, err := inst.MoveUp(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), instance.MasterKey.DisplayString()))
}
case registerCliCommand("move-up-slaves", "Classic file:pos relocation", `Moves slaves of the given instance one level up the topology`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
movedSlaves, _, err, errs := inst.MoveUpSlaves(instanceKey, pattern)
if err != nil {
log.Fatale(err)
} else {
for _, e := range errs {
log.Errore(e)
}
for _, slave := range movedSlaves {
fmt.Println(slave.Key.DisplayString())
}
}
}
case registerCliCommand("move-below", "Classic file:pos relocation", `Moves a slave beneath its sibling. Both slaves must be actively replicating from same master.`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if destinationKey == nil {
log.Fatal("Cannot deduce destination/sibling:", destination)
}
_, err := inst.MoveBelow(instanceKey, destinationKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), destinationKey.DisplayString()))
}
case registerCliCommand("move-equivalent", "Classic file:pos relocation", `Moves a slave beneath another server, based on previously recorded "equivalence coordinates"`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if destinationKey == nil {
log.Fatal("Cannot deduce destination:", destination)
}
_, err := inst.MoveEquivalent(instanceKey, destinationKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), destinationKey.DisplayString()))
}
case registerCliCommand("repoint", "Classic file:pos relocation", `Make the given instance replicate from another instance without changing the binglog coordinates. Use with care`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
// destinationKey can be null, in which case the instance repoints to its existing master
instance, err := inst.Repoint(instanceKey, destinationKey, inst.GTIDHintNeutral)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), instance.MasterKey.DisplayString()))
}
case registerCliCommand("repoint-slaves", "Classic file:pos relocation", `Repoint all slaves of given instance to replicate back from the instance. Use with care`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
repointedSlaves, err, errs := inst.RepointSlavesTo(instanceKey, pattern, destinationKey)
if err != nil {
log.Fatale(err)
} else {
for _, e := range errs {
log.Errore(e)
}
for _, slave := range repointedSlaves {
fmt.Println(fmt.Sprintf("%s<%s", slave.Key.DisplayString(), instanceKey.DisplayString()))
}
}
}
case registerCliCommand("enslave-siblings", "Classic file:pos relocation", `Turn all siblings of a slave into its sub-slaves.`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
_, _, err := inst.EnslaveSiblings(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("enslave-master", "Classic file:pos relocation", `Turn an instance into a master of its own master; essentially switch the two.`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
_, err := inst.EnslaveMaster(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("make-co-master", "Classic file:pos relocation", `Create a master-master replication. Given instance is a slave which replicates directly from a master.`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.MakeCoMaster(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("get-candidate-slave", "Classic file:pos relocation", `Information command suggesting the most up-to-date slave of a given instance that is good for promotion`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
instance, _, _, _, err := inst.GetCandidateSlave(instanceKey, false)
if err != nil {
log.Fatale(err)
} else {
fmt.Println(instance.Key.DisplayString())
}
}
case registerCliCommand("regroup-slaves-bls", "Binlog server relocation", `Regroup Binlog Server slaves of a given instance`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
_, promotedBinlogServer, err := inst.RegroupSlavesBinlogServers(instanceKey, false)
if promotedBinlogServer == nil {
log.Fatalf("Could not regroup binlog server slaves of %+v; error: %+v", *instanceKey, err)
}
fmt.Println(promotedBinlogServer.Key.DisplayString())
if err != nil {
log.Fatale(err)
}
}
// move, GTID
case registerCliCommand("move-gtid", "GTID relocation", `Move a slave beneath another instance.`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if destinationKey == nil {
log.Fatal("Cannot deduce destination:", destination)
}
_, err := inst.MoveBelowGTID(instanceKey, destinationKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), destinationKey.DisplayString()))
}
case registerCliCommand("move-slaves-gtid", "GTID relocation", `Moves all slaves of a given instance under another (destination) instance using GTID`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if destinationKey == nil {
log.Fatal("Cannot deduce destination:", destination)
}
movedSlaves, _, err, errs := inst.MoveSlavesGTID(instanceKey, destinationKey, pattern)
if err != nil {
log.Fatale(err)
} else {
for _, e := range errs {
log.Errore(e)
}
for _, slave := range movedSlaves {
fmt.Println(slave.Key.DisplayString())
}
}
}
case registerCliCommand("regroup-slaves-gtid", "GTID relocation", `Given an instance, pick one of its slave and make it local master of its siblings, using GTID.`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
lostSlaves, movedSlaves, promotedSlave, err := inst.RegroupSlavesGTID(instanceKey, false, func(candidateSlave *inst.Instance) { fmt.Println(candidateSlave.Key.DisplayString()) })
if promotedSlave == nil {
log.Fatalf("Could not regroup slaves of %+v; error: %+v", *instanceKey, err)
}
fmt.Println(fmt.Sprintf("%s lost: %d, moved: %d",
promotedSlave.Key.DisplayString(), len(lostSlaves), len(movedSlaves)))
if err != nil {
log.Fatale(err)
}
}
// Pseudo-GTID
case registerCliCommand("match", "Pseudo-GTID relocation", `Matches a slave beneath another (destination) instance using Pseudo-GTID`),
registerCliCommand("match-below", "Pseudo-GTID relocation", `Synonym to 'match', will be deprecated`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if destinationKey == nil {
log.Fatal("Cannot deduce destination:", destination)
}
_, _, err := inst.MatchBelow(instanceKey, destinationKey, true)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), destinationKey.DisplayString()))
}
case registerCliCommand("match-up", "Pseudo-GTID relocation", `Transport the slave one level up the hierarchy, making it child of its grandparent, using Pseudo-GTID`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
instance, _, err := inst.MatchUp(instanceKey, true)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), instance.MasterKey.DisplayString()))
}
case registerCliCommand("rematch", "Pseudo-GTID relocation", `Reconnect a slave onto its master, via PSeudo-GTID.`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
instance, _, err := inst.RematchSlave(instanceKey, true)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%s<%s", instanceKey.DisplayString(), instance.MasterKey.DisplayString()))
}
case registerCliCommand("match-slaves", "Pseudo-GTID relocation", `Matches all slaves of a given instance under another (destination) instance using Pseudo-GTID`),
registerCliCommand("multi-match-slaves", "Pseudo-GTID relocation", `Synonym to 'match-slaves', will be deprecated`):
{
// Move all slaves of "instance" beneath "destination"
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
if destinationKey == nil {
log.Fatal("Cannot deduce destination:", destination)
}
matchedSlaves, _, err, errs := inst.MultiMatchSlaves(instanceKey, destinationKey, pattern)
if err != nil {
log.Fatale(err)
} else {
for _, e := range errs {
log.Errore(e)
}
for _, slave := range matchedSlaves {
fmt.Println(slave.Key.DisplayString())
}
}
}
case registerCliCommand("match-up-slaves", "Pseudo-GTID relocation", `Matches slaves of the given instance one level up the topology, making them siblings of given instance, using Pseudo-GTID`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
matchedSlaves, _, err, errs := inst.MatchUpSlaves(instanceKey, pattern)
if err != nil {
log.Fatale(err)
} else {
for _, e := range errs {
log.Errore(e)
}
for _, slave := range matchedSlaves {
fmt.Println(slave.Key.DisplayString())
}
}
}
case registerCliCommand("regroup-slaves-pgtid", "Pseudo-GTID relocation", `Given an instance, pick one of its slave and make it local master of its siblings, using Pseudo-GTID.`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
lostSlaves, equalSlaves, aheadSlaves, promotedSlave, err := inst.RegroupSlavesPseudoGTID(instanceKey, false, func(candidateSlave *inst.Instance) { fmt.Println(candidateSlave.Key.DisplayString()) }, postponedFunctionsContainer)
postponedFunctionsContainer.InvokePostponed()
if promotedSlave == nil {
log.Fatalf("Could not regroup slaves of %+v; error: %+v", *instanceKey, err)
}
fmt.Println(fmt.Sprintf("%s lost: %d, trivial: %d, pseudo-gtid: %d",
promotedSlave.Key.DisplayString(), len(lostSlaves), len(equalSlaves), len(aheadSlaves)))
if err != nil {
log.Fatale(err)
}
}
// General replication commands
case registerCliCommand("enable-gtid", "Replication, general", `If possible, turn on GTID replication`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.EnableGTID(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("disable-gtid", "Replication, general", `Turn off GTID replication, back to file:pos replication`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.DisableGTID(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("reset-master-gtid-remove-own-uuid", "Replication, general", `Reset master on instance, remove GTID entries generated by instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.ResetMasterGTIDOperation(instanceKey, true, "")
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("skip-query", "Replication, general", `Skip a single statement on a slave; either when running with GTID or without`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.SkipQuery(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("stop-slave", "Replication, general", `Issue a STOP SLAVE on an instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.StopSlave(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("start-slave", "Replication, general", `Issue a START SLAVE on an instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.StartSlave(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("restart-slave", "Replication, general", `STOP and START SLAVE on an instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.RestartSlave(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("reset-slave", "Replication, general", `Issues a RESET SLAVE command; use with care`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.ResetSlaveOperation(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("detach-slave", "Replication, general", `Stops replication and modifies binlog position into an impossible, yet reversible, value.`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.DetachSlaveOperation(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("reattach-slave", "Replication, general", `Undo a detach-slave operation`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.ReattachSlaveOperation(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("detach-slave-master-host", "Replication, general", `Stops replication and modifies Master_Host into an impossible, yet reversible, value.`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
_, err := inst.DetachSlaveMasterHost(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("reattach-slave-master-host", "Replication, general", `Undo a detach-slave-master-host operation`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
_, err := inst.ReattachSlaveMasterHost(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("master-pos-wait", "Replication, general", `Wait until slave reaches given replication coordinates (--binlog=file:pos)`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatalf("Unresolved instance")
}
instance, err := inst.ReadTopologyInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
if instance == nil {
log.Fatalf("Instance not found: %+v", *instanceKey)
}
var binlogCoordinates *inst.BinlogCoordinates
if binlogCoordinates, err = inst.ParseBinlogCoordinates(*config.RuntimeCLIFlags.BinlogFile); err != nil {
log.Fatalf("Expecing --binlog argument as file:pos")
}
_, err = inst.MasterPosWait(instanceKey, binlogCoordinates)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
// Pool
case registerCliCommand("set-read-only", "Instance", `Turn an instance read-only, via SET GLOBAL read_only := 1`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.SetReadOnly(instanceKey, true)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("set-writeable", "Instance", `Turn an instance writeable, via SET GLOBAL read_only := 0`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
_, err := inst.SetReadOnly(instanceKey, false)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
// Binary log operations
case registerCliCommand("flush-binary-logs", "Binary logs", `Flush binary logs on an instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
var err error
if *config.RuntimeCLIFlags.BinlogFile == "" {
_, err = inst.FlushBinaryLogs(instanceKey, 1)
} else {
_, err = inst.FlushBinaryLogsTo(instanceKey, *config.RuntimeCLIFlags.BinlogFile)
}
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("purge-binary-logs", "Binary logs", `Purge binary logs of an instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
var err error
if *config.RuntimeCLIFlags.BinlogFile == "" {
log.Fatal("expecting --binlog value")
}
_, err = inst.PurgeBinaryLogsTo(instanceKey, *config.RuntimeCLIFlags.BinlogFile)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("last-pseudo-gtid", "Binary logs", `Find latest Pseudo-GTID entry in instance's binary logs`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatalf("Unresolved instance")
}
instance, err := inst.ReadTopologyInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
if instance == nil {
log.Fatalf("Instance not found: %+v", *instanceKey)
}
coordinates, text, err := inst.FindLastPseudoGTIDEntry(instance, instance.RelaylogCoordinates, nil, strict, nil)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%+v:%s", *coordinates, text))
}
case registerCliCommand("find-binlog-entry", "Binary logs", `Get binlog file:pos of entry given by --pattern (exact full match, not a regular expression) in a given instance`):
{
if pattern == "" {
log.Fatal("No pattern given")
}
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatalf("Unresolved instance")
}
instance, err := inst.ReadTopologyInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
if instance == nil {
log.Fatalf("Instance not found: %+v", *instanceKey)
}
coordinates, err := inst.SearchEntryInInstanceBinlogs(instance, pattern, false)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%+v", *coordinates))
}
case registerCliCommand("correlate-binlog-pos", "Binary logs", `Given an instance (-i) and binlog coordinates (--binlog=file:pos), find the correlated coordinates in another instance (-d)`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatalf("Unresolved instance")
}
instance, err := inst.ReadTopologyInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
if instance == nil {
log.Fatalf("Instance not found: %+v", *instanceKey)
}
if !instance.LogBinEnabled {
log.Fatalf("Instance does not have binary logs: %+v", *instanceKey)
}
if destinationKey == nil {
log.Fatal("Cannot deduce target instance:", destination)
}
otherInstance, err := inst.ReadTopologyInstance(destinationKey)
if err != nil {
log.Fatale(err)
}
if otherInstance == nil {
log.Fatalf("Instance not found: %+v", *destinationKey)
}
var binlogCoordinates *inst.BinlogCoordinates
if *config.RuntimeCLIFlags.BinlogFile == "" {
binlogCoordinates = &instance.SelfBinlogCoordinates
} else {
if binlogCoordinates, err = inst.ParseBinlogCoordinates(*config.RuntimeCLIFlags.BinlogFile); err != nil {
log.Fatalf("Expecing --binlog argument as file:pos")
}
}
coordinates, _, err := inst.CorrelateBinlogCoordinates(instance, binlogCoordinates, otherInstance)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%+v", *coordinates))
}
// Pool
case registerCliCommand("submit-pool-instances", "Pools", `Submit a pool name with a list of instances in that pool`):
{
if pool == "" {
log.Fatal("Please submit --pool")
}
err := inst.ApplyPoolInstances(pool, instance)
if err != nil {
log.Fatale(err)
}
}
case registerCliCommand("cluster-pool-instances", "Pools", `List all pools and their associated instances`):
{
clusterPoolInstances, err := inst.ReadAllClusterPoolInstances()
if err != nil {
log.Fatale(err)
}
for _, clusterPoolInstance := range clusterPoolInstances {
fmt.Println(fmt.Sprintf("%s\t%s\t%s\t%s:%d", clusterPoolInstance.ClusterName, clusterPoolInstance.ClusterAlias, clusterPoolInstance.Pool, clusterPoolInstance.Hostname, clusterPoolInstance.Port))
}
}
// Information
case registerCliCommand("find", "Information", `Find instances whose hostname matches given regex pattern`):
{
if pattern == "" {
log.Fatal("No pattern given")
}
instances, err := inst.FindInstances(pattern)
if err != nil {
log.Fatale(err)
} else {
for _, instance := range instances {
fmt.Println(instance.Key.DisplayString())
}
}
}
case registerCliCommand("clusters", "Information", `List all clusters known to orchestrator`):
{
clusters, err := inst.ReadClusters()
if err != nil {
log.Fatale(err)
} else {
fmt.Println(strings.Join(clusters, "\n"))
}
}
case registerCliCommand("topology", "Information", `Show an ascii-graph of a replication topology, given a member of that topology`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
output, err := inst.ASCIITopology(instanceKey, pattern)
if err != nil {
log.Fatale(err)
}
fmt.Println(output)
}
case registerCliCommand("which-instance", "Information", `Output the fully-qualified hostname:port representation of the given instance, or error if unknown`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatalf("Unable to get master: unresolved instance")
}
instance, _, err := inst.ReadInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
if instance == nil {
log.Fatalf("Instance not found: %+v", *instanceKey)
}
fmt.Println(instance.Key.DisplayString())
}
case registerCliCommand("which-cluster", "Information", `Output the name of the cluster an instance belongs to, or error if unknown to orchestrator`):
{
clusterName := getClusterName(clusterAlias, instanceKey)
fmt.Println(clusterName)
}
case registerCliCommand("which-cluster-instances", "Information", `Output the list of instances participating in same cluster as given instance`):
{
clusterName := getClusterName(clusterAlias, instanceKey)
instances, err := inst.ReadClusterInstances(clusterName)
if err != nil {
log.Fatale(err)
}
for _, clusterInstance := range instances {
fmt.Println(clusterInstance.Key.DisplayString())
}
}
case registerCliCommand("which-cluster-osc-slaves", "Information", `Output a list of slaves in same cluster as given instance, that could serve as a pt-online-schema-change operation control slaves`):
{
clusterName := getClusterName(clusterAlias, instanceKey)
instances, err := inst.GetClusterOSCSlaves(clusterName)
if err != nil {
log.Fatale(err)
}
for _, clusterInstance := range instances {
fmt.Println(clusterInstance.Key.DisplayString())
}
}
case registerCliCommand("which-master", "Information", `Output the fully-qualified hostname:port representation of a given instance's master`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatalf("Unable to get master: unresolved instance")
}
instance, _, err := inst.ReadInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
if instance == nil {
log.Fatalf("Instance not found: %+v", *instanceKey)
}
fmt.Println(instance.MasterKey.DisplayString())
}
case registerCliCommand("which-slaves", "Information", `Output the fully-qualified hostname:port list of slaves of a given instance`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatalf("Unable to get slaves: unresolved instance")
}
slaves, err := inst.ReadSlaveInstances(instanceKey)
if err != nil {
log.Fatale(err)
}
for _, slave := range slaves {
fmt.Println(slave.Key.DisplayString())
}
}
case registerCliCommand("instance-status", "Information", `Output short status on a given instance`):
{
if instanceKey == nil {
instanceKey = assignThisInstanceKey()
}
if instanceKey == nil {
log.Fatalf("Unable to get status: unresolved instance")
}
instance, _, err := inst.ReadInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
if instance == nil {
log.Fatalf("Instance not found: %+v", *instanceKey)
}
fmt.Println(instance.HumanReadableDescription())
}
case registerCliCommand("get-cluster-heuristic-lag", "Information", `For a given cluster (indicated by an instance or alias), output a heuristic "representative" lag of that cluster`):
{
clusterName := getClusterName(clusterAlias, instanceKey)
lag, err := inst.GetClusterHeuristicLag(clusterName)
if err != nil {
log.Fatale(err)
}
fmt.Println(lag)
}
// Instance management
case registerCliCommand("discover", "Instance management", `Lookup an instance, investigate it`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
instance, err := inst.ReadTopologyInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instance.Key.DisplayString())
}
case registerCliCommand("forget", "Instance management", `Forget about an instance's existence`):
{
if rawInstanceKey == nil {
rawInstanceKey = assignThisInstanceKey()
}
if rawInstanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
err := inst.ForgetInstance(rawInstanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(rawInstanceKey.DisplayString())
}
case registerCliCommand("begin-maintenance", "Instance management", `Request a maintenance lock on an instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if reason == "" {
log.Fatal("--reason option required")
}
var durationSeconds int = 0
if duration != "" {
durationSeconds, err = util.SimpleTimeToSeconds(duration)
if err != nil {
log.Fatale(err)
}
if durationSeconds < 0 {
log.Fatalf("Duration value must be non-negative. Given value: %d", durationSeconds)
}
}
maintenanceKey, err := inst.BeginBoundedMaintenance(instanceKey, inst.GetMaintenanceOwner(), reason, uint(durationSeconds))
if err == nil {
log.Infof("Maintenance key: %+v", maintenanceKey)
log.Infof("Maintenance duration: %d seconds", durationSeconds)
}
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("end-maintenance", "Instance management", `Remove maintenance lock from an instance`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
err := inst.EndMaintenanceByInstanceKey(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("begin-downtime", "Instance management", `Mark an instance as downtimed`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
if reason == "" {
log.Fatal("--reason option required")
}
var durationSeconds int = 0
if duration != "" {
durationSeconds, err = util.SimpleTimeToSeconds(duration)
if err != nil {
log.Fatale(err)
}
if durationSeconds < 0 {
log.Fatalf("Duration value must be non-negative. Given value: %d", durationSeconds)
}
}
err := inst.BeginDowntime(instanceKey, inst.GetMaintenanceOwner(), reason, uint(durationSeconds))
if err == nil {
log.Infof("Downtime duration: %d seconds", durationSeconds)
} else {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("end-downtime", "Instance management", `Indicate an instance is no longer downtimed`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
err := inst.EndDowntime(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
// Recovery & analysis
case registerCliCommand("recover", "Recovery", `Do auto-recovery given a dead instance`), registerCliCommand("recover-lite", "Recovery", `Do auto-recovery given a dead instance. Orchestrator chooses the best course of actionwithout executing external processes`):
{
if instanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
recoveryAttempted, promotedInstanceKey, err := logic.CheckAndRecover(instanceKey, destinationKey, (command == "recover-lite"))
if err != nil {
log.Fatale(err)
}
if recoveryAttempted {
if promotedInstanceKey == nil {
log.Fatalf("Recovery attempted yet no slave promoted")
}
fmt.Println(promotedInstanceKey.DisplayString())
}
}
case registerCliCommand("replication-analysis", "Recovery", `Request an analysis of potential crash incidents in all known topologies`):
{
analysis, err := inst.GetReplicationAnalysis("", false, false)
if err != nil {
log.Fatale(err)
}
for _, entry := range analysis {
fmt.Println(fmt.Sprintf("%s (cluster %s): %s", entry.AnalyzedInstanceKey.DisplayString(), entry.ClusterDetails.ClusterName, entry.Analysis))
}
}
case registerCliCommand("ack-cluster-recoveries", "Recovery", `Acknowledge recoveries for a given cluster; this unblocks pending future recoveries`):
{
if reason == "" {
log.Fatal("--reason option required (comment your ack)")
}
clusterName := getClusterName(clusterAlias, instanceKey)
countRecoveries, err := logic.AcknowledgeClusterRecoveries(clusterName, inst.GetMaintenanceOwner(), reason)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%d recoveries acknowldged", countRecoveries))
}
case registerCliCommand("ack-instance-recoveries", "Recovery", `Acknowledge recoveries for a given instance; this unblocks pending future recoveries`):
{
if reason == "" {
log.Fatal("--reason option required (comment your ack)")
}
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
countRecoveries, err := logic.AcknowledgeInstanceRecoveries(instanceKey, inst.GetMaintenanceOwner(), reason)
if err != nil {
log.Fatale(err)
}
fmt.Println(fmt.Sprintf("%d recoveries acknowldged", countRecoveries))
}
// Instance meta
case registerCliCommand("register-candidate", "Instance, meta", `Indicate that a specific instance is a preferred candidate for master promotion`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
err := inst.RegisterCandidateInstance(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("register-hostname-unresolve", "Instance, meta", `Assigns the given instance a virtual (aka "unresolved") name`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
err := inst.RegisterHostnameUnresolve(instanceKey, hostnameFlag)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
case registerCliCommand("deregister-hostname-unresolve", "Instance, meta", `Explicitly deregister/dosassociate a hostname with an "unresolved" name`):
{
instanceKey = deduceInstanceKeyIfNeeded(instance, instanceKey)
err := inst.DeregisterHostnameUnresolve(instanceKey)
if err != nil {
log.Fatale(err)
}
fmt.Println(instanceKey.DisplayString())
}
// meta
case registerCliCommand("snapshot-topologies", "Meta", `Take a snapshot of existing topologies.`):
{
err := inst.SnapshotTopologies()
if err != nil {
log.Fatale(err)
}
}
case registerCliCommand("continuous", "Meta", `Enter continuous mode, and actively poll for instances, diagnose problems, do maintenance`):
{
logic.ContinuousDiscovery()
}
case registerCliCommand("resolve", "Meta", `Resolve given hostname`):
{
if rawInstanceKey == nil {
log.Fatal("Cannot deduce instance:", instance)
}
if conn, err := net.Dial("tcp", rawInstanceKey.DisplayString()); err == nil {
log.Debugf("tcp test is good; got connection %+v", conn)
conn.Close()
} else {
log.Fatale(err)
}
if cname, err := inst.GetCNAME(rawInstanceKey.Hostname); err == nil {
log.Debugf("GetCNAME() %+v, %+v", cname, err)
rawInstanceKey.Hostname = cname
fmt.Println(rawInstanceKey.DisplayString())
} else {
log.Fatale(err)
}
}
case registerCliCommand("reset-hostname-resolve-cache", "Meta", `Clear the hostname resolve cache`):
{
err := inst.ResetHostnameResolveCache()
if err != nil {
log.Fatale(err)
}
fmt.Println("hostname resolve cache cleared")
}
case registerCliCommand("reset-internal-db-deployment", "Meta, internal", `Clear internal db deployment history, use if somehow corrupted internal deployment history`):
{
config.Config.SkipOrchestratorDatabaseUpdate = true
db.ResetInternalDeployment()
fmt.Println("Internal db deployment history reset. Next orchestrator execution will rebuild internal db structure (no data will be lost)")
}
// Help
case "help":
{
fmt.Fprintf(os.Stderr, availableCommandsUsage())
}
default:
log.Fatalf("Unknown command: \"%s\". %s", command, availableCommandsUsage())
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirrors/orchestrator.git
git@gitee.com:mirrors/orchestrator.git
mirrors
orchestrator
orchestrator
v1.4.548

搜索帮助