github.com/pingcap/tiup@v1.15.1/components/dm/command/prune.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package command 15 16 import ( 17 "sync" 18 "time" 19 20 "github.com/pingcap/tiup/components/dm/spec" 21 "github.com/pingcap/tiup/pkg/cluster/api" 22 operator "github.com/pingcap/tiup/pkg/cluster/operation" 23 tidbspec "github.com/pingcap/tiup/pkg/cluster/spec" 24 "github.com/spf13/cobra" 25 "go.uber.org/zap" 26 ) 27 28 func newPruneCmd() *cobra.Command { 29 cmd := &cobra.Command{ 30 Use: "prune <cluster-name>", 31 Short: "Clear etcd info ", 32 RunE: func(cmd *cobra.Command, args []string) error { 33 if len(args) != 1 { 34 return cmd.Help() 35 } 36 37 clusterName := args[0] 38 39 metadata := new(spec.Metadata) 40 err := dmspec.Metadata(clusterName, metadata) 41 if err != nil { 42 return err 43 } 44 45 return clearOutDatedEtcdInfo(clusterName, metadata, gOpt) 46 }, 47 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 48 switch len(args) { 49 case 0: 50 return shellCompGetClusterName(cm, toComplete) 51 default: 52 return nil, cobra.ShellCompDirectiveNoFileComp 53 } 54 }, 55 } 56 57 return cmd 58 } 59 60 func clearOutDatedEtcdInfo(clusterName string, metadata *spec.Metadata, opt operator.Options) error { 61 topo := metadata.Topology 62 63 existedMasters := make(map[string]struct{}) 64 existedWorkers := make(map[string]struct{}) 65 mastersToDelete := make([]string, 0) 66 workersToDelete := make([]string, 0) 67 68 for _, masterSpec := range topo.Masters { 69 existedMasters[masterSpec.Name] = struct{}{} 70 } 71 for _, workerSpec := range topo.Workers { 72 existedWorkers[workerSpec.Name] = struct{}{} 73 } 74 75 tlsCfg, err := topo.TLSConfig(dmspec.Path(clusterName, tidbspec.TLSCertKeyDir)) 76 if err != nil { 77 return err 78 } 79 dmMasterClient := api.NewDMMasterClient(topo.GetMasterListWithManageHost(), 10*time.Second, tlsCfg) 80 registeredMasters, registeredWorkers, err := dmMasterClient.GetRegisteredMembers() 81 if err != nil { 82 return err 83 } 84 85 for _, master := range registeredMasters { 86 if _, ok := existedMasters[master]; !ok { 87 mastersToDelete = append(mastersToDelete, master) 88 } 89 } 90 for _, worker := range registeredWorkers { 91 if _, ok := existedWorkers[worker]; !ok { 92 workersToDelete = append(workersToDelete, worker) 93 } 94 } 95 96 zap.L().Info("Outdated components needed to clear etcd info", zap.Strings("masters", mastersToDelete), zap.Strings("workers", workersToDelete)) 97 98 errCh := make(chan error, len(existedMasters)+len(existedWorkers)) 99 var wg sync.WaitGroup 100 101 for _, master := range mastersToDelete { 102 master := master 103 wg.Add(1) 104 go func() { 105 errCh <- dmMasterClient.OfflineMaster(master, nil) 106 wg.Done() 107 }() 108 } 109 for _, worker := range workersToDelete { 110 worker := worker 111 wg.Add(1) 112 go func() { 113 errCh <- dmMasterClient.OfflineWorker(worker, nil) 114 wg.Done() 115 }() 116 } 117 118 wg.Wait() 119 if len(errCh) == 0 { 120 return nil 121 } 122 123 // return any one error 124 return <-errCh 125 }