Skip to content
This repository was archived by the owner on Apr 7, 2024. It is now read-only.

Commit 3b5b025

Browse files
AlexandrClicksvaroquiemmaloubersac
authored
Itops 300/feature/update repman (#13)
Co-authored-by: apple <[email protected]> Co-authored-by: emma <[email protected]> Co-authored-by: emmaloubersac <[email protected]>
1 parent 13285c7 commit 3b5b025

38 files changed

Lines changed: 713 additions & 279 deletions

arbitrator/arbitrator_cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ func init() {
5656
rootCmd.Flags().StringVar(&conf.KeyPath, "keypath", "/etc/replication-manager/.replication-manager.key", "Encryption key file path")
5757
rootCmd.PersistentFlags().BoolVar(&conf.Verbose, "verbose", false, "Print detailed execution info")
5858
rootCmd.PersistentFlags().StringVar(&memprofile, "memprofile", "/tmp/repmgr.mprof", "Write a memory profile to a file readable by pprof")
59+
rootCmd.PersistentFlags().StringVar(&conf.WorkingDir, "monitoring-datadir", "/var/lib/replication-manager", "Path to write temporary and persistent files")
5960

6061
}
6162

cluster/cluster.go

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ import (
3030
"github.com/signal18/replication-manager/utils/s18log"
3131
"github.com/signal18/replication-manager/utils/state"
3232
log "github.com/sirupsen/logrus"
33-
logsqlerr "github.com/sirupsen/logrus"
34-
logsqlgen "github.com/sirupsen/logrus"
33+
logsql "github.com/sirupsen/logrus"
3534
"golang.org/x/crypto/ssh"
3635
)
3736

@@ -171,6 +170,11 @@ type Cluster struct {
171170
WaitingFailover int `json:"waitingFailover"`
172171
Configurator configurator.Configurator `json:"configurator"`
173172
DiffVariables []VariableDiff `json:"diffVariables"`
173+
inInitNodes bool `json:"-"`
174+
CanInitNodes bool `json:"canInitNodes"`
175+
errorInitNodes error `json:"-"`
176+
SqlErrorLog *logsql.Logger `json:"-"`
177+
SqlGeneralLog *logsql.Logger `json:"-"`
174178
sync.Mutex
175179
crcTable *crc64.Table
176180
}
@@ -251,7 +255,8 @@ const (
251255

252256
// Init initial cluster definition
253257
func (cluster *Cluster) Init(conf config.Config, cfgGroup string, tlog *s18log.TermLog, log *s18log.HttpLog, termlength int, runUUID string, repmgrVersion string, repmgrHostname string, key []byte) error {
254-
258+
cluster.SqlErrorLog = logsql.New()
259+
cluster.SqlGeneralLog = logsql.New()
255260
cluster.crcTable = crc64.MakeTable(crc64.ECMA) // http://golang.org/pkg/hash/crc64/#pkg-constants
256261
cluster.switchoverChan = make(chan bool)
257262
// should use buffered channels or it will block
@@ -263,6 +268,7 @@ func (cluster *Cluster) Init(conf config.Config, cfgGroup string, tlog *s18log.T
263268
cluster.addtableCond = nbc.New()
264269
cluster.altertableCond = nbc.New()
265270
cluster.canFlashBack = true
271+
cluster.CanInitNodes = true
266272
cluster.runOnceAfterTopology = true
267273
cluster.testStopCluster = true
268274
cluster.testStartCluster = true
@@ -309,34 +315,34 @@ func (cluster *Cluster) Init(conf config.Config, cfgGroup string, tlog *s18log.T
309315
MaxSize: cluster.Conf.LogRotateMaxSize,
310316
MaxBackups: cluster.Conf.LogRotateMaxBackup,
311317
MaxAge: cluster.Conf.LogRotateMaxAge,
312-
Level: logsqlerr.DebugLevel,
313-
Formatter: &logsqlerr.TextFormatter{
318+
Level: logsql.DebugLevel,
319+
Formatter: &logsql.TextFormatter{
314320
DisableColors: true,
315321
TimestampFormat: "2006-01-02 15:04:05",
316322
FullTimestamp: true,
317323
},
318324
})
319325
if err != nil {
320-
logsqlerr.WithError(err).Error("Can't init error sql log file")
326+
cluster.SqlErrorLog.WithError(err).Error("Can't init error sql log file")
321327
}
322-
logsqlerr.AddHook(hookerr)
328+
cluster.SqlErrorLog.AddHook(hookerr)
323329

324330
hookgen, err := s18log.NewRotateFileHook(s18log.RotateFileConfig{
325331
Filename: cluster.WorkingDir + "/sql_general.log",
326332
MaxSize: cluster.Conf.LogRotateMaxSize,
327333
MaxBackups: cluster.Conf.LogRotateMaxBackup,
328334
MaxAge: cluster.Conf.LogRotateMaxAge,
329-
Level: logsqlerr.DebugLevel,
330-
Formatter: &logsqlgen.TextFormatter{
335+
Level: logsql.DebugLevel,
336+
Formatter: &logsql.TextFormatter{
331337
DisableColors: true,
332338
TimestampFormat: "2006-01-02 15:04:05",
333339
FullTimestamp: true,
334340
},
335341
})
336342
if err != nil {
337-
logsqlgen.WithError(err).Error("Can't init general sql log file")
343+
cluster.SqlGeneralLog.WithError(err).Error("Can't init general sql log file")
338344
}
339-
logsqlgen.AddHook(hookgen)
345+
cluster.SqlGeneralLog.AddHook(hookgen)
340346
cluster.LoadAPIUsers()
341347
// createKeys do nothing yet
342348
cluster.createKeys()
@@ -359,18 +365,25 @@ func (cluster *Cluster) Init(conf config.Config, cfgGroup string, tlog *s18log.T
359365

360366
return nil
361367
}
368+
362369
func (cluster *Cluster) initOrchetratorNodes() {
370+
if cluster.inInitNodes {
371+
return
372+
}
373+
cluster.inInitNodes = true
374+
defer func() { cluster.inInitNodes = false }()
363375

376+
//defer cluster.insideInitNodes = false
364377
//cluster.LogPrintf(LvlInfo, "Loading nodes from orchestrator %s", cluster.Conf.ProvOrchestrator)
365378
switch cluster.GetOrchestrator() {
366379
case config.ConstOrchestratorOpenSVC:
367-
cluster.Agents, _ = cluster.OpenSVCGetNodes()
380+
cluster.Agents, cluster.errorInitNodes = cluster.OpenSVCGetNodes()
368381
case config.ConstOrchestratorKubernetes:
369-
cluster.Agents, _ = cluster.K8SGetNodes()
382+
cluster.Agents, cluster.errorInitNodes = cluster.K8SGetNodes()
370383
case config.ConstOrchestratorSlapOS:
371-
cluster.Agents, _ = cluster.SlapOSGetNodes()
384+
cluster.Agents, cluster.errorInitNodes = cluster.SlapOSGetNodes()
372385
case config.ConstOrchestratorLocalhost:
373-
cluster.Agents, _ = cluster.LocalhostGetNodes()
386+
cluster.Agents, cluster.errorInitNodes = cluster.LocalhostGetNodes()
374387
case config.ConstOrchestratorOnPremise:
375388
default:
376389
log.Fatalln("prov-orchestrator not supported", cluster.Conf.ProvOrchestrator)
@@ -424,8 +437,8 @@ func (cluster *Cluster) Run() {
424437
for k, v := range cluster.Servers {
425438
cluster.LogPrintf(LvlDbg, "Server [%d]: URL: %-15s State: %6s PrevState: %6s", k, v.URL, v.State, v.PrevState)
426439
}
427-
if cluster.master != nil {
428-
cluster.LogPrintf(LvlDbg, "Master [ ]: URL: %-15s State: %6s PrevState: %6s", cluster.master.URL, cluster.master.State, cluster.master.PrevState)
440+
if cluster.GetMaster() != nil {
441+
cluster.LogPrintf(LvlDbg, "Master [ ]: URL: %-15s State: %6s PrevState: %6s", cluster.master.URL, cluster.GetMaster().State, cluster.GetMaster().PrevState)
429442
for k, v := range cluster.slaves {
430443
cluster.LogPrintf(LvlDbg, "Slave [%d]: URL: %-15s State: %6s PrevState: %6s", k, v.URL, v.State, v.PrevState)
431444
}
@@ -444,7 +457,7 @@ func (cluster *Cluster) Run() {
444457
if !cluster.IsInFailover() {
445458
cluster.initProxies()
446459
}
447-
cluster.initOrchetratorNodes()
460+
go cluster.initOrchetratorNodes()
448461
cluster.ResticFetchRepo()
449462
cluster.runOnceAfterTopology = false
450463
} else {
@@ -461,7 +474,7 @@ func (cluster *Cluster) Run() {
461474
cluster.InjectProxiesTraffic()
462475
}
463476
if cluster.sme.GetHeartbeats()%30 == 0 {
464-
cluster.initOrchetratorNodes()
477+
go cluster.initOrchetratorNodes()
465478
cluster.MonitorQueryRules()
466479
cluster.MonitorVariablesDiff()
467480
cluster.ResticFetchRepo()
@@ -471,9 +484,12 @@ func (cluster *Cluster) Run() {
471484
cluster.sme.PreserveState("WARN0093")
472485
cluster.sme.PreserveState("WARN0084")
473486
cluster.sme.PreserveState("WARN0095")
474-
cluster.sme.PreserveState("ERR00082")
475487
cluster.sme.PreserveState("WARN0101")
476488
}
489+
if !cluster.CanInitNodes {
490+
cluster.SetState("ERR00082", state.State{ErrType: "WARNING", ErrDesc: fmt.Sprintf(clusterError["ERR00082"], cluster.errorInitNodes), ErrFrom: "OPENSVC"})
491+
}
492+
477493
if cluster.sme.GetHeartbeats()%36000 == 0 {
478494
cluster.ResticPurgeRepo()
479495
} else {
@@ -561,8 +577,13 @@ func (cluster *Cluster) StateProcessing() {
561577
}
562578
// cluster.statecloseChan <- s
563579
}
580+
var states []string
581+
if cluster.runOnceAfterTopology {
582+
states = cluster.sme.GetFirstStates()
564583

565-
states := cluster.sme.GetStates()
584+
} else {
585+
states = cluster.sme.GetStates()
586+
}
566587
for i := range states {
567588
cluster.LogPrintf("STATE", states[i])
568589
}
@@ -573,7 +594,9 @@ func (cluster *Cluster) StateProcessing() {
573594
}
574595

575596
for _, s := range cluster.sme.GetLastOpenedStates() {
597+
576598
cluster.CheckAlert(s)
599+
577600
}
578601

579602
cluster.sme.ClearState()
@@ -715,7 +738,7 @@ func (cluster *Cluster) FailoverForce() error {
715738

716739
}
717740
}
718-
if cluster.master == nil {
741+
if cluster.GetMaster() == nil {
719742
cluster.LogPrintf(LvlErr, "Could not find a failed server in the hosts list")
720743
return errors.New("ERROR: Could not find a failed server in the hosts list")
721744
}
@@ -861,21 +884,21 @@ func (cluster *Cluster) MonitorSchema() {
861884
if !cluster.Conf.MonitorSchemaChange {
862885
return
863886
}
864-
if cluster.master == nil {
887+
if cluster.GetMaster() == nil {
865888
return
866889
}
867-
if cluster.master.State == stateFailed || cluster.master.State == stateMaintenance || cluster.master.State == stateUnconn {
890+
if cluster.GetMaster().State == stateFailed || cluster.GetMaster().State == stateMaintenance || cluster.GetMaster().State == stateUnconn {
868891
return
869892
}
870-
if cluster.master.Conn == nil {
893+
if cluster.GetMaster().Conn == nil {
871894
return
872895
}
873896
cluster.sme.SetMonitorSchemaState()
874-
cluster.master.Conn.SetConnMaxLifetime(3595 * time.Second)
897+
cluster.GetMaster().Conn.SetConnMaxLifetime(3595 * time.Second)
875898

876-
tables, tablelist, logs, err := dbhelper.GetTables(cluster.master.Conn, cluster.master.DBVersion)
877-
cluster.LogSQL(logs, err, cluster.master.URL, "Monitor", LvlErr, "Could not fetch master tables %s", err)
878-
cluster.master.Tables = tablelist
899+
tables, tablelist, logs, err := dbhelper.GetTables(cluster.GetMaster().Conn, cluster.GetMaster().DBVersion)
900+
cluster.LogSQL(logs, err, cluster.GetMaster().URL, "Monitor", LvlErr, "Could not fetch master tables %s", err)
901+
cluster.GetMaster().Tables = tablelist
879902

880903
var tableCluster []string
881904
var duplicates []*ServerMonitor
@@ -889,7 +912,7 @@ func (cluster *Cluster) MonitorSchema() {
889912

890913
duplicates = append(duplicates, cluster.GetMaster())
891914
tableCluster = append(tableCluster, cluster.GetName())
892-
oldtable, err := cluster.master.GetTableFromDict(t.TableSchema + "." + t.TableName)
915+
oldtable, err := cluster.GetMaster().GetTableFromDict(t.TableSchema + "." + t.TableName)
893916
haschanged := false
894917
if err != nil {
895918
if err.Error() == "Empty" {
@@ -936,7 +959,7 @@ func (cluster *Cluster) MonitorSchema() {
936959
}
937960
cluster.DBIndexSize = totindexsize
938961
cluster.DBTableSize = tottablesize
939-
cluster.master.DictTables = tables
962+
cluster.GetMaster().DictTables = tables
940963
cluster.sme.RemoveMonitorSchemaState()
941964
}
942965

@@ -993,7 +1016,7 @@ func (cluster *Cluster) LostArbitration(realmasterurl string) {
9931016
}
9941017
if cluster.Conf.ArbitrationFailedMasterScript != "" {
9951018
cluster.LogPrintf(LvlInfo, "Calling abitration failed for master script")
996-
out, err := exec.Command(cluster.Conf.ArbitrationFailedMasterScript, cluster.master.Host, cluster.master.Port).CombinedOutput()
1019+
out, err := exec.Command(cluster.Conf.ArbitrationFailedMasterScript, cluster.GetMaster().Host, cluster.GetMaster().Port).CombinedOutput()
9971020
if err != nil {
9981021
cluster.LogPrintf(LvlErr, "%s", err)
9991022
}

cluster/cluster_chk.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func (cluster *Cluster) isMasterFailed() bool {
130130
func (cluster *Cluster) isMaxMasterFailedCountReached() bool {
131131
// no illimited failed count
132132

133-
if cluster.master.FailCount >= cluster.Conf.MaxFail {
133+
if cluster.GetMaster().FailCount >= cluster.Conf.MaxFail {
134134
cluster.sme.AddState("WARN0023", state.State{ErrType: "WARNING", ErrDesc: fmt.Sprintf(clusterError["WARN0023"]), ErrFrom: "CHECK"})
135135
return true
136136
} else {
@@ -256,6 +256,9 @@ func (cluster *Cluster) isMaxscaleSupectRunning() bool {
256256
}
257257

258258
func (cluster *Cluster) isFoundCandidateMaster() bool {
259+
if cluster.GetTopology() == topoActivePassive {
260+
return true
261+
}
259262
key := -1
260263
if cluster.Conf.MultiMasterGrouprep {
261264
key = cluster.electSwitchoverGroupReplicationCandidate(cluster.slaves, true)

cluster/cluster_fail.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,12 @@ func (cluster *Cluster) MasterFailover(fail bool) bool {
343343
}
344344

345345
if cluster.Conf.ReadOnly {
346-
logs, err = dbhelper.SetReadOnly(cluster.oldMaster.Conn, true)
346+
logs, err = cluster.oldMaster.SetReadOnly()
347347
cluster.LogSQL(logs, err, cluster.oldMaster.URL, "MasterFailover", LvlErr, "Could not set old master as read-only, %s", err)
348-
349-
} else {
350-
logs, err = dbhelper.SetReadOnly(cluster.oldMaster.Conn, false)
351-
cluster.LogSQL(logs, err, cluster.oldMaster.URL, "MasterFailover", LvlErr, "Could not set old master as read-write, %s", err)
348+
/* } else {
349+
logs, err = cluster.oldMaster.SetReadWrite()
350+
cluster.LogSQL(logs, err, cluster.oldMaster.URL, "MasterFailover", LvlErr, "Could not set old master as read-write, %s", err)
351+
*/
352352
}
353353
if cluster.Conf.SwitchDecreaseMaxConn {
354354

@@ -1216,7 +1216,7 @@ func (cluster *Cluster) VMasterFailover(fail bool) bool {
12161216
cluster.failoverPreScript(fail)
12171217

12181218
// Phase 2: Reject updates and sync slaves on switchover
1219-
if fail == false {
1219+
if fail == false && cluster.GetTopology() != topoMultiMasterWsrep {
12201220
cluster.LogPrintf(LvlInfo, "Rejecting updates on %s (old master)", cluster.oldMaster.URL)
12211221
cluster.oldMaster.freeze()
12221222
}
@@ -1323,7 +1323,8 @@ func (cluster *Cluster) VMasterFailover(fail bool) bool {
13231323
cluster.LogPrintf(LvlErr, "Could not set old master as read-write, %s", err)
13241324
}
13251325
}
1326-
if cluster.Conf.SwitchDecreaseMaxConn {
1326+
// Galara does not freeze old master because of bug https://jira.mariadb.org/browse/MDEV-9134
1327+
if cluster.Conf.SwitchDecreaseMaxConn && cluster.GetTopology() != topoMultiMasterWsrep {
13271328
logs, err := dbhelper.SetMaxConnections(cluster.oldMaster.Conn, cluster.oldMaster.maxConn, cluster.oldMaster.DBVersion)
13281329
cluster.LogSQL(logs, err, cluster.oldMaster.URL, "MasterFailover", LvlErr, "Could not set max connections on %s %s", cluster.oldMaster.URL, err)
13291330
}

cluster/cluster_get.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,14 @@ func (cluster *Cluster) GetGComm() string {
296296
} else {
297297
gcomms = append(gcomms, server.Host+":"+strconv.Itoa(cluster.Conf.MultiMasterGrouprepPort))
298298
}
299+
300+
}
301+
// For bootrap galera cluster on first node
302+
if cluster.AllServersFailed() && cluster.GetTopology() == topoMultiMasterWsrep {
303+
return ""
304+
}
305+
if cluster.GetTopology() == topoMultiMasterWsrep {
306+
return strings.Join(gcomms, ",") + "?pc.wait_prim=yes"
299307
}
300308
return strings.Join(gcomms, ",")
301309
}
@@ -308,7 +316,7 @@ func (cluster *Cluster) getOnePreferedMaster() *ServerMonitor {
308316
if cluster.Conf.LogLevel > 2 {
309317
cluster.LogPrintf(LvlDbg, "Lookup if server: %s is preferred master: %s", server.URL, cluster.Conf.PrefMaster)
310318
}
311-
if strings.Contains(cluster.Conf.PrefMaster, server.URL) {
319+
if server.IsPrefered() {
312320
return server
313321
}
314322
}
@@ -514,6 +522,8 @@ func (cluster *Cluster) GetTopology() string {
514522
} else if cluster.Conf.MasterSlavePgLogical {
515523
cluster.Conf.Topology = topoMasterSlavePgLog
516524
cluster.IsPostgres = true
525+
} else if cluster.Conf.ActivePassive {
526+
cluster.Conf.Topology = topoActivePassive
517527
} else {
518528
relay := cluster.GetRelayServer()
519529
if relay != nil && cluster.Conf.ReplicationNoRelay == false {

cluster/cluster_has.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,29 @@ func (cluster *Cluster) HasAllDbUp() bool {
166166
return true
167167
}
168168

169+
func (cluster *Cluster) HasNoDbUnconnected() bool {
170+
if cluster.Servers == nil {
171+
return false
172+
}
173+
for _, s := range cluster.Servers {
174+
if s != nil {
175+
if s.State == stateFailed || s.State == stateUnconn /*&& misc.Contains(cluster.ignoreList, s.URL) == false*/ {
176+
return false
177+
}
178+
if s.State == stateSuspect && cluster.GetTopology() != topoUnknown {
179+
//supect is used to reload config and avoid backend state change to failed that would disable servers in proxies and cause glinch in cluster traffic
180+
// at the same time to enbale bootstrap replication we need to know when server are up
181+
return false
182+
}
183+
if s.Conn == nil {
184+
return false
185+
}
186+
}
187+
}
188+
189+
return true
190+
}
191+
169192
func (cluster *Cluster) HasRequestDBRestart() bool {
170193
if cluster.Servers == nil {
171194
return false

0 commit comments

Comments
 (0)