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

ARO-13380 - metrics: cwp status #4002

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.4.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6 v6.2.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.1.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 h1:z4Yei
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0/go.mod h1:rko9SzMxcMk0NJsNAxALEGaTYyy79bNRwxgJfrH0Spw=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6 v6.2.0 h1:HYGD75g0bQ3VO/Omedm54v4LrD3B1cGImuRF3AJ5wLo=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6 v6.2.0/go.mod h1:ulHyBFJOI0ONiRL4vcJTmS7rx18jQQlEPmAgo80cRdM=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70=
Expand Down
1 change: 1 addition & 0 deletions pkg/monitor/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ func (mon *Monitor) Monitor(ctx context.Context) (errs []error) {
mon.emitCertificateExpirationStatuses,
mon.emitEtcdCertificateExpiry,
mon.emitPrometheusAlerts, // at the end for now because it's the slowest/least reliable
mon.emitCWPStatus,
} {
err = f(ctx)
if err != nil {
Expand Down
202 changes: 202 additions & 0 deletions pkg/monitor/cluster/clusterwideproxystatus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package cluster

// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.

import (
"context"
"net/url"
"strconv"
"strings"

"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

apisubnet "github.com/Azure/ARO-RP/pkg/api/util/subnet"
arov1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/aro.openshift.io/v1alpha1"
)

const (
cwp = "clusterWideProxy.status"
cwpErrorMessage = "NoProxy entries are incorrect"
cluster = "cluster"
mandatory_no_proxies = "localhost,127.0.0.1,.svc,.cluster.local.,168.63.129.16,169.254.169.254"
//169.254.169.254 (the IMDS IP)
//168.63.129.16 (Azure DNS, if no custom DNS exists)
//localhost, 127.0.0.1, .svc, .cluster.local
)

// Helper function to emit and log the gauge status
func (mon *Monitor) emitAndLogCWPStatus(status bool, message string) {
mon.emitGauge(cwp, 1, map[string]string{
"status": strconv.FormatBool(status),
"Message": message,
})

if mon.hourlyRun {
mon.log.WithFields(logrus.Fields{
"metric": cwp,
"status": strconv.FormatBool(status),
"Message": message,
}).Print()
}
}

// Main function to emit CWP status
func (mon *Monitor) emitCWPStatus(ctx context.Context) error {
mon.hourlyRun = true
proxyConfig, err := mon.configcli.ConfigV1().Proxies().Get(ctx, cluster, metav1.GetOptions{})
if err != nil {
mon.log.Errorf("Error in getting the cluster wide proxy: %v", err)
return err
}
if proxyConfig.Spec.HTTPProxy == "" && proxyConfig.Spec.HTTPSProxy == "" && proxyConfig.Spec.NoProxy == "" {
mon.emitAndLogCWPStatus(false, "CWP not enabled")
} else {
// Create the noProxy map for efficient lookups
no_proxy_list := strings.Split(proxyConfig.Spec.NoProxy, ",")
LiniSusan marked this conversation as resolved.
Show resolved Hide resolved
noProxyMap := make(map[string]bool)
for _, proxy := range no_proxy_list {
noProxyMap[proxy] = true
}

// Check mandatory no_proxy entries
for _, mandatory_no_proxy := range strings.Split(mandatory_no_proxies, ",") {
if !noProxyMap[mandatory_no_proxy] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing "+mandatory_no_proxy+" in the no_proxy list")
}
}

// Azure credentials and client setup
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
mon.log.Errorf("failed to obtain a credential: %v", err)
return err
}

mastersubnetID, err := azure.ParseResourceID(mon.oc.Properties.MasterProfile.SubnetID)
if err != nil {
return err
}

// Create client factory
clientFactory, err := armnetwork.NewClientFactory(mastersubnetID.SubscriptionID, cred, nil)
if err != nil {
mon.log.Errorf("failed to create client: %v", err)
return err
}

// Check master subnet
masterVnetID, _, err := apisubnet.Split(mon.oc.Properties.MasterProfile.SubnetID)
if err != nil {
return err
}
mastervnetId, err := azure.ParseResourceID(masterVnetID)
if err != nil {
return err
}
res, err := clientFactory.NewSubnetsClient().Get(ctx, mastersubnetID.ResourceGroup, mastervnetId.ResourceName, mastersubnetID.ResourceName, &armnetwork.SubnetsClientGetOptions{Expand: nil})
if err != nil {
mon.log.Errorf("failed to finish the request: %v", err)
return err
}
mastermachineCIDR := *res.Properties.AddressPrefix
if !noProxyMap[mastermachineCIDR] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing master machineCIDR "+mastermachineCIDR+" in the no_proxy list")
}

// Check worker profiles
for _, workerProfile := range mon.oc.Properties.WorkerProfiles {
workersubnetID, err := azure.ParseResourceID(workerProfile.SubnetID)
if err != nil {
return err
}
workerVnetID, _, err := apisubnet.Split(workerProfile.SubnetID)
if err != nil {
return err
}
workervnetId, err := azure.ParseResourceID(workerVnetID)
if err != nil {
return err
}
workerres, err := clientFactory.NewSubnetsClient().Get(ctx, workersubnetID.ResourceGroup, workervnetId.ResourceName, workersubnetID.ResourceName, &armnetwork.SubnetsClientGetOptions{Expand: nil})
if err != nil {
mon.log.Errorf("failed to finish the request: %v", err)
}
workermachinesCIDR := *workerres.Properties.AddressPrefix
if !noProxyMap[workermachinesCIDR] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing Worker machine CIDR "+workermachinesCIDR+" in the no_proxy list")
}
}

