github.com/verrazzano/verrazzano-monitoring-operator@v0.0.30/pkg/resources/nodes/nodes.go (about) 1 // Copyright (C) 2022, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package nodes 5 6 import ( 7 "bytes" 8 "fmt" 9 vmcontrollerv1 "github.com/verrazzano/verrazzano-monitoring-operator/pkg/apis/vmcontroller/v1" 10 "github.com/verrazzano/verrazzano-monitoring-operator/pkg/constants" 11 "github.com/verrazzano/verrazzano-monitoring-operator/pkg/resources" 12 "strings" 13 ) 14 15 type NodeCount struct { 16 // amount of nodes with 'master' role 17 MasterNodes int32 18 // amount of nodes with 'ingest' role 19 IngestNodes int32 20 // amount of nodes with 'data' role 21 DataNodes int32 22 // sum of node replicas 23 // this may be greater than the sum of master, data, and ingest, since nodes may have 1-3 roles. 24 Replicas int32 25 } 26 27 var ( 28 RoleMaster = GetRoleLabel(vmcontrollerv1.MasterRole) 29 RoleData = GetRoleLabel(vmcontrollerv1.DataRole) 30 RoleIngest = GetRoleLabel(vmcontrollerv1.IngestRole) 31 RoleAssigned = "true" 32 ) 33 34 // MasterNodes returns the list of master role containing nodes in the VMI spec. These nodes will be created as statefulsets. 35 func MasterNodes(vmo *vmcontrollerv1.VerrazzanoMonitoringInstance) []vmcontrollerv1.ElasticsearchNode { 36 return append([]vmcontrollerv1.ElasticsearchNode{vmo.Spec.Elasticsearch.MasterNode}, filterNodes(vmo, masterNodeMatcher)...) 37 } 38 39 // DataNodes returns the list of data nodes (that are not masters) in the VMI spec. 40 func DataNodes(vmo *vmcontrollerv1.VerrazzanoMonitoringInstance) []vmcontrollerv1.ElasticsearchNode { 41 return append([]vmcontrollerv1.ElasticsearchNode{vmo.Spec.Elasticsearch.DataNode}, filterNodes(vmo, dataNodeMatcher)...) 42 } 43 44 // IngestNodes returns the list of ingest nodes in the VMI spec. These nodes will have no other role but ingest. 45 func IngestNodes(vmo *vmcontrollerv1.VerrazzanoMonitoringInstance) []vmcontrollerv1.ElasticsearchNode { 46 return append([]vmcontrollerv1.ElasticsearchNode{vmo.Spec.Elasticsearch.IngestNode}, filterNodes(vmo, ingestNodeMatcher)...) 47 } 48 49 // GetRolesString turns a nodes role list into a role string 50 // roles: [master, ingest, data] => "master,ingest,data" 51 // we have to use a buffer because NodeRole is a type alias 52 func GetRolesString(node *vmcontrollerv1.ElasticsearchNode) string { 53 var buf bytes.Buffer 54 for idx, role := range node.Roles { 55 buf.WriteString(string(role)) 56 if idx < len(node.Roles)-1 { 57 buf.WriteString(",") 58 } 59 } 60 return buf.String() 61 } 62 63 func GetRoleLabel(role vmcontrollerv1.NodeRole) string { 64 return fmt.Sprintf("opensearch.%s/role-%s", constants.VMOGroup, string(role)) 65 } 66 67 // SetNodeRoleLabels adds node role labels to an existing label map 68 // role labels follow the format: opensearch.verrazzano.io/role-<role name>=true 69 func SetNodeRoleLabels(node *vmcontrollerv1.ElasticsearchNode, labels map[string]string) { 70 for _, role := range node.Roles { 71 labels[GetRoleLabel(role)] = RoleAssigned 72 } 73 } 74 75 // IsSingleNodeCluster Returns true if only a single master node is requested; single-node ES cluster 76 func IsSingleNodeCluster(vmo *vmcontrollerv1.VerrazzanoMonitoringInstance) bool { 77 nodeCount := GetNodeCount(vmo) 78 return nodeCount.MasterNodes == 1 && nodeCount.Replicas == 1 79 } 80 81 // GetNodeCount returns a struct containing the count of nodes of each role type, and the sum of all node replicas. 82 func GetNodeCount(vmo *vmcontrollerv1.VerrazzanoMonitoringInstance) *NodeCount { 83 nodeCount := &NodeCount{} 84 for _, node := range AllNodes(vmo) { 85 nodeCount.Replicas += node.Replicas 86 for _, role := range node.Roles { 87 switch role { 88 case vmcontrollerv1.IngestRole: 89 nodeCount.IngestNodes += node.Replicas 90 case vmcontrollerv1.DataRole: 91 nodeCount.DataNodes += node.Replicas 92 default: 93 nodeCount.MasterNodes += node.Replicas 94 } 95 } 96 } 97 return nodeCount 98 } 99 100 // InitialMasterNodes returns a comma separated list of master nodes for cluster bootstrapping 101 func InitialMasterNodes(vmoName string, masterNodes []vmcontrollerv1.ElasticsearchNode) string { 102 var j int32 103 var initialMasterNodes []string 104 for _, node := range masterNodes { 105 for j = 0; j < node.Replicas; j++ { 106 initialMasterNodes = append(initialMasterNodes, resources.GetMetaName(vmoName, node.Name)+"-"+fmt.Sprintf("%d", j)) 107 } 108 } 109 return strings.Join(initialMasterNodes, ",") 110 } 111 112 // AllNodes returns a list of all nodes that need to be created 113 func AllNodes(vmo *vmcontrollerv1.VerrazzanoMonitoringInstance) []vmcontrollerv1.ElasticsearchNode { 114 return append(vmo.Spec.Elasticsearch.Nodes, vmo.Spec.Elasticsearch.MasterNode, vmo.Spec.Elasticsearch.DataNode, vmo.Spec.Elasticsearch.IngestNode) 115 } 116 117 func filterNodes(vmo *vmcontrollerv1.VerrazzanoMonitoringInstance, matcher func(node vmcontrollerv1.ElasticsearchNode) bool) []vmcontrollerv1.ElasticsearchNode { 118 var nodes []vmcontrollerv1.ElasticsearchNode 119 for _, node := range vmo.Spec.Elasticsearch.Nodes { 120 if matcher(node) { 121 nodes = append(nodes, node) 122 } 123 } 124 return nodes 125 } 126 127 func matcherFactory(excluded, matched func(role vmcontrollerv1.NodeRole) bool) func(node vmcontrollerv1.ElasticsearchNode) bool { 128 return func(node vmcontrollerv1.ElasticsearchNode) bool { 129 var isMatch bool 130 for _, role := range node.Roles { 131 if excluded(role) { 132 return false 133 } 134 if matched(role) { 135 isMatch = true 136 } 137 } 138 return isMatch 139 } 140 } 141 142 var ( 143 // matches any node with master role 144 masterNodeMatcher = matcherFactory(func(role vmcontrollerv1.NodeRole) bool { 145 return false 146 }, func(role vmcontrollerv1.NodeRole) bool { 147 return role == vmcontrollerv1.MasterRole 148 }) 149 // matches nodes with data role, or data + ingest 150 dataNodeMatcher = matcherFactory(func(role vmcontrollerv1.NodeRole) bool { 151 return role == vmcontrollerv1.MasterRole 152 }, func(role vmcontrollerv1.NodeRole) bool { 153 return role == vmcontrollerv1.DataRole 154 }) 155 // Matches only nodes who have ingest role, and nothing else 156 ingestNodeMatcher = matcherFactory(func(role vmcontrollerv1.NodeRole) bool { 157 return role == vmcontrollerv1.MasterRole || role == vmcontrollerv1.DataRole 158 }, func(role vmcontrollerv1.NodeRole) bool { 159 return role == vmcontrollerv1.IngestRole 160 }) 161 )