mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
urpc encodes with encoding/json, which walks the payload on every call: a realistic control.ExecArgs costs 7084ns and 10 allocations to cross. ZAP reads a field at a constant offset out of the buffer that arrived, so the same payload is 740ns and one allocation -- but only if the offsets are stated, and a stated offset that is wrong is silent corruption rather than a compile error. So state them from the types themselves. //tools/zap reflects over the payloads at build time and writes the wire as Go source with the offsets as constants. It lives inside Bazel because pkg/sentry/control cannot be imported from outside it: the *_go_proto packages it depends on have no source in the tree. Six payloads had no layout to state. A map, an interface and a type from another module have no offsets, so each is answered in the type: SaveOpts.Metadata and StartContainerArgs.InitialCgroups/Limits cross as lists of pairs; boot.Route.Destination restates net.IPNet as Subnet; OpenMountArgs restates the OCI mount fields the call actually uses; StartArgs.Spec and SinkConfig.Config carry their documents as the bytes they arrived as; MetricsRegistrationResponse carries the protocol buffer the same way; and seccheck's session options become a type instead of a map of any. ExecArgs and MetricsExportData still have none: ExecArgs holds live kernel objects behind an interface, and MetricsExportData reaches a prometheus snapshot whose labels are a map. Co-authored-by: Hanzo Dev <[email protected]>
136 lines
4.4 KiB
Go
136 lines
4.4 KiB
Go
// Copyright 2022 The gVisor 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 control
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
"gvisor.dev/gvisor/pkg/metric"
|
|
"gvisor.dev/gvisor/pkg/prometheus"
|
|
"gvisor.dev/gvisor/pkg/sync"
|
|
)
|
|
|
|
// Metrics includes metrics-related RPC stubs.
|
|
type Metrics struct{}
|
|
|
|
// GetRegisteredMetricsOpts contains metric registration query options.
|
|
type GetRegisteredMetricsOpts struct{}
|
|
|
|
// MetricsRegistrationResponse contains metric registration data.
|
|
type MetricsRegistrationResponse struct {
|
|
// Registration is a metric_go_proto.MetricRegistration as the protocol
|
|
// buffer states it. The RPC carries the bytes: a message generated by
|
|
// another tool declares its own wire, and re-stating it here would be a
|
|
// second answer to what those bytes are.
|
|
Registration []byte
|
|
}
|
|
|
|
// GetRegisteredMetrics sets `out` to the metric registration information.
|
|
// Meant to be called over the control channel, with `out` as return value.
|
|
// This should be called during Sentry boot before any container starts.
|
|
// Metric registration data is used by the processes querying sandbox metrics
|
|
// to ensure the integrity of metrics exported from the untrusted sandbox.
|
|
func (u *Metrics) GetRegisteredMetrics(_ *GetRegisteredMetricsOpts, out *MetricsRegistrationResponse) error {
|
|
registration, err := metric.GetMetricRegistration()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
out.Registration, err = proto.Marshal(registration)
|
|
return err
|
|
}
|
|
|
|
// MetricsExportOpts contains metric exporting options.
|
|
type MetricsExportOpts struct {
|
|
// If set, this is a regular expression that is used to filter the set of
|
|
// exported metrics.
|
|
OnlyMetrics string `json:"only_metrics"`
|
|
}
|
|
|
|
var (
|
|
// lastOnlyMetricsMu protects the variables below.
|
|
lastOnlyMetricsMu sync.Mutex
|
|
|
|
// lastOnlyMetricsStr is the last value of the "only_metrics" parameter passed to
|
|
// MetricsExport. It is used to avoid re-compiling the regular expression on every
|
|
// request in the common case where a single metric scraper is scraping the sandbox
|
|
// metrics using the same filter in each request.
|
|
lastOnlyMetricsStr string
|
|
|
|
// lastOnlyMetrics is the compiled version of lastOnlyMetricsStr.
|
|
lastOnlyMetrics *regexp.Regexp
|
|
)
|
|
|
|
// filterFunc returns a filter function to filter relevant Prometheus metric names.
|
|
func (m *MetricsExportOpts) filterFunc() (func(*prometheus.Metric) bool, error) {
|
|
if m.OnlyMetrics == "" {
|
|
return nil, nil
|
|
}
|
|
lastOnlyMetricsMu.Lock()
|
|
defer lastOnlyMetricsMu.Unlock()
|
|
onlyMetricsReg := lastOnlyMetrics
|
|
if m.OnlyMetrics != lastOnlyMetricsStr {
|
|
reg, err := regexp.Compile(m.OnlyMetrics)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot compile regexp %q: %v", m.OnlyMetrics, err)
|
|
}
|
|
lastOnlyMetricsStr = m.OnlyMetrics
|
|
lastOnlyMetrics = reg
|
|
onlyMetricsReg = reg
|
|
}
|
|
return func(m *prometheus.Metric) bool {
|
|
return onlyMetricsReg.MatchString(m.Name)
|
|
}, nil
|
|
}
|
|
|
|
// Verify verifies that the given exported data is compliant with the export
|
|
// options. This should be run client-side to double-check results.
|
|
func (m *MetricsExportOpts) Verify(data *MetricsExportData) error {
|
|
filterFunc, err := m.filterFunc()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if filterFunc != nil && data.Snapshot != nil {
|
|
for _, data := range data.Snapshot.Data {
|
|
if !filterFunc(data.Metric) {
|
|
return fmt.Errorf("metric %v violated the filter set in export options", data.Metric)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MetricsExportData contains data for all metrics being exported.
|
|
type MetricsExportData struct {
|
|
Snapshot *prometheus.Snapshot `json:"snapshot"`
|
|
}
|
|
|
|
// Export export metrics data into MetricsExportData.
|
|
func (u *Metrics) Export(opts *MetricsExportOpts, out *MetricsExportData) error {
|
|
filterFunc, err := opts.filterFunc()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
snapshot, err := metric.GetSnapshot(metric.SnapshotOptions{
|
|
Filter: filterFunc,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
out.Snapshot = snapshot
|
|
return nil
|
|
}
|