From 181360c23e82f51ac2d15c3bcaed9f9f4b171f7c Mon Sep 17 00:00:00 2001 From: Etienne Perot Date: Tue, 15 Aug 2023 17:12:21 -0700 Subject: [PATCH] Refactor: Move container metric metadata helpers into their own package. PiperOrigin-RevId: 557298185 --- runsc/cmd/BUILD | 1 + runsc/cmd/metric_export.go | 4 +- runsc/metricserver/BUILD | 1 + runsc/metricserver/containermetrics/BUILD | 18 ++++ .../containermetrics/containermetrics.go | 87 +++++++++++++++++++ runsc/metricserver/metricserver.go | 5 +- runsc/metricserver/metricserver_metrics.go | 66 -------------- 7 files changed, 112 insertions(+), 70 deletions(-) create mode 100644 runsc/metricserver/containermetrics/BUILD create mode 100644 runsc/metricserver/containermetrics/containermetrics.go diff --git a/runsc/cmd/BUILD b/runsc/cmd/BUILD index dff998761..e6417a64b 100644 --- a/runsc/cmd/BUILD +++ b/runsc/cmd/BUILD @@ -78,6 +78,7 @@ go_library( "//runsc/fsgofer", "//runsc/fsgofer/filter", "//runsc/metricserver", + "//runsc/metricserver/containermetrics", "//runsc/mitigate", "//runsc/profile", "//runsc/specutils", diff --git a/runsc/cmd/metric_export.go b/runsc/cmd/metric_export.go index 4c0ef9a4d..88fcf37a5 100644 --- a/runsc/cmd/metric_export.go +++ b/runsc/cmd/metric_export.go @@ -26,7 +26,7 @@ import ( "gvisor.dev/gvisor/runsc/config" "gvisor.dev/gvisor/runsc/container" "gvisor.dev/gvisor/runsc/flag" - "gvisor.dev/gvisor/runsc/metricserver" + "gvisor.dev/gvisor/runsc/metricserver/containermetrics" ) // MetricExport implements subcommands.Command for the "metric-export" command. @@ -72,7 +72,7 @@ func (m *MetricExport) Execute(ctx context.Context, f *flag.FlagSet, args ...any util.Fatalf("loading container: %v", err) } - prometheusLabels, err := metricserver.SandboxPrometheusLabels(cont) + prometheusLabels, err := containermetrics.SandboxPrometheusLabels(cont) if err != nil { util.Fatalf("Cannot compute Prometheus labels of sandbox: %v", err) } diff --git a/runsc/metricserver/BUILD b/runsc/metricserver/BUILD index cc0a205f3..895bfb963 100644 --- a/runsc/metricserver/BUILD +++ b/runsc/metricserver/BUILD @@ -25,6 +25,7 @@ go_library( "//pkg/sync", "//runsc/config", "//runsc/container", + "//runsc/metricserver/containermetrics", "//runsc/sandbox", "@org_golang_google_api//option:go_default_library", "@org_golang_google_grpc//:go_default_library", diff --git a/runsc/metricserver/containermetrics/BUILD b/runsc/metricserver/containermetrics/BUILD new file mode 100644 index 000000000..8f4b681d6 --- /dev/null +++ b/runsc/metricserver/containermetrics/BUILD @@ -0,0 +1,18 @@ +load("//tools:defs.bzl", "go_library") + +package( + default_applicable_licenses = ["//:license"], + licenses = ["notice"], +) + +go_library( + name = "containermetrics", + srcs = ["containermetrics.go"], + visibility = [ + "//:sandbox", + ], + deps = [ + "//pkg/prometheus", + "//runsc/container", + ], +) diff --git a/runsc/metricserver/containermetrics/containermetrics.go b/runsc/metricserver/containermetrics/containermetrics.go new file mode 100644 index 000000000..9d9ce543c --- /dev/null +++ b/runsc/metricserver/containermetrics/containermetrics.go @@ -0,0 +1,87 @@ +// Copyright 2023 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 containermetrics returns metrics and labels interesting to export +// about a container or sandbox. +package containermetrics + +import ( + "crypto/sha256" + "encoding/binary" + "io" + "strconv" + + "gvisor.dev/gvisor/pkg/prometheus" + "gvisor.dev/gvisor/runsc/container" +) + +// SandboxPrometheusLabels returns a set of Prometheus labels that identifies the sandbox running +// the given root container. +func SandboxPrometheusLabels(rootContainer *container.Container) (map[string]string, error) { + s := rootContainer.Sandbox + labels := make(map[string]string, 4) + labels[prometheus.SandboxIDLabel] = s.ID + + // Compute iteration ID label in a stable manner. + // This uses sha256(ID + ":" + creation time). + h := sha256.New() + if _, err := io.WriteString(h, s.ID); err != nil { + return nil, err + } + if _, err := io.WriteString(h, ":"); err != nil { + return nil, err + } + if _, err := io.WriteString(h, rootContainer.CreatedAt.UTC().String()); err != nil { + return nil, err + } + labels[prometheus.IterationIDLabel] = strconv.FormatUint(binary.BigEndian.Uint64(h.Sum(nil)[:8]), 36) + + if s.PodName != "" { + labels[prometheus.PodNameLabel] = s.PodName + } + if s.Namespace != "" { + labels[prometheus.NamespaceLabel] = s.Namespace + } + return labels, nil +} + +// ComputeSpecMetadata returns the labels for the `spec_metadata` metric. +// It merges data from the Specs of multiple containers running within the +// same sandbox. +// This function must support being called with `allContainers` being nil. +// It must return the same set of label keys regardless of how many containers +// are in `allContainers`. +func ComputeSpecMetadata(allContainers []*container.Container) map[string]string { + const ( + unknownOCIVersion = "UNKNOWN" + inconsistentOCIVersion = "INCONSISTENT" + ) + + hasUID0Container := false + ociVersion := unknownOCIVersion + for _, cont := range allContainers { + if cont.RunsAsUID0() { + hasUID0Container = true + } + if ociVersion == unknownOCIVersion { + ociVersion = cont.Spec.Version + } else if ociVersion != cont.Spec.Version { + ociVersion = inconsistentOCIVersion + } + } + return map[string]string{ + "hasuid0": strconv.FormatBool(hasUID0Container), + "ociversion": ociVersion, + } +} diff --git a/runsc/metricserver/metricserver.go b/runsc/metricserver/metricserver.go index d28bb999a..72f569fa6 100644 --- a/runsc/metricserver/metricserver.go +++ b/runsc/metricserver/metricserver.go @@ -43,6 +43,7 @@ import ( "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/runsc/config" "gvisor.dev/gvisor/runsc/container" + "gvisor.dev/gvisor/runsc/metricserver/containermetrics" "gvisor.dev/gvisor/runsc/sandbox" ) @@ -141,7 +142,7 @@ func (s *servedSandbox) load() (*sandbox.Sandbox, *prometheus.Verifier, error) { } // Update label data as read from the state file. // Do not store empty labels. - authoritativeLabels, err := SandboxPrometheusLabels(rootContainer) + authoritativeLabels, err := containermetrics.SandboxPrometheusLabels(rootContainer) if err != nil { return nil, nil, fmt.Errorf("cannot compute Prometheus labels of sandbox: %v", err) } @@ -178,7 +179,7 @@ func (s *servedSandbox) load() (*sandbox.Sandbox, *prometheus.Verifier, error) { } // Compute spec metadata. - s.specMetadataLabels = ComputeSpecMetadata(allContainers) + s.specMetadataLabels = containermetrics.ComputeSpecMetadata(allContainers) s.sandbox = rootContainer.Sandbox s.createdAt = rootContainer.CreatedAt diff --git a/runsc/metricserver/metricserver_metrics.go b/runsc/metricserver/metricserver_metrics.go index fac3dc600..a8d58c4ee 100644 --- a/runsc/metricserver/metricserver_metrics.go +++ b/runsc/metricserver/metricserver_metrics.go @@ -15,13 +15,7 @@ package metricserver import ( - "crypto/sha256" - "encoding/binary" - "io" - "strconv" - "gvisor.dev/gvisor/pkg/prometheus" - "gvisor.dev/gvisor/runsc/container" ) // Metrics generated by the metrics server itself. @@ -87,63 +81,3 @@ var Metrics = []*prometheus.Metric{ &NumTotalSandboxesMetric, &prometheus.ProcessStartTimeSeconds, } - -// SandboxPrometheusLabels returns a set of Prometheus labels that identifies the sandbox running -// the given root container. -func SandboxPrometheusLabels(rootContainer *container.Container) (map[string]string, error) { - s := rootContainer.Sandbox - labels := make(map[string]string, 4) - labels[prometheus.SandboxIDLabel] = s.ID - - // Compute iteration ID label in a stable manner. - // This uses sha256(ID + ":" + creation time). - h := sha256.New() - if _, err := io.WriteString(h, s.ID); err != nil { - return nil, err - } - if _, err := io.WriteString(h, ":"); err != nil { - return nil, err - } - if _, err := io.WriteString(h, rootContainer.CreatedAt.UTC().String()); err != nil { - return nil, err - } - labels[prometheus.IterationIDLabel] = strconv.FormatUint(binary.BigEndian.Uint64(h.Sum(nil)[:8]), 36) - - if s.PodName != "" { - labels[prometheus.PodNameLabel] = s.PodName - } - if s.Namespace != "" { - labels[prometheus.NamespaceLabel] = s.Namespace - } - return labels, nil -} - -// ComputeSpecMetadata returns the labels for the `spec_metadata` metric. -// It merges data from the Specs of multiple containers running within the -// same sandbox. -// This function must support being called with `allContainers` being nil. -// It must return the same set of label keys regardless of how many containers -// are in `allContainers`. -func ComputeSpecMetadata(allContainers []*container.Container) map[string]string { - const ( - unknownOCIVersion = "UNKNOWN" - inconsistentOCIVersion = "INCONSISTENT" - ) - - hasUID0Container := false - ociVersion := unknownOCIVersion - for _, cont := range allContainers { - if cont.RunsAsUID0() { - hasUID0Container = true - } - if ociVersion == unknownOCIVersion { - ociVersion = cont.Spec.Version - } else if ociVersion != cont.Spec.Version { - ociVersion = inconsistentOCIVersion - } - } - return map[string]string{ - "hasuid0": strconv.FormatBool(hasUID0Container), - "ociversion": ociVersion, - } -}