Skip to content

Commit

Permalink
roachprod: permit disabling of Prometheus registration
Browse files Browse the repository at this point in the history
This patch makes an empty value for the COCKROACH_PROM_HOST_URL env var
disable the roachprod's cluster registration with the Prometheus
registration service. This is useful for people who don't work at
CockroachLabs and don't have access to this service.

Release note: None
Epic: None
  • Loading branch information
andreimatei authored and srosenberg committed May 30, 2024
1 parent 3cb29e1 commit 439daf3
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 29 deletions.
1 change: 1 addition & 0 deletions pkg/roachprod/promhelperclient/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ go_library(
importpath = "github.com/cockroachdb/cockroach/pkg/roachprod/promhelperclient",
visibility = ["//visibility:public"],
deps = [
"//pkg/roachprod/config",
"//pkg/roachprod/logger",
"//pkg/roachprod/vm/gce",
"//pkg/util/httputil",
Expand Down
55 changes: 35 additions & 20 deletions pkg/roachprod/promhelperclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"strconv"
"strings"

"github.com/cockroachdb/cockroach/pkg/roachprod/config"
"github.com/cockroachdb/cockroach/pkg/roachprod/logger"
"github.com/cockroachdb/cockroach/pkg/roachprod/vm/gce"
"github.com/cockroachdb/cockroach/pkg/util/httputil"
Expand All @@ -34,24 +35,27 @@ import (
)

const (
resourceName = "instance-configs"
resourceVersion = "v1"

// defaultPrometheusHostUrl for prometheus cluster config
defaultPrometheusHostUrl = "https://grafana.testeng.crdb.io/promhelpers"
// prometheusHostUrlEnv is the environment variable to override defaultPrometheusHostUrl
prometheusHostUrlEnv = "ROACHPROD_PROM_HOST_URL"

resourceName = "instance-configs"
resourceVersion = "v1"
serviceAccountJson = "PROM_HELPER_SERVICE_ACCOUNT_JSON"
serviceAccountAudience = "PROM_HELPER_SERVICE_ACCOUNT_AUDIENCE"
)

// SupportedPromProjects are the projects supported for prometheus target
var SupportedPromProjects = map[string]struct{}{gce.DefaultProject(): {}}

// The URL for the Prometheus registration service. An empty string means that the
// Prometheus integration is disabled. Should be accessed through
// getPrometheusRegistrationUrl().
var promRegistrationUrl = config.EnvOrDefaultString("ROACHPROD_PROM_HOST_URL",
"https://grafana.testeng.crdb.io/promhelpers")

// PromClient is used to communicate with the prometheus helper service
// keeping the functions as a variable enables us to override the value for unit testing
type PromClient struct {
promUrl string
disabled bool

// httpPut is used for http PUT operation.
httpPut func(
ctx context.Context, url string, h *http.Header, body io.Reader,
Expand All @@ -64,15 +68,26 @@ type PromClient struct {
oauth2.TokenSource, error)
}

// DefaultPromClient is the default instance of PromClient. This instance should
// be used unless custom configuration is needed.
var DefaultPromClient = NewPromClient()

// NewPromClient returns a new instance of PromClient
func NewPromClient() *PromClient {
return &PromClient{
promUrl: promRegistrationUrl,
disabled: promRegistrationUrl == "",
httpPut: httputil.Put,
httpDelete: httputil.Delete,
newTokenSource: idtoken.NewTokenSource,
}
}

func (c *PromClient) setUrl(url string) {
c.promUrl = url
c.disabled = false
}

// instanceConfigRequest is the HTTP request received for generating instance config
type instanceConfigRequest struct {
//Config is the content of the yaml file
Expand All @@ -89,19 +104,19 @@ func (c *PromClient) UpdatePrometheusTargets(
insecure bool,
l *logger.Logger,
) error {
promUrl := defaultPrometheusHostUrl
if v, ok := os.LookupEnv(prometheusHostUrlEnv); ok {
promUrl = v
if c.disabled {
l.Printf("Prometheus registration is disabled")
return nil
}
req, err := buildCreateRequest(nodes, insecure)
if err != nil {
return err
}
token, err := c.getToken(ctx, promUrl, forceFetchCreds, l)
token, err := c.getToken(ctx, forceFetchCreds, l)
if err != nil {
return err
}
url := getUrl(promUrl, clusterName)
url := getUrl(c.promUrl, clusterName)
l.Printf("invoking PUT for URL: %s", url)
h := &http.Header{}
h.Set("ContentType", "application/json")
Expand Down Expand Up @@ -132,15 +147,15 @@ func (c *PromClient) UpdatePrometheusTargets(
func (c *PromClient) DeleteClusterConfig(
ctx context.Context, clusterName string, forceFetchCreds bool, l *logger.Logger,
) error {
promUrl := defaultPrometheusHostUrl
if v, ok := os.LookupEnv(prometheusHostUrlEnv); ok {
promUrl = v

if c.disabled {
return nil
}
token, err := c.getToken(ctx, promUrl, forceFetchCreds, l)
token, err := c.getToken(ctx, forceFetchCreds, l)
if err != nil {
return err
}
url := getUrl(promUrl, clusterName)
url := getUrl(c.promUrl, clusterName)
l.Printf("invoking DELETE for URL: %s", url)
h := &http.Header{}
h.Set("Authorization", token)
Expand Down Expand Up @@ -206,9 +221,9 @@ func buildCreateRequest(nodes map[int]*NodeInfo, insecure bool) (io.Reader, erro

// getToken gets the Authorization token for grafana
func (c *PromClient) getToken(
ctx context.Context, promUrl string, forceFetchCreds bool, l *logger.Logger,
ctx context.Context, forceFetchCreds bool, l *logger.Logger,
) (string, error) {
if strings.HasPrefix(promUrl, "http:/") {
if strings.HasPrefix(c.promUrl, "http:/") {
// no token needed for insecure URL
return "", nil
}
Expand Down
16 changes: 10 additions & 6 deletions pkg/roachprod/promhelperclient/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ func TestUpdatePrometheusTargets(t *testing.T) {
}()
ctx := context.Background()
promUrl := "http://prom_url.com"
_ = os.Setenv(prometheusHostUrlEnv, promUrl)
c := NewPromClient()
c.setUrl(promUrl)
t.Run("UpdatePrometheusTargets fails with 400", func(t *testing.T) {
c.httpPut = func(ctx context.Context, reqUrl string, h *http.Header, body io.Reader) (
resp *http.Response, err error) {
Expand Down Expand Up @@ -96,8 +96,8 @@ func TestDeleteClusterConfig(t *testing.T) {
}()
ctx := context.Background()
promUrl := "http://prom_url.com"
_ = os.Setenv(prometheusHostUrlEnv, promUrl)
c := NewPromClient()
c.setUrl(promUrl)
t.Run("DeleteClusterConfig fails with 400", func(t *testing.T) {
c.httpDelete = func(ctx context.Context, url string, h *http.Header) (
resp *http.Response, err error) {
Expand Down Expand Up @@ -144,7 +144,8 @@ func Test_getToken(t *testing.T) {
}()
c := NewPromClient()
t.Run("insecure url", func(t *testing.T) {
token, err := c.getToken(ctx, "http://test.com", false, l)
c.setUrl("http://test.com")
token, err := c.getToken(ctx, false, l)
require.Nil(t, err)
require.Empty(t, token)
})
Expand All @@ -156,7 +157,8 @@ func Test_getToken(t *testing.T) {
c.newTokenSource = func(ctx context.Context, audience string, opts ...idtoken.ClientOption) (oauth2.TokenSource, error) {
return nil, fmt.Errorf("invalid")
}
token, err := c.getToken(ctx, "https://test.com", false, l)
c.setUrl("https://test.com")
token, err := c.getToken(ctx, false, l)
require.NotNil(t, err)
require.Empty(t, token)
require.Equal(t, "error creating GCS oauth token source from specified credential: invalid", err.Error())
Expand All @@ -169,7 +171,8 @@ func Test_getToken(t *testing.T) {
c.newTokenSource = func(ctx context.Context, audience string, opts ...idtoken.ClientOption) (oauth2.TokenSource, error) {
return &mockToken{token: "", err: fmt.Errorf("failed")}, nil
}
token, err := c.getToken(ctx, "https://test.com", false, l)
c.setUrl("https://test.com")
token, err := c.getToken(ctx, false, l)
require.NotNil(t, err)
require.Empty(t, token)
require.Equal(t, "error getting identity token: failed", err.Error())
Expand All @@ -182,7 +185,8 @@ func Test_getToken(t *testing.T) {
c.newTokenSource = func(ctx context.Context, audience string, opts ...idtoken.ClientOption) (oauth2.TokenSource, error) {
return &mockToken{token: "token"}, nil
}
token, err := c.getToken(ctx, "https://test.com", false, l)
c.setUrl("https://test.com")
token, err := c.getToken(ctx, false, l)
require.Nil(t, err)
require.Equal(t, "Bearer token", token)
})
Expand Down
11 changes: 8 additions & 3 deletions pkg/roachprod/roachprod.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ import (
"golang.org/x/sys/unix"
)

// supportedPromProjects are the projects supported for prometheus target
var supportedPromProjects = map[string]struct{}{gce.DefaultProject(): {}}

// MalformedClusterNameError is returned when the cluster name passed to Create is invalid.
type MalformedClusterNameError struct {
name string
Expand Down Expand Up @@ -821,7 +824,7 @@ func updatePrometheusTargets(ctx context.Context, l *logger.Logger, c *install.S
}
wg.Wait()
if len(nodeIPPorts) > 0 {
if err := promhelperclient.NewPromClient().UpdatePrometheusTargets(ctx,
if err := promhelperclient.DefaultPromClient.UpdatePrometheusTargets(ctx,
c.Name, false, nodeIPPorts, !c.Secure, l); err != nil {
l.Errorf("creating cluster config failed for the ip:ports %v: %v", nodeIPPorts, err)
}
Expand Down Expand Up @@ -1453,15 +1456,17 @@ func Destroy(
// and let the caller retry.
cld, _ = cloud.ListCloud(l, vm.ListOptions{IncludeEmptyClusters: true})
}
return destroyCluster(cld, l, name)
return destroyCluster(ctx, cld, l, name)
}); err != nil {
return err
}
l.Printf("OK")
return nil
}

func destroyCluster(cld *cloud.Cloud, l *logger.Logger, clusterName string) error {
func destroyCluster(
ctx context.Context, cld *cloud.Cloud, l *logger.Logger, clusterName string,
) error {
c, ok := cld.Clusters[clusterName]
if !ok {
return fmt.Errorf("cluster %s does not exist", clusterName)
Expand Down

0 comments on commit 439daf3

Please sign in to comment.