func (this *Consumers) cleanupStaleConsumerGroups(zkzone *zk.ZkZone, clusterPattern string) { // what consumer groups are safe to delete? // 1. not online // 2. have no offsets this.Ui.Output(color.Blue(zkzone.Name())) zkzone.ForSortedClusters(func(zkcluster *zk.ZkCluster) { if !patternMatched(zkcluster.Name(), clusterPattern) { return } this.Ui.Output(strings.Repeat(" ", 4) + zkcluster.Name()) consumerGroups := zkcluster.ConsumerGroups() for group, consumers := range consumerGroups { if len(consumers) > 0 { // this consumer group is online continue } if !patternMatched(group, this.groupPattern) { continue } if !strings.HasPrefix(group, "console-consumer-") { path := zkcluster.ConsumerGroupOffsetPath(group) _, _, err := zkzone.Conn().Children(path) if err == nil { this.Ui.Warn(fmt.Sprintf("%s not empty, unsafe to cleanup", path)) continue } if err != gozk.ErrNoNode { // should never happen swallow(err) } } // have no offsets, safe to delete if this.confirmYes { yes, err := this.Ui.Ask(fmt.Sprintf("confirm to remove cluster[%s] consumer group: %s? [Y/n]", zkcluster.Name(), group)) swallow(err) if strings.ToLower(yes) == "n" { this.Ui.Info(fmt.Sprintf("%s skipped", group)) continue } } else { yes, err := this.Ui.Ask(fmt.Sprintf("confirm to remove cluster[%s] consumer group: %s? [y/N]", zkcluster.Name(), group)) swallow(err) if strings.ToLower(yes) != "y" { this.Ui.Info(fmt.Sprintf("%s skipped", group)) continue } } // do delete this consumer group zkzone.DeleteRecursive(zkcluster.ConsumerGroupRoot(group)) this.Ui.Info(fmt.Sprintf("%s deleted", group)) } }) }