Skip to content

Commit 718019e

Browse files
committed
Custom Metrics for ACS API calls. One metric updater implemented in isolated_network.go. Draft for feedback.
1 parent c0d5e8d commit 718019e

File tree

4 files changed

+68
-3
lines changed

4 files changed

+68
-3
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/onsi/gomega v1.19.0
1212
github.com/pkg/errors v0.9.1
1313
github.com/smallfish/simpleyaml v0.1.0
14+
github.com/prometheus/client_golang v1.11.0
1415
github.com/spf13/pflag v1.0.5
1516
gopkg.in/ini.v1 v1.63.2
1617
k8s.io/api v0.23.0

pkg/cloud/client.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package cloud
1818

1919
import (
20+
"sigs.k8s.io/cluster-api-provider-cloudstack/pkg/metrics"
2021
"strings"
2122

2223
"github.com/apache/cloudstack-go/v2/cloudstack"
@@ -40,9 +41,10 @@ type Client interface {
4041
}
4142

4243
type client struct {
43-
cs *cloudstack.CloudStackClient
44-
csAsync *cloudstack.CloudStackClient
45-
config Config
44+
cs *cloudstack.CloudStackClient
45+
csAsync *cloudstack.CloudStackClient
46+
config Config
47+
customMetrics metrics.AcsCustomMetrics
4648
}
4749

4850
// cloud-config ini structure.
@@ -68,6 +70,7 @@ func NewClient(ccPath string) (Client, error) {
6870
// comments for more details
6971
c.cs = cloudstack.NewAsyncClient(c.config.APIURL, c.config.APIKey, c.config.SecretKey, c.config.VerifySSL)
7072
c.csAsync = cloudstack.NewClient(c.config.APIURL, c.config.APIKey, c.config.SecretKey, c.config.VerifySSL)
73+
c.customMetrics = metrics.NewCustomMetrics()
7174

7275
_, err := c.cs.APIDiscovery.ListApis(c.cs.APIDiscovery.NewListApisParams())
7376
if err != nil && strings.Contains(strings.ToLower(err.Error()), "i/o timeout") {

pkg/cloud/isolated_network.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func (c *client) AssociatePublicIPAddress(
6060
// Check specified IP address is available or get an unused one if not specified.
6161
publicAddress, err := c.GetPublicIP(zone, isoNet, csCluster)
6262
if err != nil {
63+
c.customMetrics.IncrementAcsReconciliationErrors(err)
6364
return errors.Wrapf(err, "fetching a public IP address")
6465
}
6566
isoNet.Spec.ControlPlaneEndpoint.Host = publicAddress.Ipaddress

pkg/metrics/metrics.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
//Package metrics implements custom metrics for CAPC
18+
package metrics
19+
20+
import (
21+
"github.com/prometheus/client_golang/prometheus"
22+
"regexp"
23+
crtlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
24+
)
25+
26+
// AcsCustomMetrics encapsulates all CloudStack custom metrics defined for the controller.
27+
type AcsCustomMetrics struct {
28+
acsReconciliationErrorCount *prometheus.CounterVec
29+
errorCodeRegexp *regexp.Regexp
30+
}
31+
32+
// NewCustomMetrics constructs an AcsCustomMetrics with all desired CloudStack custom metrics and any supporting resources.
33+
func NewCustomMetrics() AcsCustomMetrics {
34+
customMetrics := AcsCustomMetrics{}
35+
customMetrics.acsReconciliationErrorCount = prometheus.NewCounterVec(
36+
prometheus.CounterOpts{
37+
Name: "acs_reconciliation_errors",
38+
Help: "Count of reconciliation errors caused by ACS issues, bucketed by error code",
39+
},
40+
[]string{"acs_error_code"},
41+
)
42+
crtlmetrics.Registry.MustRegister(customMetrics.acsReconciliationErrorCount)
43+
44+
// ACS standard error messages of the form "CloudStack API error 431 (CSExceptionErrorCode: 9999):..."
45+
// This regexp is used to extract CSExceptionCodes from the message.
46+
customMetrics.errorCodeRegexp, _ = regexp.Compile(".+CSExceptionErrorCode: ([0-9]+).+")
47+
48+
return customMetrics
49+
}
50+
51+
// IncrementAcsReconciliationErrors accepts a CloudStack error message and increments the custom
52+
// acs_reconciliation_errors counter, labeled with the error code if present in the error message.
53+
func (m *AcsCustomMetrics) IncrementAcsReconciliationErrors(acsError error) {
54+
matches := m.errorCodeRegexp.FindStringSubmatch(acsError.Error())
55+
if len(matches) > 1 {
56+
m.acsReconciliationErrorCount.WithLabelValues(matches[1]).Inc()
57+
} else {
58+
m.acsReconciliationErrorCount.WithLabelValues("No error code").Inc()
59+
}
60+
}

0 commit comments

Comments
 (0)