diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..8d0d4925 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto +pkg/crds/client linguist-generated=true +zz_generated*.go linguist-generated=true diff --git a/Makefile b/Makefile index 5b928d5a..1daa3070 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ endif LINKER_WORKER_COUNT ?= 1 -CONTROLLERS ?= audit-consumer,audit-producer,audit-webhook,event-informer,annotation-linker,owner-linker,resource-object-tag,resource-event-tag,diff-decorator,diff-controller,diff-api,pprof,jaeger-storage-plugin,jaeger-redirect-server,kelemetrix +CONTROLLERS ?= audit-consumer,audit-producer,audit-webhook,event-informer,annotation-linker,owner-linker,rule-linker,resource-object-tag,resource-event-tag,diff-decorator,diff-controller,diff-api,pprof,jaeger-storage-plugin,jaeger-redirect-server,kelemetrix ifeq ($(CONTROLLERS),) ENABLE_ARGS ?= else @@ -181,3 +181,36 @@ fmt: golines -m140 --base-formatter=gofumpt -w . goimports -l -w . gci write -s standard -s default -s 'prefix(github.com/kubewharf/kelemetry)' . + +generate: + go run sigs.k8s.io/controller-tools/cmd/controller-gen \ + crd \ + paths=./pkg/crds/apis/... \ + output:crd:dir=./crds/config + go run k8s.io/code-generator/cmd/deepcopy-gen \ + -o /tmp/kelemetry-gen/github.com/kubewharf/kelemetry \ + --input-dirs=./pkg/crds/apis/v1alpha1 \ + --output-file-base=zz_generated.deepcopy \ + -h ./hack/boilerplate.txt + go run k8s.io/code-generator/cmd/client-gen \ + -o /tmp/kelemetry-gen \ + --input=github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1 \ + --input-base= \ + --output-package=github.com/kubewharf/kelemetry/pkg/crds/client/clientset \ + --clientset-name=versioned \ + -h ./hack/boilerplate.txt + go run k8s.io/code-generator/cmd/lister-gen \ + -o /tmp/kelemetry-gen \ + --input-dirs=github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1 \ + --output-package=github.com/kubewharf/kelemetry/pkg/crds/client/listers \ + -h ./hack/boilerplate.txt + go run k8s.io/code-generator/cmd/informer-gen \ + -o /tmp/kelemetry-gen \ + --input-dirs=github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1 \ + --output-package=github.com/kubewharf/kelemetry/pkg/crds/client/informers \ + --versioned-clientset-package=github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned \ + --listers-package=github.com/kubewharf/kelemetry/pkg/crds/client/listers \ + -h ./hack/boilerplate.txt + cp -r /tmp/kelemetry-gen/github.com/kubewharf/kelemetry/pkg/crds -T pkg/crds + rm -r /tmp/kelemetry-gen + $(MAKE) fmt diff --git a/charts/kelemetry/crds b/charts/kelemetry/crds new file mode 120000 index 00000000..17e154c7 --- /dev/null +++ b/charts/kelemetry/crds @@ -0,0 +1 @@ +../../crds/config \ No newline at end of file diff --git a/crds/config/kelemetry.kubewharf.io_linkrules.yaml b/crds/config/kelemetry.kubewharf.io_linkrules.yaml new file mode 100644 index 00000000..4aecc644 --- /dev/null +++ b/crds/config/kelemetry.kubewharf.io_linkrules.yaml @@ -0,0 +1,163 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.0 + name: linkrules.kelemetry.kubewharf.io +spec: + group: kelemetry.kubewharf.io + names: + kind: LinkRule + listKind: LinkRuleList + plural: linkrules + singular: linkrule + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: "LinkRule instructs Kelemetry to display multiple objects (the + \"source\" and the \"target\") in the same trace by looking up the \"target\" + when the span of the \"source\" object gets created. \n LinkRule is bidirectional. + Once the link is recorded, searching \"source\" or \"target\" would both + display the other trace in the link as long as the link is not filtered + out by tfconfig." + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + link: + description: Link specifies how the two objects are linked together. + properties: + class: + description: "If Class is non empty, a pseudospan named the given + value is inserted in the hierarchy between the target and source + objects. \n Multiple links with the same nonempty Class share the + same pseudospan." + type: string + targetRole: + default: Child + description: "TargetRole selects the display position of the target + object. \n One of the target objects will be arbitrarily selected + if there are multiple links with preferTargetParent=true." + type: string + required: + - targetRole + type: object + metadata: + type: object + sourceFilter: + description: SourceFilter determines whether a source object matches this + rule. + properties: + resources: + description: Resources are the possible resource types that a child + object may belong to. + items: + description: GroupResource specifies a Group and a Resource, but + does not force a version. This is useful for identifying concepts + during lookup stages without having partially valid types + properties: + group: + type: string + resource: + type: string + required: + - group + - resource + type: object + type: array + selector: + description: Selector selects matching child objects by label. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + targetTemplate: + description: TargetTemplate indicates how to find the target object from + a matched source object. + properties: + clusterTemplate: + description: "ClusterTemplate is a Go text template string to compute + the cluster name of the target object. \n The context of the template + is the child object that matched the rule. \n If empty or unspecified, + uses the cluster of the child object." + type: string + group: + type: string + nameTemplate: + description: "NameTemplate is a Go text template string to compute + the target object name. \n The context of the template is the child + object that matched the rule." + type: string + namespaceTemplate: + description: "NamespaceTemplate is a Go text template string to compute + the target object name. \n If the namespace is empty, the target + object is expected to be cluster-scoped." + type: string + resource: + type: string + version: + type: string + required: + - group + - nameTemplate + - namespaceTemplate + - resource + - version + type: object + required: + - link + - sourceFilter + - targetTemplate + type: object + served: true + storage: true diff --git a/crds/samples/helm-release-link-rule.yaml b/crds/samples/helm-release-link-rule.yaml new file mode 100644 index 00000000..f7b66e3c --- /dev/null +++ b/crds/samples/helm-release-link-rule.yaml @@ -0,0 +1,17 @@ +apiVersion: kelemetry.kubewharf.io/v1alpha1 +kind: LinkRule +metadata: + name: helm-release +sourceFilter: + selector: + matchLabels: + app.kubernetes.io/managed-by: Helm +targetTemplate: + group: "" + version: v1 + resource: secrets + namespaceTemplate: '{{.metadata.annotations["meta.helm.sh/release-namespace"]}}' + nameTemplate: '{{.metadata.annotations["meta.helm.sh/release-name"]}}' +link: + targetRole: Parent + class: templates diff --git a/go.mod b/go.mod index 8f84b9dc..0be87e26 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/eapache/queue v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.10.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/fatih/color v1.14.1 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -61,6 +61,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/gobuffalo/flect v1.0.2 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gocql/gocql v1.3.2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -84,6 +85,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/imdario/mergo v0.3.13 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect @@ -115,6 +117,7 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect @@ -132,12 +135,14 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.13.0 // indirect + golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.15.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sys v0.12.0 // indirect golang.org/x/term v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.8.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect @@ -147,7 +152,11 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.27.1 // indirect + k8s.io/code-generator v0.27.3 // indirect + k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + sigs.k8s.io/controller-tools v0.12.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index 4011b2f8..37ea7ccf 100644 --- a/go.sum +++ b/go.sum @@ -90,6 +90,7 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/crossdock/crossdock-go v0.0.0-20160816171116-049aabb0122b h1:WR1qVJzbvrVywhAk4kMQKRPx09AZVI0NdEdYs59iHcA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -126,6 +127,8 @@ github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -140,6 +143,7 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= @@ -160,6 +164,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= +github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gocql/gocql v1.3.2 h1:ox3T+R7VFibHSIGxRkuUi1uIvAv8jBHCWxc+9aFQ/LA= @@ -225,6 +231,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -278,6 +285,7 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jaegertracing/jaeger v1.49.0 h1:3XI8ZOK6oncyoAxCiKakC9sRaeDTdDwmxmaSN+KQBo8= github.com/jaegertracing/jaeger v1.49.0/go.mod h1:gU5wCSJSwk5MJHO/uWEBYKklT80oqEc2ixj3ssbwloQ= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= @@ -309,6 +317,7 @@ github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZX github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -377,6 +386,7 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqn github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -390,6 +400,7 @@ github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -520,6 +531,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -688,6 +701,7 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -705,6 +719,7 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -837,12 +852,19 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.28.1 h1:i+0O8k2NPBCPYaMB+uCkseEbawEt/eFaiRqUx8aB108= k8s.io/api v0.28.1/go.mod h1:uBYwID+66wiL28Kn2tBjBYQdEU0Xk0z5qF8bIBqk/Dg= +k8s.io/apiextensions-apiserver v0.27.1 h1:Hp7B3KxKHBZ/FxmVFVpaDiXI6CCSr49P1OJjxKO6o4g= +k8s.io/apiextensions-apiserver v0.27.1/go.mod h1:8jEvRDtKjVtWmdkhOqE84EcNWJt/uwF8PC4627UZghY= k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= k8s.io/apiserver v0.28.1 h1:dw2/NKauDZCnOUAzIo2hFhtBRUo6gQK832NV8kuDbGM= k8s.io/apiserver v0.28.1/go.mod h1:d8aizlSRB6yRgJ6PKfDkdwCy2DXt/d1FDR6iJN9kY1w= k8s.io/client-go v0.28.1 h1:pRhMzB8HyLfVwpngWKE8hDcXRqifh1ga2Z/PU9SXVK8= k8s.io/client-go v0.28.1/go.mod h1:pEZA3FqOsVkCc07pFVzK076R+P/eXqsgx5zuuRWukNE= +k8s.io/code-generator v0.27.3 h1:JRhRQkzKdQhHmv9s5f7vuqveL8qukAQ2IqaHm6MFspM= +k8s.io/code-generator v0.27.3/go.mod h1:DPung1sI5vBgn4AGKtlPRQAyagj/ir/4jI55ipZHVww= +k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08= +k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= @@ -853,9 +875,12 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-tools v0.12.0 h1:TY6CGE6+6hzO7hhJFte65ud3cFmmZW947jajXkuDfBw= +sigs.k8s.io/controller-tools v0.12.0/go.mod h1:rXlpTfFHZMpZA8aGq9ejArgZiieHd+fkk/fTatY8A2M= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/hack/boilerplate.txt b/hack/boilerplate.txt new file mode 100644 index 00000000..143af851 --- /dev/null +++ b/hack/boilerplate.txt @@ -0,0 +1,14 @@ +// Copyright 2023 The Kelemetry 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. + diff --git a/hack/typos.toml b/hack/typos.toml index c9406868..c2ab504e 100644 --- a/hack/typos.toml +++ b/hack/typos.toml @@ -1,5 +1,5 @@ [files] -extend-exclude = ["go.mod", "go.sum"] +extend-exclude = ["go.mod", "go.sum", "crds/config/*.yaml"] [default.extend-identifiers] -O_WRONLY = "O_WRONLY" +ANDed = "ANDed" diff --git a/pkg/annotationlinker/linker.go b/pkg/aggregator/linker/annotation/linker.go similarity index 100% rename from pkg/annotationlinker/linker.go rename to pkg/aggregator/linker/annotation/linker.go diff --git a/pkg/annotationlinker/schema.go b/pkg/aggregator/linker/annotation/schema.go similarity index 100% rename from pkg/annotationlinker/schema.go rename to pkg/aggregator/linker/annotation/schema.go diff --git a/pkg/ownerlinker/linker.go b/pkg/aggregator/linker/owner/linker.go similarity index 100% rename from pkg/ownerlinker/linker.go rename to pkg/aggregator/linker/owner/linker.go diff --git a/pkg/aggregator/linker/rule/linker.go b/pkg/aggregator/linker/rule/linker.go new file mode 100644 index 00000000..3ea05080 --- /dev/null +++ b/pkg/aggregator/linker/rule/linker.go @@ -0,0 +1,278 @@ +// Copyright 2023 The Kelemetry 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 rulelinker + +import ( + "context" + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/sirupsen/logrus" + "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + "k8s.io/utils/clock" + + "github.com/kubewharf/kelemetry/pkg/aggregator/linker" + kelemetryv1a1util "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1/util" + "github.com/kubewharf/kelemetry/pkg/crds/client/informers/externalversions/apis/v1alpha1" + kelemetryv1a1listers "github.com/kubewharf/kelemetry/pkg/crds/client/listers/apis/v1alpha1" + "github.com/kubewharf/kelemetry/pkg/k8s" + "github.com/kubewharf/kelemetry/pkg/k8s/discovery" + "github.com/kubewharf/kelemetry/pkg/k8s/objectcache" + "github.com/kubewharf/kelemetry/pkg/manager" + utilobject "github.com/kubewharf/kelemetry/pkg/util/object" + reflectutil "github.com/kubewharf/kelemetry/pkg/util/reflect" + "github.com/kubewharf/kelemetry/pkg/util/zconstants" +) + +func init() { + manager.Global.ProvideListImpl("rule-linker", manager.Ptr(&Controller{}), &manager.List[linker.Linker]{}) +} + +type Options struct { + Enable bool + InformerTtl time.Duration + CacheSyncTimeout time.Duration +} + +func (options *Options) Setup(fs *pflag.FlagSet) { + fs.BoolVar(&options.Enable, "rule-linker-enable", false, "enable rule linker") + fs.DurationVar( + &options.InformerTtl, + "rule-linker-informer-ttl", + time.Hour, + "duration for which the LinkRule lister is unused before the reflector is closed", + ) + fs.DurationVar( + &options.CacheSyncTimeout, + "rule-linker-sync-timeout", + time.Second*5, + "duration to wait for the initial LinkRule list to become ready; timeout has no effect other than potentially missing link rules in some objects", + ) +} + +func (options *Options) EnableFlag() *bool { return &options.Enable } + +type Controller struct { + options Options + Logger logrus.FieldLogger + Clock clock.Clock + Clients k8s.Clients + Discovery discovery.DiscoveryCache + ObjectCache *objectcache.ObjectCache + + listersMu sync.RWMutex + listers map[string]*listerEntry +} + +type listerEntry struct { + readyCh <-chan struct{} + lister kelemetryv1a1listers.LinkRuleLister + err error + resetTimer func(time.Duration) +} + +var _ manager.Component = &Controller{} + +func (ctrl *Controller) Options() manager.Options { return &ctrl.options } +func (ctrl *Controller) Init() error { + ctrl.listers = make(map[string]*listerEntry) + return nil +} +func (ctrl *Controller) Start(ctx context.Context) error { return nil } +func (ctrl *Controller) Close(ctx context.Context) error { return nil } + +var _ linker.Linker = &Controller{} + +func (ctrl *Controller) LinkerName() string { return "rule-linker" } + +func (ctrl *Controller) Lookup(ctx context.Context, object utilobject.Rich) ([]linker.LinkerResult, error) { + logger := ctrl.Logger.WithFields(object.AsFields("object")) + + raw := object.Raw + if raw == nil { + logger.Debug("Fetching dynamic object") + + var err error + raw, err = ctrl.ObjectCache.Get(ctx, object.VersionedKey) + if err != nil { + return nil, fmt.Errorf("cannot fetch object value: %w", err) + } + + if raw == nil { + return nil, fmt.Errorf("object does not exist") + } + } + + lister, err := ctrl.getLister(ctx, object.Cluster) + if err != nil { + return nil, fmt.Errorf("lister is unavailable for cluster %q", object.Cluster) + } + + var results []linker.LinkerResult + + rules, err := lister.List(labels.Everything()) + if err != nil { + return nil, fmt.Errorf("cannot list rules") + } + + for _, rule := range rules { + matched, err := kelemetryv1a1util.TestObject(object.Key, raw, &rule.SourceFilter) + if err != nil { + logger.WithField("rule", rule.Name).WithError(err).Error("error testing object for rule match") + continue + } + + if !matched { + continue + } + + parentRef, err := kelemetryv1a1util.GenerateTarget(&rule.TargetTemplate, object, raw) + if err != nil { + return nil, fmt.Errorf("cannot infer parent object: %w", err) + } + + logger.WithField("rule", rule.Name).WithFields(parentRef.AsFields("parent")).Debug("Testing if parent exists") + parentRaw, err := ctrl.ObjectCache.Get(ctx, parentRef) + if err != nil { + return nil, fmt.Errorf("cannot get parent specified by rule: %w", err) + } + + role, err := zconstants.LinkRoleValueFromTargetRole(rule.Link.TargetRole) + if err != nil { + return nil, fmt.Errorf("cannot parse target role: %w", err) + } + + results = append(results, linker.LinkerResult{ + Object: utilobject.Rich{ + VersionedKey: parentRef, + Uid: parentRaw.GetUID(), + Raw: parentRaw, + }, + Role: role, + }) + } + + return results, nil +} + +func (ctrl *Controller) getLister(ctx context.Context, cluster string) (kelemetryv1a1listers.LinkRuleLister, error) { + if lister, exists := ctrl.tryGetLister(cluster); exists { + return lister.touch(ctrl.options.InformerTtl) + } + + entry, readyCh := ctrl.setPendingLister(cluster) + if readyCh == nil { + return entry.touch(ctrl.options.InformerTtl) + } + + defer close(readyCh) + + client, err := ctrl.Clients.Cluster(cluster) + if err != nil { + err := fmt.Errorf("cannot initialize clients for cluster %q: %w", cluster, err) + entry.err = err + return nil, err + } + + informer := v1alpha1.NewLinkRuleInformer(client.KelemetryClient(), 0, cache.Indexers{}) + + entry.lister = kelemetryv1a1listers.NewLinkRuleLister(informer.GetIndexer()) + + timerCh, resetFunc := startTimer(ctrl.Clock, ctrl.options.InformerTtl) + go informer.Run(timerCh) + + waitCtx, waitCtxCancelFunc := context.WithTimeout(ctx, ctrl.options.CacheSyncTimeout) + defer waitCtxCancelFunc() + populated := cache.WaitForCacheSync(waitCtx.Done(), informer.HasSynced) + if !populated { + ctrl.Logger.WithField("cluster", cluster).Warn("LinkRule lister has not synced, will continue as usual") + } + + entry.resetTimer = resetFunc + + return entry.lister, nil +} + +func (ctrl *Controller) tryGetLister(cluster string) (*listerEntry, bool) { + ctrl.listersMu.RLock() + defer ctrl.listersMu.RUnlock() + lister, exists := ctrl.listers[cluster] + return lister, exists +} + +func (ctrl *Controller) setPendingLister(cluster string) (_ *listerEntry, _readyCh chan<- struct{}) { + ctrl.listersMu.Lock() + defer ctrl.listersMu.Unlock() + + lister, exists := ctrl.listers[cluster] + if exists { + return lister, nil + } + + readyCh := make(chan struct{}) + + entry := &listerEntry{ + readyCh: readyCh, + } + ctrl.listers[cluster] = entry + + return entry, readyCh +} + +func (entry *listerEntry) touch(ttl time.Duration) (kelemetryv1a1listers.LinkRuleLister, error) { + <-entry.readyCh + if entry.err != nil { + return nil, entry.err + } + + entry.resetTimer(ttl) + return entry.lister, nil +} + +// a specialized timer optimized for frequent resets and only supports strictly increasing resets. +func startTimer(clock clock.Clock, initialTtl time.Duration) (<-chan struct{}, func(time.Duration)) { + timerCh := make(chan struct{}) + + var targetAtomic atomic.Pointer[time.Time] + targetAtomic.Store(reflectutil.Box(clock.Now().Add(initialTtl))) + + go func() { + target := targetAtomic.Load() + + for { + remaining := (*target).Sub(clock.Now()) + if remaining <= 0 { + break + } + + clock.Sleep(remaining) + newTarget := targetAtomic.Load() + if newTarget == target { + break // break without checking clock.Now() to ensure we don't sleep on the same target multiple times + } + target = newTarget + } + + timerCh <- struct{}{} + }() + + return timerCh, func(newTtl time.Duration) { + targetAtomic.Store(reflectutil.Box(clock.Now().Add(newTtl))) + } +} diff --git a/pkg/crds/apis/register.go b/pkg/crds/apis/register.go new file mode 100644 index 00000000..5cf6a170 --- /dev/null +++ b/pkg/crds/apis/register.go @@ -0,0 +1,15 @@ +// 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 kelemetry + +const GroupName = "kelemetry.kubewharf.io" diff --git a/pkg/crds/apis/v1alpha1/doc.go b/pkg/crds/apis/v1alpha1/doc.go new file mode 100644 index 00000000..d6764c1e --- /dev/null +++ b/pkg/crds/apis/v1alpha1/doc.go @@ -0,0 +1,16 @@ +// 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. + +// +k8s:deepcopy-gen=package +// +groupName=kelemetry.kubewharf.io + +package v1alpha1 diff --git a/pkg/crds/apis/v1alpha1/register.go b/pkg/crds/apis/v1alpha1/register.go new file mode 100644 index 00000000..4f858cac --- /dev/null +++ b/pkg/crds/apis/v1alpha1/register.go @@ -0,0 +1,46 @@ +// 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + kelemetry "github.com/kubewharf/kelemetry/pkg/crds/apis" +) + +var SchemeGroupVersion = schema.GroupVersion{ + Group: kelemetry.GroupName, + Version: "v1alpha1", +} + +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + localSchemeBuilder.Register(addKnownTypes) +} + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, &LinkRule{}, &LinkRuleList{}) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/crds/apis/v1alpha1/types_linkrule.go b/pkg/crds/apis/v1alpha1/types_linkrule.go new file mode 100644 index 00000000..61705cc8 --- /dev/null +++ b/pkg/crds/apis/v1alpha1/types_linkrule.go @@ -0,0 +1,114 @@ +// Copyright 2023 The Kelemetry 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:validation:Required +// +kubebuilder:resource:path=linkrules,scope=Cluster +// +kubebuilder:object:root=true + +// LinkRule instructs Kelemetry to display multiple objects (the "source" and the "target") in the same trace +// by looking up the "target" when the span of the "source" object gets created. +// +// LinkRule is bidirectional. +// Once the link is recorded, searching "source" or "target" would both display the other trace in the link +// as long as the link is not filtered out by tfconfig. +type LinkRule struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // SourceFilter determines whether a source object matches this rule. + SourceFilter LinkRuleSourceFilter `json:"sourceFilter"` + + // TargetTemplate indicates how to find the target object from a matched source object. + TargetTemplate LinkRuleTargetTemplate `json:"targetTemplate"` + + // Link specifies how the two objects are linked together. + Link LinkRuleLink `json:"link"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type LinkRuleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []LinkRule `json:"items"` +} + +// LinkRuleSourceFilter determines whether an object is a child object that matches a rule. +type LinkRuleSourceFilter struct { + // Resources are the possible resource types that a child object may belong to. + // + // +optional + Resources *[]metav1.GroupResource `json:"resources"` + + // Selector selects matching child objects by label. + // + // +optional + Selector metav1.LabelSelector `json:"selector"` +} + +// LinkRuleTargetTemplate indicates how to find the target object from a matched source object. +type LinkRuleTargetTemplate struct { + // ClusterTemplate is a Go text template string to compute the cluster name of the target object. + // + // The context of the template is the child object that matched the rule. + // + // If empty or unspecified, uses the cluster of the child object. + // +optional + ClusterTemplate string `json:"clusterTemplate,omitempty"` + + // The type of the target object. + metav1.GroupVersionResource `json:",inline"` + + // NamespaceTemplate is a Go text template string to compute the target object name. + // + // If the namespace is empty, the target object is expected to be cluster-scoped. + NamespaceTemplate string `json:"namespaceTemplate"` + + // NameTemplate is a Go text template string to compute the target object name. + // + // The context of the template is the child object that matched the rule. + NameTemplate string `json:"nameTemplate"` +} + +// LinkRuleLink specifies how the two objects are linked together. +type LinkRuleLink struct { + // TargetRole selects the display position of the target object. + // + // One of the target objects will be arbitrarily selected if there are multiple links with preferTargetParent=true. + // +kubebuilder:default=Child + TargetRole TargetRole `json:"targetRole"` + + // If Class is non empty, a pseudospan named the given value is inserted in the hierarchy between the target and source objects. + // + // Multiple links with the same nonempty Class share the same pseudospan. + // +optional + Class string `json:"class,omitempty"` +} + +// TargetRole selects whether the target object is rendered as the parent or as the child of the source object. +type TargetRole string + +const ( + TargetRoleChild TargetRole = "Child" + TargetRoleParent TargetRole = "Parent" +) diff --git a/pkg/crds/apis/v1alpha1/util/util.go b/pkg/crds/apis/v1alpha1/util/util.go new file mode 100644 index 00000000..0dfd6cba --- /dev/null +++ b/pkg/crds/apis/v1alpha1/util/util.go @@ -0,0 +1,104 @@ +// Copyright 2023 The Kelemetry 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 kelemetryv1a1util + +import ( + "bytes" + "fmt" + "text/template" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/labels" + + kelemetryv1a1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" + utilobject "github.com/kubewharf/kelemetry/pkg/util/object" +) + +func TestObject(objectRef utilobject.Key, object metav1.Object, rule *kelemetryv1a1.LinkRuleSourceFilter) (bool, error) { + objectGr := metav1.GroupResource{Group: objectRef.Group, Resource: objectRef.Resource} + + if rule.Resources != nil { + matchedGr := false + for _, ruleGr := range *rule.Resources { + if ruleGr == objectGr { + matchedGr = true + } + } + + if !matchedGr { + return false, nil + } + } + + selector, err := metav1.LabelSelectorAsSelector(&rule.Selector) + if err != nil { + return false, fmt.Errorf("rule has invalid label selector: %w", err) + } + + objectLabels := labels.Set(object.GetLabels()) + + return selector.Matches(objectLabels), nil +} + +func GenerateTarget( + rule *kelemetryv1a1.LinkRuleTargetTemplate, + sourceObjectRef utilobject.Rich, + sourceObject *unstructured.Unstructured, +) (_target utilobject.VersionedKey, _ error) { + cluster := sourceObjectRef.Cluster + if rule.ClusterTemplate != "" { + var err error + cluster, err = executeTemplate("clusterTemplate", rule.ClusterTemplate, sourceObject) + if err != nil { + return _target, err + } + } + + namespace, err := executeTemplate("namespaceTemplate", rule.NamespaceTemplate, sourceObject) + if err != nil { + return _target, err + } + + name, err := executeTemplate("nameTemplate", rule.NameTemplate, sourceObject) + if err != nil { + return _target, err + } + + return utilobject.VersionedKey{ + Key: utilobject.Key{ + Cluster: cluster, + Group: rule.Group, + Resource: rule.Resource, + Namespace: namespace, + Name: name, + }, + Version: rule.Version, + }, nil +} + +func executeTemplate(templateName string, templateString string, sourceObject *unstructured.Unstructured) (string, error) { + tmpl, err := template.New(templateName).Parse(templateString) + if err != nil { + return "", fmt.Errorf("cannot parse %s as Go text/template: %w", templateName, err) + } + + buf := new(bytes.Buffer) + if err := tmpl.Execute(buf, sourceObject.Object); err != nil { + return "", fmt.Errorf("cannot execute %s: %w", templateName, err) + } + + return buf.String(), nil +} diff --git a/pkg/crds/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/crds/apis/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..0ee4eb77 --- /dev/null +++ b/pkg/crds/apis/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,146 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Copyright 2023 The Kelemetry 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. + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LinkRule) DeepCopyInto(out *LinkRule) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.SourceFilter.DeepCopyInto(&out.SourceFilter) + out.TargetTemplate = in.TargetTemplate + out.Link = in.Link + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinkRule. +func (in *LinkRule) DeepCopy() *LinkRule { + if in == nil { + return nil + } + out := new(LinkRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LinkRule) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LinkRuleLink) DeepCopyInto(out *LinkRuleLink) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinkRuleLink. +func (in *LinkRuleLink) DeepCopy() *LinkRuleLink { + if in == nil { + return nil + } + out := new(LinkRuleLink) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LinkRuleList) DeepCopyInto(out *LinkRuleList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]LinkRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinkRuleList. +func (in *LinkRuleList) DeepCopy() *LinkRuleList { + if in == nil { + return nil + } + out := new(LinkRuleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LinkRuleList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LinkRuleSourceFilter) DeepCopyInto(out *LinkRuleSourceFilter) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = new([]v1.GroupResource) + if **in != nil { + in, out := *in, *out + *out = make([]v1.GroupResource, len(*in)) + copy(*out, *in) + } + } + in.Selector.DeepCopyInto(&out.Selector) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinkRuleSourceFilter. +func (in *LinkRuleSourceFilter) DeepCopy() *LinkRuleSourceFilter { + if in == nil { + return nil + } + out := new(LinkRuleSourceFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LinkRuleTargetTemplate) DeepCopyInto(out *LinkRuleTargetTemplate) { + *out = *in + out.GroupVersionResource = in.GroupVersionResource + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinkRuleTargetTemplate. +func (in *LinkRuleTargetTemplate) DeepCopy() *LinkRuleTargetTemplate { + if in == nil { + return nil + } + out := new(LinkRuleTargetTemplate) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/crds/client/clientset/versioned/clientset.go b/pkg/crds/client/clientset/versioned/clientset.go new file mode 100644 index 00000000..48ccc62d --- /dev/null +++ b/pkg/crds/client/clientset/versioned/clientset.go @@ -0,0 +1,119 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + "fmt" + "net/http" + + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + + kelemetryv1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + KelemetryV1alpha1() kelemetryv1alpha1.KelemetryV1alpha1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + kelemetryV1alpha1 *kelemetryv1alpha1.KelemetryV1alpha1Client +} + +// KelemetryV1alpha1 retrieves the KelemetryV1alpha1Client +func (c *Clientset) KelemetryV1alpha1() kelemetryv1alpha1.KelemetryV1alpha1Interface { + return c.kelemetryV1alpha1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.kelemetryV1alpha1, err = kelemetryv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.kelemetryV1alpha1 = kelemetryv1alpha1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/pkg/crds/client/clientset/versioned/fake/clientset_generated.go b/pkg/crds/client/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 00000000..4818e9b6 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,84 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + + clientset "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned" + kelemetryv1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1" + fakekelemetryv1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// KelemetryV1alpha1 retrieves the KelemetryV1alpha1Client +func (c *Clientset) KelemetryV1alpha1() kelemetryv1alpha1.KelemetryV1alpha1Interface { + return &fakekelemetryv1alpha1.FakeKelemetryV1alpha1{Fake: &c.Fake} +} diff --git a/pkg/crds/client/clientset/versioned/fake/doc.go b/pkg/crds/client/clientset/versioned/fake/doc.go new file mode 100644 index 00000000..87cb60a9 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/fake/doc.go @@ -0,0 +1,18 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/pkg/crds/client/clientset/versioned/fake/register.go b/pkg/crds/client/clientset/versioned/fake/register.go new file mode 100644 index 00000000..9a5acd79 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/fake/register.go @@ -0,0 +1,57 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + + kelemetryv1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" +) + +var ( + scheme = runtime.NewScheme() + codecs = serializer.NewCodecFactory(scheme) +) + +var localSchemeBuilder = runtime.SchemeBuilder{ + kelemetryv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/pkg/crds/client/clientset/versioned/scheme/doc.go b/pkg/crds/client/clientset/versioned/scheme/doc.go new file mode 100644 index 00000000..915166a5 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/scheme/doc.go @@ -0,0 +1,18 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/pkg/crds/client/clientset/versioned/scheme/register.go b/pkg/crds/client/clientset/versioned/scheme/register.go new file mode 100644 index 00000000..4c90e8cd --- /dev/null +++ b/pkg/crds/client/clientset/versioned/scheme/register.go @@ -0,0 +1,57 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + + kelemetryv1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" +) + +var ( + Scheme = runtime.NewScheme() + Codecs = serializer.NewCodecFactory(Scheme) + ParameterCodec = runtime.NewParameterCodec(Scheme) + localSchemeBuilder = runtime.SchemeBuilder{ + kelemetryv1alpha1.AddToScheme, + } +) + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/apis_client.go b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/apis_client.go new file mode 100644 index 00000000..177e7292 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/apis_client.go @@ -0,0 +1,106 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "net/http" + + rest "k8s.io/client-go/rest" + + v1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" + "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned/scheme" +) + +type KelemetryV1alpha1Interface interface { + RESTClient() rest.Interface + LinkRulesGetter +} + +// KelemetryV1alpha1Client is used to interact with features provided by the kelemetry.kubewharf.io group. +type KelemetryV1alpha1Client struct { + restClient rest.Interface +} + +func (c *KelemetryV1alpha1Client) LinkRules() LinkRuleInterface { + return newLinkRules(c) +} + +// NewForConfig creates a new KelemetryV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*KelemetryV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new KelemetryV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*KelemetryV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &KelemetryV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new KelemetryV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *KelemetryV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new KelemetryV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *KelemetryV1alpha1Client { + return &KelemetryV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *KelemetryV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/doc.go b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/doc.go new file mode 100644 index 00000000..e0863049 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/doc.go @@ -0,0 +1,18 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/doc.go b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/doc.go new file mode 100644 index 00000000..c677baf6 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/doc.go @@ -0,0 +1,18 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_apis_client.go b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_apis_client.go new file mode 100644 index 00000000..8bb25361 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_apis_client.go @@ -0,0 +1,39 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + + v1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1" +) + +type FakeKelemetryV1alpha1 struct { + *testing.Fake +} + +func (c *FakeKelemetryV1alpha1) LinkRules() v1alpha1.LinkRuleInterface { + return &FakeLinkRules{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeKelemetryV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_linkrule.go b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_linkrule.go new file mode 100644 index 00000000..e1d73037 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_linkrule.go @@ -0,0 +1,135 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + + v1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" +) + +// FakeLinkRules implements LinkRuleInterface +type FakeLinkRules struct { + Fake *FakeKelemetryV1alpha1 +} + +var linkrulesResource = v1alpha1.SchemeGroupVersion.WithResource("linkrules") + +var linkrulesKind = v1alpha1.SchemeGroupVersion.WithKind("LinkRule") + +// Get takes name of the linkRule, and returns the corresponding linkRule object, and an error if there is any. +func (c *FakeLinkRules) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LinkRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(linkrulesResource, name), &v1alpha1.LinkRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.LinkRule), err +} + +// List takes label and field selectors, and returns the list of LinkRules that match those selectors. +func (c *FakeLinkRules) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LinkRuleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(linkrulesResource, linkrulesKind, opts), &v1alpha1.LinkRuleList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.LinkRuleList{ListMeta: obj.(*v1alpha1.LinkRuleList).ListMeta} + for _, item := range obj.(*v1alpha1.LinkRuleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested linkRules. +func (c *FakeLinkRules) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(linkrulesResource, opts)) +} + +// Create takes the representation of a linkRule and creates it. Returns the server's representation of the linkRule, and an error, if there is any. +func (c *FakeLinkRules) Create( + ctx context.Context, + linkRule *v1alpha1.LinkRule, + opts v1.CreateOptions, +) (result *v1alpha1.LinkRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(linkrulesResource, linkRule), &v1alpha1.LinkRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.LinkRule), err +} + +// Update takes the representation of a linkRule and updates it. Returns the server's representation of the linkRule, and an error, if there is any. +func (c *FakeLinkRules) Update( + ctx context.Context, + linkRule *v1alpha1.LinkRule, + opts v1.UpdateOptions, +) (result *v1alpha1.LinkRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(linkrulesResource, linkRule), &v1alpha1.LinkRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.LinkRule), err +} + +// Delete takes name of the linkRule and deletes it. Returns an error if one occurs. +func (c *FakeLinkRules) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(linkrulesResource, name, opts), &v1alpha1.LinkRule{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeLinkRules) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(linkrulesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.LinkRuleList{}) + return err +} + +// Patch applies the patch and returns the patched linkRule. +func (c *FakeLinkRules) Patch( + ctx context.Context, + name string, + pt types.PatchType, + data []byte, + opts v1.PatchOptions, + subresources ...string, +) (result *v1alpha1.LinkRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(linkrulesResource, name, pt, data, subresources...), &v1alpha1.LinkRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.LinkRule), err +} diff --git a/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/generated_expansion.go b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/generated_expansion.go new file mode 100644 index 00000000..662577fd --- /dev/null +++ b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/generated_expansion.go @@ -0,0 +1,19 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +type LinkRuleExpansion interface{} diff --git a/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/linkrule.go b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/linkrule.go new file mode 100644 index 00000000..ebb1d240 --- /dev/null +++ b/pkg/crds/client/clientset/versioned/typed/apis/v1alpha1/linkrule.go @@ -0,0 +1,181 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + + v1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" + scheme "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned/scheme" +) + +// LinkRulesGetter has a method to return a LinkRuleInterface. +// A group's client should implement this interface. +type LinkRulesGetter interface { + LinkRules() LinkRuleInterface +} + +// LinkRuleInterface has methods to work with LinkRule resources. +type LinkRuleInterface interface { + Create(ctx context.Context, linkRule *v1alpha1.LinkRule, opts v1.CreateOptions) (*v1alpha1.LinkRule, error) + Update(ctx context.Context, linkRule *v1alpha1.LinkRule, opts v1.UpdateOptions) (*v1alpha1.LinkRule, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.LinkRule, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.LinkRuleList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch( + ctx context.Context, + name string, + pt types.PatchType, + data []byte, + opts v1.PatchOptions, + subresources ...string, + ) (result *v1alpha1.LinkRule, err error) + LinkRuleExpansion +} + +// linkRules implements LinkRuleInterface +type linkRules struct { + client rest.Interface +} + +// newLinkRules returns a LinkRules +func newLinkRules(c *KelemetryV1alpha1Client) *linkRules { + return &linkRules{ + client: c.RESTClient(), + } +} + +// Get takes name of the linkRule, and returns the corresponding linkRule object, and an error if there is any. +func (c *linkRules) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LinkRule, err error) { + result = &v1alpha1.LinkRule{} + err = c.client.Get(). + Resource("linkrules"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of LinkRules that match those selectors. +func (c *linkRules) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LinkRuleList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.LinkRuleList{} + err = c.client.Get(). + Resource("linkrules"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested linkRules. +func (c *linkRules) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("linkrules"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a linkRule and creates it. Returns the server's representation of the linkRule, and an error, if there is any. +func (c *linkRules) Create(ctx context.Context, linkRule *v1alpha1.LinkRule, opts v1.CreateOptions) (result *v1alpha1.LinkRule, err error) { + result = &v1alpha1.LinkRule{} + err = c.client.Post(). + Resource("linkrules"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(linkRule). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a linkRule and updates it. Returns the server's representation of the linkRule, and an error, if there is any. +func (c *linkRules) Update(ctx context.Context, linkRule *v1alpha1.LinkRule, opts v1.UpdateOptions) (result *v1alpha1.LinkRule, err error) { + result = &v1alpha1.LinkRule{} + err = c.client.Put(). + Resource("linkrules"). + Name(linkRule.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(linkRule). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the linkRule and deletes it. Returns an error if one occurs. +func (c *linkRules) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("linkrules"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *linkRules) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("linkrules"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched linkRule. +func (c *linkRules) Patch( + ctx context.Context, + name string, + pt types.PatchType, + data []byte, + opts v1.PatchOptions, + subresources ...string, +) (result *v1alpha1.LinkRule, err error) { + result = &v1alpha1.LinkRule{} + err = c.client.Patch(pt). + Resource("linkrules"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/crds/client/informers/externalversions/apis/interface.go b/pkg/crds/client/informers/externalversions/apis/interface.go new file mode 100644 index 00000000..f169df20 --- /dev/null +++ b/pkg/crds/client/informers/externalversions/apis/interface.go @@ -0,0 +1,44 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by informer-gen. DO NOT EDIT. + +package apis + +import ( + v1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/client/informers/externalversions/apis/v1alpha1" + internalinterfaces "github.com/kubewharf/kelemetry/pkg/crds/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/crds/client/informers/externalversions/apis/v1alpha1/interface.go b/pkg/crds/client/informers/externalversions/apis/v1alpha1/interface.go new file mode 100644 index 00000000..8b1043b7 --- /dev/null +++ b/pkg/crds/client/informers/externalversions/apis/v1alpha1/interface.go @@ -0,0 +1,43 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + internalinterfaces "github.com/kubewharf/kelemetry/pkg/crds/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // LinkRules returns a LinkRuleInformer. + LinkRules() LinkRuleInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// LinkRules returns a LinkRuleInformer. +func (v *version) LinkRules() LinkRuleInformer { + return &linkRuleInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/crds/client/informers/externalversions/apis/v1alpha1/linkrule.go b/pkg/crds/client/informers/externalversions/apis/v1alpha1/linkrule.go new file mode 100644 index 00000000..17e43f6f --- /dev/null +++ b/pkg/crds/client/informers/externalversions/apis/v1alpha1/linkrule.go @@ -0,0 +1,98 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + + apisv1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" + versioned "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned" + internalinterfaces "github.com/kubewharf/kelemetry/pkg/crds/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/client/listers/apis/v1alpha1" +) + +// LinkRuleInformer provides access to a shared informer and lister for +// LinkRules. +type LinkRuleInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.LinkRuleLister +} + +type linkRuleInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewLinkRuleInformer constructs a new informer for LinkRule type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewLinkRuleInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredLinkRuleInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredLinkRuleInformer constructs a new informer for LinkRule type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredLinkRuleInformer( + client versioned.Interface, + resyncPeriod time.Duration, + indexers cache.Indexers, + tweakListOptions internalinterfaces.TweakListOptionsFunc, +) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.KelemetryV1alpha1().LinkRules().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.KelemetryV1alpha1().LinkRules().Watch(context.TODO(), options) + }, + }, + &apisv1alpha1.LinkRule{}, + resyncPeriod, + indexers, + ) +} + +func (f *linkRuleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredLinkRuleInformer( + client, + resyncPeriod, + cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, + f.tweakListOptions, + ) +} + +func (f *linkRuleInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisv1alpha1.LinkRule{}, f.defaultInformer) +} + +func (f *linkRuleInformer) Lister() v1alpha1.LinkRuleLister { + return v1alpha1.NewLinkRuleLister(f.Informer().GetIndexer()) +} diff --git a/pkg/crds/client/informers/externalversions/factory.go b/pkg/crds/client/informers/externalversions/factory.go new file mode 100644 index 00000000..fed3298e --- /dev/null +++ b/pkg/crds/client/informers/externalversions/factory.go @@ -0,0 +1,259 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + + versioned "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned" + apis "github.com/kubewharf/kelemetry/pkg/crds/client/informers/externalversions/apis" + internalinterfaces "github.com/kubewharf/kelemetry/pkg/crds/client/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory( + client versioned.Interface, + defaultResync time.Duration, + namespace string, + tweakListOptions internalinterfaces.TweakListOptionsFunc, +) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions( + client versioned.Interface, + defaultResync time.Duration, + options ...SharedInformerOption, +) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InternalInformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + Kelemetry() apis.Interface +} + +func (f *sharedInformerFactory) Kelemetry() apis.Interface { + return apis.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/crds/client/informers/externalversions/generic.go b/pkg/crds/client/informers/externalversions/generic.go new file mode 100644 index 00000000..e9581f3f --- /dev/null +++ b/pkg/crds/client/informers/externalversions/generic.go @@ -0,0 +1,60 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + + v1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=kelemetry.kubewharf.io, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("linkrules"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Kelemetry().V1alpha1().LinkRules().Informer()}, nil + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/pkg/crds/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/crds/client/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 00000000..dcde767b --- /dev/null +++ b/pkg/crds/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,39 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + + versioned "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/pkg/crds/client/listers/apis/v1alpha1/expansion_generated.go b/pkg/crds/client/listers/apis/v1alpha1/expansion_generated.go new file mode 100644 index 00000000..015ba055 --- /dev/null +++ b/pkg/crds/client/listers/apis/v1alpha1/expansion_generated.go @@ -0,0 +1,21 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// LinkRuleListerExpansion allows custom methods to be added to +// LinkRuleLister. +type LinkRuleListerExpansion interface{} diff --git a/pkg/crds/client/listers/apis/v1alpha1/linkrule.go b/pkg/crds/client/listers/apis/v1alpha1/linkrule.go new file mode 100644 index 00000000..e40b46ed --- /dev/null +++ b/pkg/crds/client/listers/apis/v1alpha1/linkrule.go @@ -0,0 +1,67 @@ +// Copyright 2023 The Kelemetry 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. + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + + v1alpha1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" +) + +// LinkRuleLister helps list LinkRules. +// All objects returned here must be treated as read-only. +type LinkRuleLister interface { + // List lists all LinkRules in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.LinkRule, err error) + // Get retrieves the LinkRule from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.LinkRule, error) + LinkRuleListerExpansion +} + +// linkRuleLister implements the LinkRuleLister interface. +type linkRuleLister struct { + indexer cache.Indexer +} + +// NewLinkRuleLister returns a new LinkRuleLister. +func NewLinkRuleLister(indexer cache.Indexer) LinkRuleLister { + return &linkRuleLister{indexer: indexer} +} + +// List lists all LinkRules in the indexer. +func (s *linkRuleLister) List(selector labels.Selector) (ret []*v1alpha1.LinkRule, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.LinkRule)) + }) + return ret, err +} + +// Get retrieves the LinkRule from the index for a given name. +func (s *linkRuleLister) Get(name string) (*v1alpha1.LinkRule, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("linkrule"), name) + } + return obj.(*v1alpha1.LinkRule), nil +} diff --git a/pkg/imports.go b/pkg/imports.go index f7a779ff..86c029f7 100644 --- a/pkg/imports.go +++ b/pkg/imports.go @@ -18,13 +18,15 @@ package kelemetry_pkg import ( _ "github.com/kubewharf/kelemetry/pkg/aggregator/aggregatorevent" _ "github.com/kubewharf/kelemetry/pkg/aggregator/eventdecorator/eventtagger" + _ "github.com/kubewharf/kelemetry/pkg/aggregator/linker/annotation" _ "github.com/kubewharf/kelemetry/pkg/aggregator/linker/job/local" _ "github.com/kubewharf/kelemetry/pkg/aggregator/linker/job/worker" + _ "github.com/kubewharf/kelemetry/pkg/aggregator/linker/owner" + _ "github.com/kubewharf/kelemetry/pkg/aggregator/linker/rule" _ "github.com/kubewharf/kelemetry/pkg/aggregator/objectspandecorator/resourcetagger" _ "github.com/kubewharf/kelemetry/pkg/aggregator/spancache/etcd" _ "github.com/kubewharf/kelemetry/pkg/aggregator/spancache/local" _ "github.com/kubewharf/kelemetry/pkg/aggregator/tracer/otel" - _ "github.com/kubewharf/kelemetry/pkg/annotationlinker" _ "github.com/kubewharf/kelemetry/pkg/audit" _ "github.com/kubewharf/kelemetry/pkg/audit/consumer" _ "github.com/kubewharf/kelemetry/pkg/audit/dump" @@ -58,5 +60,4 @@ import ( _ "github.com/kubewharf/kelemetry/pkg/kelemetrix/defaults/tags" _ "github.com/kubewharf/kelemetry/pkg/metrics/noop" _ "github.com/kubewharf/kelemetry/pkg/metrics/prometheus" - _ "github.com/kubewharf/kelemetry/pkg/ownerlinker" ) diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index b8758370..cc29b2a7 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -35,6 +35,7 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/klog/v2" + kelemetryversioned "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned" k8sconfig "github.com/kubewharf/kelemetry/pkg/k8s/config" "github.com/kubewharf/kelemetry/pkg/manager" ) @@ -77,6 +78,7 @@ type Client interface { ClusterName() string DynamicClient() dynamic.Interface KubernetesClient() kubernetes.Interface + KelemetryClient() kelemetryversioned.Interface InformerFactory() informers.SharedInformerFactory NewInformerFactory(options ...informers.SharedInformerOption) informers.SharedInformerFactory EventRecorder(name string) record.EventRecorder @@ -99,6 +101,7 @@ type client struct { restConfig *rest.Config dynamicClient dynamic.Interface kubernetesClient *kubernetes.Clientset + kelemetryClient kelemetryversioned.Interface informerFactory informers.SharedInformerFactory eventBroadcaster record.EventBroadcaster } @@ -191,6 +194,11 @@ func (clients *clusterClients) newClient(name string) (*client, error) { return nil, fmt.Errorf("kubernetes client creation failed: %w", err) } + kelemetryClient, err := kelemetryversioned.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("kelemetry client creation failed: %w", err) + } + var informerFactory informers.SharedInformerFactory if atomic.LoadInt32(&clients.started) == 0 { // we do not support using informers on clusters created after start @@ -205,6 +213,7 @@ func (clients *clusterClients) newClient(name string) (*client, error) { restConfig: config, dynamicClient: dynamicClient, kubernetesClient: kubernetesClient, + kelemetryClient: kelemetryClient, informerFactory: informerFactory, eventBroadcaster: broadcaster, }, nil @@ -226,6 +235,10 @@ func (client *client) KubernetesClient() kubernetes.Interface { return client.kubernetesClient } +func (client *client) KelemetryClient() kelemetryversioned.Interface { + return client.kelemetryClient +} + func (client *client) InformerFactory() informers.SharedInformerFactory { if client.informerFactory == nil { panic("InformerFactory is only available for clusters requested at Init phase") diff --git a/pkg/k8s/k8smock.go b/pkg/k8s/k8smock.go index c9fcef3d..da6e471d 100644 --- a/pkg/k8s/k8smock.go +++ b/pkg/k8s/k8smock.go @@ -28,6 +28,9 @@ import ( "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/record" "k8s.io/klog/v2" + + kelemetryversioned "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned" + kelemetryfake "github.com/kubewharf/kelemetry/pkg/crds/client/clientset/versioned/fake" ) type MockClients struct { @@ -55,6 +58,7 @@ type MockClient struct { singleFakeGuard bool dynamicClient *dynamicfake.FakeDynamicClient k8sClient *k8sfake.Clientset + kelemetryClient *kelemetryfake.Clientset } func (client *MockClient) BindKlog(verbosity int32) { @@ -98,6 +102,17 @@ func (client *MockClient) KubernetesClient() kubernetes.Interface { return client.k8sClient } +func (client *MockClient) KelemetryClient() kelemetryversioned.Interface { + client.mutex.Lock() + defer client.mutex.Unlock() + + if client.kelemetryClient == nil { + client.acquireSingleFake() + client.kelemetryClient = kelemetryfake.NewSimpleClientset(client.Objects...) + } + return client.kelemetryClient +} + func (client *MockClient) InformerFactory() informers.SharedInformerFactory { panic("not yet implemented") } diff --git a/pkg/util/cache/ttl.go b/pkg/util/cache/ttl.go index 79fed06f..caf16e3c 100644 --- a/pkg/util/cache/ttl.go +++ b/pkg/util/cache/ttl.go @@ -46,7 +46,7 @@ func NewTtlOnce(ttl time.Duration, clock clock.Clock) *TtlOnce { return &TtlOnce{ ttl: ttl, clock: clock, - wakeupCh: make(chan struct{}), + wakeupCh: make(chan struct{}, 1), cleanupQueue: channel.NewDeque[cleanupEntry](16), data: map[string]any{}, } @@ -60,6 +60,11 @@ func (cache *TtlOnce) Add(key string, value any) { cache.data[key] = value expiry := cache.clock.Now().Add(cache.ttl) cache.cleanupQueue.LockedPushBack(cleanupEntry{key: key, expiry: expiry}) + + select { + case cache.wakeupCh <- struct{}{}: + default: + } } } @@ -85,8 +90,11 @@ func (cache *TtlOnce) RunCleanupLoop(ctx context.Context, logger logrus.FieldLog wakeup := cache.wakeupCh var nextExpiryCh <-chan time.Time if expiry, hasNext := cache.peekExpiry(); hasNext { - nextExpiryCh = cache.clock.After(expiry.Sub(cache.clock.Now()) + time.Second) // +1s to mitigate race conditions - wakeup = nil + timeout := expiry.Sub(cache.clock.Now()) + time.Second + if timeout > 0 { + nextExpiryCh = cache.clock.After(timeout) // +1s to mitigate race conditions + wakeup = nil + } } select { diff --git a/pkg/util/reflect/reflect.go b/pkg/util/reflect/reflect.go index 3ce6179d..17d21116 100644 --- a/pkg/util/reflect/reflect.go +++ b/pkg/util/reflect/reflect.go @@ -25,3 +25,5 @@ func TypeOf[T any]() reflect.Type { func ZeroOf[T any]() (_ T) { return } func Identity[T any](t T) T { return t } + +func Box[T any](t T) *T { return &t } diff --git a/pkg/util/zconstants/link.go b/pkg/util/zconstants/link.go index dd17ffa5..a237a02a 100644 --- a/pkg/util/zconstants/link.go +++ b/pkg/util/zconstants/link.go @@ -15,8 +15,12 @@ package zconstants import ( + "fmt" + "github.com/jaegertracing/jaeger/model" + kelemetryv1a1 "github.com/kubewharf/kelemetry/pkg/crds/apis/v1alpha1" + "github.com/kubewharf/kelemetry/pkg/metrics" utilobject "github.com/kubewharf/kelemetry/pkg/util/object" ) @@ -117,6 +121,19 @@ const ( LinkRoleChild LinkRoleValue = "child" ) +var ErrUnknownTargetRole = metrics.LabelError(fmt.Errorf("unknown target role"), "UnknownTargetRole") + +func LinkRoleValueFromTargetRole(targetRole kelemetryv1a1.TargetRole) (LinkRoleValue, error) { + switch targetRole { + case kelemetryv1a1.TargetRoleChild: + return LinkRoleChild, nil + case kelemetryv1a1.TargetRoleParent: + return LinkRoleParent, nil + } + + return "", fmt.Errorf("%w %q", ErrUnknownTargetRole, targetRole) +} + // Determines the role of the reverse link. func ReverseLinkRole(role LinkRoleValue) LinkRoleValue { switch role {