github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/lorry/operations/switchover.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package operations 21 22 import ( 23 "context" 24 "fmt" 25 26 "github.com/pkg/errors" 27 28 "github.com/1aal/kubeblocks/pkg/lorry/dcs" 29 "github.com/1aal/kubeblocks/pkg/lorry/engines/register" 30 ) 31 32 type Switchover struct { 33 Base 34 dcsStore dcs.DCS 35 } 36 37 var switchover Operation = &Switchover{} 38 39 func init() { 40 err := Register("switchover", switchover) 41 if err != nil { 42 panic(err.Error()) 43 } 44 } 45 46 func (s *Switchover) Init(ctx context.Context) error { 47 s.dcsStore = dcs.GetStore() 48 if s.dcsStore == nil { 49 return errors.New("dcs store init failed") 50 } 51 52 return nil 53 } 54 55 func (s *Switchover) PreCheck(ctx context.Context, req *OpsRequest) error { 56 primary := req.Parameters["primary"].(string) 57 candidate := req.Parameters["candidate"].(string) 58 if primary == "" && candidate == "" { 59 return errors.New("primary or candidate must be set") 60 } 61 62 cluster, err := s.dcsStore.GetCluster() 63 if cluster == nil { 64 return errors.Wrap(err, "get cluster failed") 65 } 66 67 manager, err := register.GetDBManager() 68 if err != nil { 69 return errors.Wrap(err, "get manager failed") 70 } 71 72 if primary != "" { 73 leaderMember := cluster.GetMemberWithName(primary) 74 if leaderMember == nil { 75 message := fmt.Sprintf("primary %s not exists", primary) 76 return errors.New(message) 77 } 78 79 if ok, err := manager.IsLeaderMember(ctx, cluster, leaderMember); err != nil || !ok { 80 message := fmt.Sprintf("%s is not the primary", primary) 81 return errors.New(message) 82 } 83 } 84 85 if candidate != "" { 86 candidateMember := cluster.GetMemberWithName(candidate) 87 if candidateMember == nil { 88 message := fmt.Sprintf("candidate %s not exists", candidate) 89 return errors.New(message) 90 } 91 92 if !manager.IsMemberHealthy(ctx, cluster, candidateMember) { 93 message := fmt.Sprintf("candidate %s is unhealthy", candidate) 94 return errors.New(message) 95 } 96 } else if len(manager.HasOtherHealthyMembers(ctx, cluster, primary)) == 0 { 97 return errors.New("candidate is not set and has no other healthy members") 98 } 99 100 return nil 101 } 102 103 func (s *Switchover) Do(ctx context.Context, req *OpsRequest) (*OpsResponse, error) { 104 primary := req.Parameters["primary"].(string) 105 candidate := req.Parameters["candidate"].(string) 106 err := s.dcsStore.CreateSwitchover(primary, candidate) 107 if err != nil { 108 message := fmt.Sprintf("Create switchover failed: %v", err) 109 return nil, errors.New(message) 110 } 111 112 return nil, nil 113 }