Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pod_owner label to metrics when -spire-agent-address is set #1137

Merged
merged 1 commit into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cmd/nginx-ingress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ func main() {
StubStatusOverUnixSocketForOSS: *enablePrometheusMetrics,
TLSPassthrough: *enableTLSPassthrough,
EnableSnippets: *enableSnippets,
SpiffeCerts: *spireAgentAddress != "",
NginxServiceMesh: *spireAgentAddress != "",
MainAppProtectLoadModule: *appProtect,
EnableLatencyMetrics: *enableLatencyMetrics,
}
Expand Down Expand Up @@ -548,6 +548,9 @@ func main() {
if *enablePrometheusMetrics {
upstreamServerVariableLabels := []string{"service", "resource_type", "resource_name", "resource_namespace"}
upstreamServerPeerVariableLabelNames := []string{"pod_name"}
if staticCfgParams.NginxServiceMesh {
upstreamServerPeerVariableLabelNames = append(upstreamServerPeerVariableLabelNames, "pod_owner")
}
if *nginxPlus {
serverZoneVariableLabels := []string{"resource_type", "resource_name", "resource_namespace"}
variableLabelNames := nginxCollector.NewVariableLabelNames(upstreamServerVariableLabels, serverZoneVariableLabels, upstreamServerPeerVariableLabelNames)
Expand Down
2 changes: 1 addition & 1 deletion internal/configs/config_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ type StaticConfigParams struct {
StubStatusOverUnixSocketForOSS bool
TLSPassthrough bool
EnableSnippets bool
SpiffeCerts bool
NginxServiceMesh bool
EnableInternalRoutes bool
MainAppProtectLoadModule bool
PodName string
Expand Down
16 changes: 12 additions & 4 deletions internal/configs/configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,13 @@ func (cnf *Configurator) updateIngressMetricsLabels(ingEx *IngressEx, upstreams
newUpstreamsNames = append(newUpstreamsNames, u.Name)
for _, server := range u.UpstreamServers {
s := fmt.Sprintf("%v:%v", server.Address, server.Port)
podName := ingEx.PodsByIP[s]
podInfo := ingEx.PodsByIP[s]
labelKey := fmt.Sprintf("%v/%v", u.Name, s)
upstreamServerPeerLabels[labelKey] = []string{podName}
upstreamServerPeerLabels[labelKey] = []string{podInfo.Name}
if cnf.staticCfgParams.NginxServiceMesh {
ownerLabelVal := fmt.Sprintf("%s/%s", podInfo.OwnerType, podInfo.OwnerName)
upstreamServerPeerLabels[labelKey] = append(upstreamServerPeerLabels[labelKey], ownerLabelVal)
}
newPeers[labelKey] = true
newPeersIPs = append(newPeersIPs, labelKey)
}
Expand Down Expand Up @@ -314,9 +318,13 @@ func (cnf *Configurator) updateVirtualServerMetricsLabels(virtualServerEx *Virtu
newUpstreams[u.Name] = true
newUpstreamsNames = append(newUpstreamsNames, u.Name)
for _, server := range u.Servers {
podName := virtualServerEx.PodsByIP[server.Address]
podInfo := virtualServerEx.PodsByIP[server.Address]
labelKey := fmt.Sprintf("%v/%v", u.Name, server.Address)
upstreamServerPeerLabels[labelKey] = []string{podName}
upstreamServerPeerLabels[labelKey] = []string{podInfo.Name}
if cnf.staticCfgParams.NginxServiceMesh {
ownerLabelVal := fmt.Sprintf("%s/%s", podInfo.OwnerType, podInfo.OwnerName)
upstreamServerPeerLabels[labelKey] = append(upstreamServerPeerLabels[labelKey], ownerLabelVal)
}
newPeers[labelKey] = true
newPeersIPs = append(newPeersIPs, labelKey)
}
Expand Down
12 changes: 6 additions & 6 deletions internal/configs/configurator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -640,9 +640,9 @@ func TestUpdateIngressMetricsLabels(t *testing.T) {
},
},
},
PodsByIP: map[string]string{
"10.0.0.1:80": "pod-1",
"10.0.0.2:80": "pod-2",
PodsByIP: map[string]PodInfo{
"10.0.0.1:80": {Name: "pod-1"},
"10.0.0.2:80": {Name: "pod-2"},
},
}

Expand Down Expand Up @@ -800,9 +800,9 @@ func TestUpdateVirtualServerMetricsLabels(t *testing.T) {
Host: "example.com",
},
},
PodsByIP: map[string]string{
"10.0.0.1:80": "pod-1",
"10.0.0.2:80": "pod-2",
PodsByIP: map[string]PodInfo{
"10.0.0.1:80": {Name: "pod-1"},
"10.0.0.2:80": {Name: "pod-2"},
},
}

Expand Down
8 changes: 4 additions & 4 deletions internal/configs/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type IngressEx struct {
Endpoints map[string][]string
HealthChecks map[string]*api_v1.Probe
ExternalNameSvcs map[string]bool
PodsByIP map[string]string
PodsByIP map[string]PodInfo
AppProtectPolicy *unstructured.Unstructured
AppProtectLogConf *unstructured.Unstructured
AppProtectLogDst string
Expand Down Expand Up @@ -250,7 +250,7 @@ func generateNginxCfg(ingEx *IngressEx, pems map[string]string, apResources map[
Namespace: ingEx.Ingress.Namespace,
Annotations: ingEx.Ingress.Annotations,
},
SpiffeClientCerts: staticParams.SpiffeCerts && !cfgParams.SpiffeServerCerts,
SpiffeClientCerts: staticParams.NginxServiceMesh && !cfgParams.SpiffeServerCerts,
}
}

Expand Down Expand Up @@ -478,10 +478,10 @@ func generateNginxCfgForMergeableIngresses(mergeableIngs *MergeableIngresses, ma
Upstreams: upstreams,
Keepalive: keepalive,
Ingress: masterNginxCfg.Ingress,
SpiffeClientCerts: staticParams.SpiffeCerts && !baseCfgParams.SpiffeServerCerts,
SpiffeClientCerts: staticParams.NginxServiceMesh && !baseCfgParams.SpiffeServerCerts,
}
}

func isSSLEnabled(isSSLService bool, cfgParams ConfigParams, staticCfgParams *StaticConfigParams) bool {
return isSSLService || staticCfgParams.SpiffeCerts && !cfgParams.SpiffeServerCerts
return isSSLService || staticCfgParams.NginxServiceMesh && !cfgParams.SpiffeServerCerts
}
24 changes: 12 additions & 12 deletions internal/configs/ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ func TestGenerateNginxCfgForSpiffe(t *testing.T) {
}

apResources := make(map[string]string)
result := generateNginxCfg(&cafeIngressEx, pems, apResources, false, configParams, false, false, "", &StaticConfigParams{SpiffeCerts: true})
result := generateNginxCfg(&cafeIngressEx, pems, apResources, false, configParams, false, false, "", &StaticConfigParams{NginxServiceMesh: true})

if !reflect.DeepEqual(result, expected) {
t.Errorf("generateNginxCfg returned \n%v, but expected \n%v", result, expected)
Expand All @@ -788,7 +788,7 @@ func TestGenerateNginxCfgForInternalRoute(t *testing.T) {
}

apResources := make(map[string]string)
result := generateNginxCfg(&cafeIngressEx, pems, apResources, false, configParams, false, false, "", &StaticConfigParams{SpiffeCerts: true, EnableInternalRoutes: true})
result := generateNginxCfg(&cafeIngressEx, pems, apResources, false, configParams, false, false, "", &StaticConfigParams{NginxServiceMesh: true, EnableInternalRoutes: true})

if !reflect.DeepEqual(result, expected) {
t.Errorf("generateNginxCfg returned \n%+v, but expected \n%+v", result, expected)
Expand All @@ -799,61 +799,61 @@ func TestIsSSLEnabled(t *testing.T) {
type testCase struct {
IsSSLService,
SpiffeServerCerts,
SpiffeCerts,
NginxServiceMesh,
Expected bool
}
var testCases = []testCase{
{
IsSSLService: false,
SpiffeServerCerts: false,
SpiffeCerts: false,
NginxServiceMesh: false,
Expected: false,
},
{
IsSSLService: false,
SpiffeServerCerts: true,
SpiffeCerts: true,
NginxServiceMesh: true,
Expected: false,
},
{
IsSSLService: false,
SpiffeServerCerts: false,
SpiffeCerts: true,
NginxServiceMesh: true,
Expected: true,
},
{
IsSSLService: false,
SpiffeServerCerts: true,
SpiffeCerts: false,
NginxServiceMesh: false,
Expected: false,
},
{
IsSSLService: true,
SpiffeServerCerts: true,
SpiffeCerts: true,
NginxServiceMesh: true,
Expected: true,
},
{
IsSSLService: true,
SpiffeServerCerts: false,
SpiffeCerts: true,
NginxServiceMesh: true,
Expected: true,
},
{
IsSSLService: true,
SpiffeServerCerts: true,
SpiffeCerts: false,
NginxServiceMesh: false,
Expected: true,
},
{
IsSSLService: true,
SpiffeServerCerts: false,
SpiffeCerts: false,
NginxServiceMesh: false,
Expected: true,
},
}
for i, tc := range testCases {
actual := isSSLEnabled(tc.IsSSLService, ConfigParams{SpiffeServerCerts: tc.SpiffeServerCerts}, &StaticConfigParams{SpiffeCerts: tc.SpiffeCerts})
actual := isSSLEnabled(tc.IsSSLService, ConfigParams{SpiffeServerCerts: tc.SpiffeServerCerts}, &StaticConfigParams{NginxServiceMesh: tc.NginxServiceMesh})
if actual != tc.Expected {
t.Errorf("isSSLEnabled returned %v but expected %v for the case %v", actual, tc.Expected, i)
}
Expand Down
20 changes: 18 additions & 2 deletions internal/configs/virtualserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ var incompatibleLBMethodsForSlowStart = map[string]bool{
"random two least_time=last_byte": true,
}

// MeshPodOwner contains the type and name of the K8s resource that owns the pod.
// This owner information is needed for NGINX Service Mesh metrics.
type MeshPodOwner struct {
// OwnerType is one of the following: statefulset, daemonset, deployment.
OwnerType string
// OwnerName is the name of the statefulset, daemonset, or deployment.
OwnerName string
}

// PodInfo contains the name of the Pod and the MeshPodOwner information
// which is used for NGINX Service Mesh metrics.
type PodInfo struct {
Name string
MeshPodOwner
}

// VirtualServerEx holds a VirtualServer along with the resources that are referenced in this VirtualServer.
type VirtualServerEx struct {
VirtualServer *conf_v1.VirtualServer
Expand All @@ -37,7 +53,7 @@ type VirtualServerEx struct {
VirtualServerRoutes []*conf_v1.VirtualServerRoute
ExternalNameSvcs map[string]bool
Policies map[string]*conf_v1alpha1.Policy
PodsByIP map[string]string
PodsByIP map[string]PodInfo
}

func (vsx *VirtualServerEx) String() string {
Expand Down Expand Up @@ -168,7 +184,7 @@ func newVirtualServerConfigurator(cfgParams *ConfigParams, isPlus bool, isResolv
isTLSPassthrough: staticParams.TLSPassthrough,
enableSnippets: staticParams.EnableSnippets,
warnings: make(map[runtime.Object][]string),
spiffeCerts: staticParams.SpiffeCerts,
spiffeCerts: staticParams.NginxServiceMesh,
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/configs/virtualserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ func TestGenerateVirtualServerConfigWithSpiffeCerts(t *testing.T) {
isPlus := false
isResolverConfigured := false
tlsPemFileName := ""
staticConfigParams := &StaticConfigParams{TLSPassthrough: true, SpiffeCerts: true}
staticConfigParams := &StaticConfigParams{TLSPassthrough: true, NginxServiceMesh: true}
vsc := newVirtualServerConfigurator(&baseCfgParams, isPlus, isResolverConfigured, staticConfigParams)
result, warnings := vsc.GenerateVirtualServerConfig(&virtualServerEx, tlsPemFileName)
if !reflect.DeepEqual(result, expected) {
Expand Down
68 changes: 60 additions & 8 deletions internal/k8s/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ var (
type podEndpoint struct {
Address string
PodName string
// MeshPodOwner is used for NGINX Service Mesh metrics
configs.MeshPodOwner
}

// LoadBalancerController watches Kubernetes API and
Expand Down Expand Up @@ -2360,7 +2362,7 @@ func (lbc *LoadBalancerController) createIngress(ing *networking.Ingress) (*conf
ingEx.Endpoints = make(map[string][]string)
ingEx.HealthChecks = make(map[string]*api_v1.Probe)
ingEx.ExternalNameSvcs = make(map[string]bool)
ingEx.PodsByIP = make(map[string]string)
ingEx.PodsByIP = make(map[string]configs.PodInfo)

if ing.Spec.Backend != nil {
podEndps := []podEndpoint{}
Expand Down Expand Up @@ -2393,7 +2395,10 @@ func (lbc *LoadBalancerController) createIngress(ing *networking.Ingress) (*conf

if lbc.isNginxPlus || lbc.isLatencyMetricsEnabled {
for _, endpoint := range podEndps {
ingEx.PodsByIP[endpoint.Address] = endpoint.PodName
ingEx.PodsByIP[endpoint.Address] = configs.PodInfo{
Name: endpoint.PodName,
MeshPodOwner: endpoint.MeshPodOwner,
}
}
}
}
Expand Down Expand Up @@ -2440,7 +2445,10 @@ func (lbc *LoadBalancerController) createIngress(ing *networking.Ingress) (*conf

if lbc.isNginxPlus || lbc.isLatencyMetricsEnabled {
for _, endpoint := range podEndps {
ingEx.PodsByIP[endpoint.Address] = endpoint.PodName
ingEx.PodsByIP[endpoint.Address] = configs.PodInfo{
Name: endpoint.PodName,
MeshPodOwner: endpoint.MeshPodOwner,
}
}
}
}
Expand Down Expand Up @@ -2551,7 +2559,7 @@ func (lbc *LoadBalancerController) createVirtualServer(virtualServer *conf_v1.Vi

endpoints := make(map[string][]string)
externalNameSvcs := make(map[string]bool)
podsByIP := make(map[string]string)
podsByIP := make(map[string]configs.PodInfo)

for _, u := range virtualServer.Spec.Upstreams {
endpointsKey := configs.GenerateEndpointsKey(virtualServer.Namespace, u.Service, u.Subselector, u.Port)
Expand Down Expand Up @@ -2579,7 +2587,10 @@ func (lbc *LoadBalancerController) createVirtualServer(virtualServer *conf_v1.Vi

if lbc.isNginxPlus || lbc.isLatencyMetricsEnabled {
for _, endpoint := range podEndps {
podsByIP[endpoint.Address] = endpoint.PodName
podsByIP[endpoint.Address] = configs.PodInfo{
Name: endpoint.PodName,
MeshPodOwner: endpoint.MeshPodOwner,
}
}
}
}
Expand Down Expand Up @@ -2667,7 +2678,10 @@ func (lbc *LoadBalancerController) createVirtualServer(virtualServer *conf_v1.Vi

if lbc.isNginxPlus || lbc.isLatencyMetricsEnabled {
for _, endpoint := range podEndps {
podsByIP[endpoint.Address] = endpoint.PodName
podsByIP[endpoint.Address] = configs.PodInfo{
Name: endpoint.PodName,
MeshPodOwner: endpoint.MeshPodOwner,
}
}
}
}
Expand Down Expand Up @@ -2831,10 +2845,14 @@ func getEndpointsBySubselectedPods(targetPort int32, pods []*api_v1.Pod, svcEps
for _, address := range subset.Addresses {
if address.IP == pod.Status.PodIP {
addr := fmt.Sprintf("%v:%v", pod.Status.PodIP, targetPort)

ownerType, ownerName := getPodOwnerTypeAndName(pod)
podEnd := podEndpoint{
Address: addr,
PodName: getPodName(address.TargetRef),
MeshPodOwner: configs.MeshPodOwner{
OwnerType: ownerType,
OwnerName: ownerName,
},
}
endps = append(endps, podEnd)
}
Expand Down Expand Up @@ -2960,7 +2978,12 @@ func (lbc *LoadBalancerController) getEndpointsForPort(endps api_v1.Endpoints, i
addr := fmt.Sprintf("%v:%v", address.IP, port.Port)
podEnd := podEndpoint{
Address: addr,
PodName: address.TargetRef.Name,
}
if address.TargetRef != nil {
parentType, parentName := lbc.getPodOwnerTypeAndNameFromAddress(address.TargetRef.Namespace, address.TargetRef.Name)
podEnd.OwnerType = parentType
podEnd.OwnerName = parentName
podEnd.PodName = address.TargetRef.Name
}
endpoints = append(endpoints, podEnd)
}
Expand All @@ -2972,6 +2995,35 @@ func (lbc *LoadBalancerController) getEndpointsForPort(endps api_v1.Endpoints, i
return nil, fmt.Errorf("No endpoints for target port %v in service %s", targetPort, svc.Name)
}

func (lbc *LoadBalancerController) getPodOwnerTypeAndNameFromAddress(ns, name string) (parentType, parentName string) {
obj, exists, err := lbc.podLister.GetByKey(fmt.Sprintf("%s/%s", ns, name))
if err != nil {
glog.Warningf("could not get pod by key %s/%s: %v", ns, name, err)
return "", ""
}
if exists {
pod := obj.(*api_v1.Pod)
return getPodOwnerTypeAndName(pod)
}
return "", ""
}

func getPodOwnerTypeAndName(pod *api_v1.Pod) (parentType, parentName string) {
parentType = "deployment"
for _, owner := range pod.GetOwnerReferences() {
parentName = owner.Name
if owner.Controller != nil && *owner.Controller {
if owner.Kind == "StatefulSet" || owner.Kind == "DaemonSet" {
parentType = strings.ToLower(owner.Kind)
}
if owner.Kind == "ReplicaSet" && strings.HasSuffix(owner.Name, pod.Labels["pod-template-hash"]) {
parentName = strings.TrimSuffix(owner.Name, "-"+pod.Labels["pod-template-hash"])
}
}
}
return parentType, parentName
}

func (lbc *LoadBalancerController) getServicePortForIngressPort(ingSvcPort intstr.IntOrString, svc *api_v1.Service) *api_v1.ServicePort {
for _, port := range svc.Spec.Ports {
if (ingSvcPort.Type == intstr.Int && port.Port == int32(ingSvcPort.IntValue())) || (ingSvcPort.Type == intstr.String && port.Name == ingSvcPort.String()) {
Expand Down
Loading