mirror of https://github.com/knative/caching.git
189 lines
5.8 KiB
Go
189 lines
5.8 KiB
Go
/*
|
|
Copyright 2019 The Knative Authors
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package mako
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"cloud.google.com/go/compute/metadata"
|
|
kubeclient "knative.dev/pkg/client/injection/kube/client"
|
|
|
|
"github.com/google/mako/go/quickstore"
|
|
qpb "github.com/google/mako/proto/quickstore/quickstore_go_proto"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/rest"
|
|
"knative.dev/pkg/changeset"
|
|
"knative.dev/pkg/controller"
|
|
"knative.dev/pkg/injection"
|
|
"knative.dev/pkg/test/mako/alerter"
|
|
"knative.dev/pkg/test/mako/config"
|
|
)
|
|
|
|
const (
|
|
// sidecarAddress is the address of the Mako sidecar to which we locally
|
|
// write results, and it authenticates and publishes them to Mako after
|
|
// assorted preprocessing.
|
|
sidecarAddress = "localhost:9813"
|
|
|
|
// org is the orgnization name that is used by Github client
|
|
org = "knative"
|
|
|
|
// slackUserName is the slack user name that is used by Slack client
|
|
slackUserName = "Knative Testgrid Robot"
|
|
|
|
// These token settings are for alerter.
|
|
// If we want to enable the alerter for a benchmark, we need to mount the
|
|
// token to the pod, with the same name and path.
|
|
// See https://github.com/knative/serving/blob/master/test/performance/benchmarks/dataplane-probe/continuous/dataplane-probe.yaml
|
|
tokenFolder = "/var/secret"
|
|
githubToken = "github-token"
|
|
slackReadToken = "slack-read-token"
|
|
slackWriteToken = "slack-write-token"
|
|
)
|
|
|
|
// Client is a wrapper that wraps all Mako related operations
|
|
type Client struct {
|
|
Quickstore *quickstore.Quickstore
|
|
Context context.Context
|
|
ShutDownFunc func(context.Context)
|
|
|
|
benchmarkKey string
|
|
benchmarkName string
|
|
alerter *alerter.Alerter
|
|
}
|
|
|
|
// StoreAndHandleResult stores the benchmarking data and handles the result.
|
|
func (c *Client) StoreAndHandleResult() error {
|
|
out, err := c.Quickstore.Store()
|
|
return c.alerter.HandleBenchmarkResult(c.benchmarkKey, c.benchmarkName, out, err)
|
|
}
|
|
|
|
var tagEscaper = strings.NewReplacer("+", "-", "\t", "_", " ", "_")
|
|
|
|
// EscapeTag replaces characters that Mako doesn't accept with ones it does.
|
|
func EscapeTag(tag string) string {
|
|
return tagEscaper.Replace(tag)
|
|
}
|
|
|
|
// SetupHelper sets up the mako client for the provided benchmarkKey.
|
|
// It will add a few common tags and allow each benchmark to add custm tags as well.
|
|
// It returns the mako client handle to store metrics, a method to close the connection
|
|
// to mako server once done and error in case of failures.
|
|
func SetupHelper(ctx context.Context, benchmarkKey *string, benchmarkName *string, extraTags ...string) (*Client, error) {
|
|
tags := append(config.MustGetTags(), extraTags...)
|
|
// Get the commit of the benchmarks
|
|
commitID, err := changeset.Get()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Setup a deployment informer, so that we can use the lister to track
|
|
// desired and available pod counts.
|
|
cfg, err := rest.InClusterConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ctx, informers := injection.Default.SetupInformers(ctx, cfg)
|
|
if err := controller.StartInformers(ctx.Done(), informers...); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get the Kubernetes version from the API server.
|
|
kc := kubeclient.Get(ctx)
|
|
version, err := kc.Discovery().ServerVersion()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Determine the number of Kubernetes nodes through the kubernetes client.
|
|
nodes, err := kc.CoreV1().Nodes().List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tags = append(tags, "nodes="+fmt.Sprintf("%d", len(nodes.Items)))
|
|
|
|
// Decorate GCP metadata as tags (when we're running on GCP).
|
|
if projectID, err := metadata.ProjectID(); err != nil {
|
|
log.Printf("GCP project ID is not available: %v", err)
|
|
} else {
|
|
tags = append(tags, "project-id="+EscapeTag(projectID))
|
|
}
|
|
if zone, err := metadata.Zone(); err != nil {
|
|
log.Printf("GCP zone is not available: %v", err)
|
|
} else {
|
|
tags = append(tags, "zone="+EscapeTag(zone))
|
|
}
|
|
if machineType, err := metadata.Get("instance/machine-type"); err != nil {
|
|
log.Printf("GCP machine type is not available: %v", err)
|
|
} else if parts := strings.Split(machineType, "/"); len(parts) != 4 {
|
|
tags = append(tags, "instanceType="+EscapeTag(parts[3]))
|
|
}
|
|
tags = append(tags,
|
|
"commit="+commitID,
|
|
"kubernetes="+EscapeTag(version.String()),
|
|
"goversion="+EscapeTag(runtime.Version()),
|
|
)
|
|
log.Printf("The tags for this run are: %+v", tags)
|
|
// Create a new Quickstore that connects to the microservice
|
|
qs, qclose, err := quickstore.NewAtAddress(ctx, &qpb.QuickstoreInput{
|
|
BenchmarkKey: benchmarkKey,
|
|
Tags: tags,
|
|
}, sidecarAddress)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create a new Alerter that alerts for performance regressions
|
|
alerter := &alerter.Alerter{}
|
|
alerter.SetupGitHub(
|
|
org,
|
|
config.GetRepository(),
|
|
tokenPath(githubToken),
|
|
)
|
|
alerter.SetupSlack(
|
|
slackUserName,
|
|
tokenPath(slackReadToken),
|
|
tokenPath(slackWriteToken),
|
|
config.GetSlackChannels(*benchmarkName),
|
|
)
|
|
|
|
client := &Client{
|
|
Quickstore: qs,
|
|
Context: ctx,
|
|
ShutDownFunc: qclose,
|
|
alerter: alerter,
|
|
benchmarkKey: *benchmarkKey,
|
|
benchmarkName: *benchmarkName,
|
|
}
|
|
|
|
return client, nil
|
|
}
|
|
|
|
func Setup(ctx context.Context, extraTags ...string) (*Client, error) {
|
|
bench := config.MustGetBenchmark()
|
|
return SetupHelper(ctx, bench.BenchmarkKey, bench.BenchmarkName, extraTags...)
|
|
}
|
|
|
|
func tokenPath(token string) string {
|
|
return filepath.Join(tokenFolder, token)
|
|
}
|