Skip to content

Commit ef4c91e

Browse files
Implement metrics annotation (#2588)
* Implement metrics annotation * Changes * Suggested changes * Suggested changes * Attributor
1 parent cce430f commit ef4c91e

File tree

6 files changed

+429
-4
lines changed

6 files changed

+429
-4
lines changed

internal/cmdliveinit/cmdliveinit.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/GoogleContainerTools/kpt/internal/errors"
1717
"github.com/GoogleContainerTools/kpt/internal/pkg"
1818
"github.com/GoogleContainerTools/kpt/internal/printer"
19+
"github.com/GoogleContainerTools/kpt/internal/util/attribution"
1920
kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
2021
"github.com/GoogleContainerTools/kpt/pkg/kptfile/kptfileutil"
2122
"github.com/spf13/cobra"
@@ -174,6 +175,10 @@ func (c *ConfigureInventoryInfo) Run(ctx context.Context) error {
174175
if err != nil {
175176
return errors.E(op, c.Pkg.UniquePath, err)
176177
}
178+
// add metrics annotation to package resources to track the usage as the resources
179+
// will be applied using kpt live group
180+
at := attribution.Attributor{PackagePaths: []string{c.Pkg.UniquePath.String()}, CmdGroup: "live"}
181+
at.Process()
177182
return nil
178183
}
179184

internal/cmdrender/executor.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/GoogleContainerTools/kpt/internal/pkg"
2828
"github.com/GoogleContainerTools/kpt/internal/printer"
2929
"github.com/GoogleContainerTools/kpt/internal/types"
30+
"github.com/GoogleContainerTools/kpt/internal/util/attribution"
3031
"github.com/GoogleContainerTools/kpt/internal/util/printerutil"
3132
fnresult "github.com/GoogleContainerTools/kpt/pkg/api/fnresult/v1"
3233
kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
@@ -81,6 +82,11 @@ func (e *Executor) Execute(ctx context.Context) error {
8182
return err
8283
}
8384

85+
// add metrics annotation to output resources to track the usage as the resources
86+
// are rendered by kpt fn group
87+
at := attribution.Attributor{Resources: hctx.root.resources, CmdGroup: "fn"}
88+
at.Process()
89+
8490
if e.Output == nil {
8591
// the intent of the user is to modify resources in-place
8692
pkgWriter := &kio.LocalPackageReadWriter{
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package attribution
16+
17+
import (
18+
"fmt"
19+
"os"
20+
"strings"
21+
22+
"sigs.k8s.io/kustomize/kyaml/kio"
23+
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
24+
)
25+
26+
const (
27+
CNRMMetricsAnnotation = "cnrm.cloud.google.com/blueprint"
28+
DisableKptAttributionEnvVariable = "KPT_DISABLE_ATTRIBUTION"
29+
)
30+
31+
// Attributor is used to attribute the kpt action on resources
32+
type Attributor struct {
33+
// PackagePaths is the package paths to add the attribution annotation
34+
PackagePaths []string
35+
36+
// Resources to add the attribution annotation
37+
Resources []*kyaml.RNode
38+
39+
// CmdGroup is the command groups in kpt, e.g., pkg, fn, live
40+
CmdGroup string
41+
}
42+
43+
// Process invokes Attribution kyaml filter on the resources in input packages paths
44+
func (a *Attributor) Process() {
45+
// users can opt-out by setting the "KPT_DISABLE_ATTRIBUTION" environment variable
46+
if os.Getenv(DisableKptAttributionEnvVariable) != "" {
47+
return
48+
}
49+
50+
if a.CmdGroup == "" {
51+
return
52+
}
53+
54+
for _, path := range a.PackagePaths {
55+
inout := &kio.LocalPackageReadWriter{PackagePath: path, PreserveSeqIndent: true, WrapBareSeqNode: true}
56+
err := kio.Pipeline{
57+
Inputs: []kio.Reader{inout},
58+
Filters: []kio.Filter{kio.FilterAll(a)},
59+
Outputs: []kio.Writer{inout},
60+
}.Execute()
61+
if err != nil {
62+
// this should be a best effort, do not error if this step fails
63+
// https://github.com/GoogleContainerTools/kpt/issues/2559
64+
return
65+
}
66+
}
67+
68+
for _, resource := range a.Resources {
69+
_, _ = a.Filter(resource)
70+
}
71+
}
72+
73+
// Filter implements kyaml.Filter
74+
// this filter adds "cnrm.cloud.google.com/blueprint" annotation to the resource
75+
// if the annotation is already present, it appends kpt-<cmdGroup> suffix
76+
// it uses "default" namespace
77+
func (a *Attributor) Filter(object *kyaml.RNode) (*kyaml.RNode, error) {
78+
// users can opt-out by setting the "KPT_DISABLE_ATTRIBUTION" environment variable
79+
if os.Getenv(DisableKptAttributionEnvVariable) != "" {
80+
return object, nil
81+
}
82+
83+
// add this annotation to only KCC resource types
84+
if !strings.Contains(object.GetApiVersion(), ".cnrm.") {
85+
return object, nil
86+
}
87+
88+
curAnnoVal := object.GetAnnotations()[CNRMMetricsAnnotation]
89+
mf := object.Field(kyaml.MetadataField)
90+
if mf.IsNilOrEmpty() {
91+
// skip adding merge comment if empty metadata
92+
return object, nil
93+
}
94+
if _, err := object.Pipe(kyaml.SetAnnotation(CNRMMetricsAnnotation, recordAction(curAnnoVal, a.CmdGroup))); err != nil {
95+
return object, nil
96+
}
97+
return object, nil
98+
}
99+
100+
// recordAction appends the input cmdGroup to the annotation to attribute the usage
101+
// if the cmdGroup is already present, then it is no-op
102+
func recordAction(curAnnoVal, cmdGroup string) string {
103+
if curAnnoVal == "" {
104+
return fmt.Sprintf("kpt-%s", cmdGroup)
105+
}
106+
if !strings.Contains(curAnnoVal, "kpt-") {
107+
// just append the value
108+
return fmt.Sprintf("%s,kpt-%s", curAnnoVal, cmdGroup)
109+
}
110+
// we want to extract the current kpt part from the annotation
111+
// value and make sure that the input cmdGroup is added
112+
// e.g. curAnnoVal: cnrm/landing-zone:networking/v0.4.0,kpt-pkg,blueprints_controller
113+
curAnnoParts := strings.Split(curAnnoVal, ",")
114+
115+
// form the new kpt part value
116+
newKptPart := []string{"kpt"}
117+
118+
for i, curAnnoPart := range curAnnoParts {
119+
if strings.Contains(curAnnoPart, "kpt") {
120+
if strings.Contains(curAnnoPart, "pkg") || cmdGroup == "pkg" {
121+
newKptPart = append(newKptPart, "pkg")
122+
}
123+
if strings.Contains(curAnnoPart, "fn") || cmdGroup == "fn" {
124+
newKptPart = append(newKptPart, "fn")
125+
}
126+
if strings.Contains(curAnnoPart, "live") || cmdGroup == "live" {
127+
newKptPart = append(newKptPart, "live")
128+
}
129+
// replace the kpt part with the newly formed part
130+
curAnnoParts[i] = strings.Join(newKptPart, "-")
131+
}
132+
}
133+
return strings.Join(curAnnoParts, ",")
134+
}

0 commit comments

Comments
 (0)