func (n Nodes) FilterByFunc(fn func(*Node) bool) Nodes {
	newSlice := Nodes{}
	for _, node := range n {
		if fn(node) {
			newSlice = append(newSlice, node)
		}
	}
	return newSlice
}
FilterByFunc remove a node from a slice by node ID and returns the slice. If not found, fail silently. Value must be unique
package redisutil
import (
	"errors"
	"fmt"
	"net"
	"sort"
	"strings"
	"time"
	corev1 "k8s.io/api/core/v1"
	redisv1alpha1 "github.com/ucloud/redis-cluster-operator/pkg/apis/redis/v1alpha1"
	"github.com/ucloud/redis-cluster-operator/pkg/utils"
)
const (
	DefaultRedisPort = "6379"
	RedisMasterRole = "master"
	RedisSlaveRole = "slave"
)
const (
	RedisLinkStateConnected = "connected"
	RedisLinkStateDisconnected = "disconnected"
)
const (
	NodeStatusPFail = "fail?"
	NodeStatusFail = "fail"
	NodeStatusHandshake = "handshake"
	NodeStatusNoAddr = "noaddr"
	NodeStatusNoFlags = "noflags"
)
type Node struct {
	ID              string
	IP              string
	Port            string
	Role            string
	LinkState       string
	MasterReferent  string
	FailStatus      []string
	PingSent        int64
	PongRecv        int64
	ConfigEpoch     int64
	Slots           []Slot
	balance         int
	MigratingSlots  map[Slot]string
	ImportingSlots  map[Slot]string
	ServerStartTime time.Time
	NodeName    string
	PodName     string
	StatefulSet string
}
type Nodes []*Node
func (n Nodes) String() string {
	stringer := []utils.Stringer{}
	for _, node := range n {
		stringer = append(stringer, node)
	}
	return utils.SliceJoin(stringer, ",")
}
func NewDefaultNode() *Node {
	return &Node{
		Port:           DefaultRedisPort,
		Slots:          []Slot{},
		MigratingSlots: map[Slot]string{},
		ImportingSlots: map[Slot]string{},
	}
}
func NewNode(id, ip string, pod *corev1.Pod) *Node {
	node := NewDefaultNode()
	node.ID = id
	node.IP = ip
	node.PodName = pod.Name
	node.NodeName = pod.Spec.NodeName
	return node
}
func (n *Node) SetRole(flags string) error {
	n.Role = ""  
	vals := strings.Split(flags, ",")
	for _, val := range vals {
		switch val {
		case RedisMasterRole:
			n.Role = RedisMasterRole
		case RedisSlaveRole:
			n.Role = RedisSlaveRole
		}
	}
	if n.Role == "" {
		return errors.New("node setRole failed")
	}
	return nil
}
func (n *Node) GetRole() redisv1alpha1.RedisRole {
	switch n.Role {
	case RedisMasterRole:
		return redisv1alpha1.RedisClusterNodeRoleMaster
	case RedisSlaveRole:
		return redisv1alpha1.RedisClusterNodeRoleSlave
	default:
		if n.MasterReferent != "" {
			return redisv1alpha1.RedisClusterNodeRoleSlave
		}
		if len(n.Slots) > 0 {
			return redisv1alpha1.RedisClusterNodeRoleMaster
		}
	}
	return redisv1alpha1.RedisClusterNodeRoleNone
}
func (n *Node) String() string {
	if n.ServerStartTime.IsZero() {
		return fmt.Sprintf("{Redis ID: %s, role: %s, master: %s, link: %s, status: %s, addr: %s, slots: %s, len(migratingSlots): %d, len(importingSlots): %d}", n.ID, n.GetRole(), n.MasterReferent, n.LinkState, n.FailStatus, n.IPPort(), SlotSlice(n.Slots), len(n.MigratingSlots), len(n.ImportingSlots))
	}
	return fmt.Sprintf("{Redis ID: %s, role: %s, master: %s, link: %s, status: %s, addr: %s, slots: %s, len(migratingSlots): %d, len(importingSlots): %d, ServerStartTime: %s}", n.ID, n.GetRole(), n.MasterReferent, n.LinkState, n.FailStatus, n.IPPort(), SlotSlice(n.Slots), len(n.MigratingSlots), len(n.ImportingSlots), n.ServerStartTime.Format("2006-01-02 15:04:05"))
}
func (n *Node) IPPort() string {
	return net.JoinHostPort(n.IP, n.Port)
}
func (n Nodes) GetNodesByFunc(f FindNodeFunc) (Nodes, error) {
	nodes := Nodes{}
	for _, node := range n {
		if f(node) {
			nodes = append(nodes, node)
		}
	}
	if len(nodes) == 0 {
		return nodes, nodeNotFoundedError
	}
	return nodes, nil
}
func (n *Node) ToAPINode() redisv1alpha1.RedisClusterNode {
	apiNode := redisv1alpha1.RedisClusterNode{
		ID:      n.ID,
		IP:      n.IP,
		PodName: n.PodName,
		Role:    n.GetRole(),
		Slots:   []string{},
	}
	return apiNode
}
func (n *Node) Clear() {
}
func (n *Node) Balance() int {
	return n.balance
}
func (n *Node) SetBalance(balance int) {
	n.balance = balance
}
func (n *Node) SetLinkStatus(status string) error {
	n.LinkState = ""  
	switch status {
	case RedisLinkStateConnected:
		n.LinkState = RedisLinkStateConnected
	case RedisLinkStateDisconnected:
		n.LinkState = RedisLinkStateDisconnected
	}
	if n.LinkState == "" {
		return errors.New("Node SetLinkStatus failed")
	}
	return nil
}
func (n *Node) SetFailureStatus(flags string) {
	n.FailStatus = []string{}  
	vals := strings.Split(flags, ",")
	for _, val := range vals {
		switch val {
		case NodeStatusFail:
			n.FailStatus = append(n.FailStatus, NodeStatusFail)
		case NodeStatusPFail:
			n.FailStatus = append(n.FailStatus, NodeStatusPFail)
		case NodeStatusHandshake:
			n.FailStatus = append(n.FailStatus, NodeStatusHandshake)
		case NodeStatusNoAddr:
			n.FailStatus = append(n.FailStatus, NodeStatusNoAddr)
		case NodeStatusNoFlags:
			n.FailStatus = append(n.FailStatus, NodeStatusNoFlags)
		}
	}
}
func (n *Node) SetReferentMaster(ref string) {
	n.MasterReferent = ""
	if ref == "-" {
		return
	}
	n.MasterReferent = ref
}
func (n *Node) TotalSlots() int {
	return len(n.Slots)
}
func (n *Node) HasStatus(flag string) bool {
	for _, status := range n.FailStatus {
		if status == flag {
			return true
		}
	}
	return false
}
var IsMasterWithNoSlot = func(n *Node) bool {
	if (n.GetRole() == redisv1alpha1.RedisClusterNodeRoleMaster) && (n.TotalSlots() == 0) {
		return true
	}
	return false
}
var IsMasterWithSlot = func(n *Node) bool {
	if (n.GetRole() == redisv1alpha1.RedisClusterNodeRoleMaster) && (n.TotalSlots() > 0) {
		return true
	}
	return false
}
var IsSlave = func(n *Node) bool {
	return n.GetRole() == redisv1alpha1.RedisClusterNodeRoleSlave
}
func (n Nodes) SortNodes() Nodes {
	sort.Sort(n)
	return n
}
func (n Nodes) GetNodeByID(id string) (*Node, error) {
	for _, node := range n {
		if node.ID == id {
			return node, nil
		}
	}
	return nil, nodeNotFoundedError
}
func (n Nodes) CountByFunc(fn func(*Node) bool) (result int) {
	for _, v := range n {
		if fn(v) {
			result++
		}
	}
	return
}