// Network Configuration Check
networkConfig, err := mon.configcli.ConfigV1().Networks().Get(ctx, cluster, metav1.GetOptions{})
if err != nil {
mon.log.Errorf("Error in getting network info: %v", err)
return err
}
for _, network := range networkConfig.Spec.ClusterNetwork {
if !noProxyMap[network.CIDR] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing PodCIDR "+network.CIDR+" in the no_proxy list")
}
}
for _, network := range networkConfig.Spec.ServiceNetwork {
if !noProxyMap[network] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing ServiceCIDR "+network+" in the no_proxy list")
}
}

// Gateway Domains Check
clusterdetails, err := mon.arocli.AroV1alpha1().Clusters().Get(ctx, arov1alpha1.SingletonClusterName, metav1.GetOptions{})
if err != nil {
return err
}
for _, gatewayDomain := range clusterdetails.Spec.GatewayDomains {
if !noProxyMap[gatewayDomain] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing Gateway domain "+gatewayDomain+" in the no_proxy list")
}
}

// Infrastructure Configuration Check
infraConfig, err := mon.configcli.ConfigV1().Infrastructures().Get(ctx, cluster, metav1.GetOptions{})
if err != nil {
mon.log.Errorf("Error in getting network info: %v", err)
return err
}

// APIServerInternal URL Check
apiServerIntURL, err := url.Parse(infraConfig.Status.APIServerInternalURL)
if err != nil {
return err
}
apiServerIntdomain := strings.Split(apiServerIntURL.Host, ":")[0]
if !noProxyMap[apiServerIntdomain] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing APIServerInternal URL "+apiServerIntdomain+" in the no_proxy list")
}

// APIServerProfile URL Check
apiServerProfileURL, err := url.Parse(mon.oc.Properties.APIServerProfile.URL)
if err != nil {
return err
}
apiServerProfiledomain := strings.Split(apiServerProfileURL.Host, ":")[0]
if !noProxyMap[apiServerProfiledomain] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing APiServerProfile URL "+apiServerProfiledomain+" in the no_proxy list")
}

// ConsoleProfile URL Check
consolProfileURL, err := url.Parse(mon.oc.Properties.ConsoleProfile.URL)
if err != nil {
return err
}
consoleProfiledomain := strings.Split(consolProfileURL.Host, ":")[0]
if !noProxyMap[consolProfileURL.Host] {
mon.emitAndLogCWPStatus(true, "CWP enabled but missing Console Profile URL "+consoleProfiledomain+" in the no_proxy list")
}
}

return nil
}
Loading
Loading