diff --git a/Makefile b/Makefile
index 7b7fa385f..3116462a5 100644
--- a/Makefile
+++ b/Makefile
@@ -279,6 +279,7 @@ endif
doc: crdoc ## Generate markdown documentation
$(CRDOC) --resources config/crd/bases/flows.netobserv.io_flowcollectors.yaml --output docs/FlowCollector.md
$(CRDOC) --resources config/crd/bases/flows.netobserv.io_flowmetrics.yaml --output docs/FlowMetric.md
+ $(CRDOC) --resources config/crd/bases/flows.netobserv.io_flowcollectorslices.yaml --output docs/FlowCollectorSlice.md
# Hack to reintroduce when the API stored version != latest version; see also envtest.go (CRD path config)
# .PHONY: hack-crd-for-test
@@ -288,6 +289,7 @@ doc: crdoc ## Generate markdown documentation
# '(.spec.versions.[]|select(.name != "v1beta2").storage) = false,(.spec.versions.[]|select(.name == "v1beta2").storage) = true' \
# > ./hack/cloned.flows.netobserv.io_flowcollectors.yaml
# cp ./config/crd/bases/flows.netobserv.io_flowmetrics.yaml ./hack/cloned.flows.netobserv.io_flowmetrics.yaml
+# cp ./config/crd/bases/flows.netobserv.io_flowcollectorslices.yaml ./hack/cloned.flows.netobserv.io_flowcollectorslices.yaml
generate: gencode manifests doc ## Run all code/file generators
diff --git a/PROJECT b/PROJECT
index 776d1aae0..36cbab34c 100644
--- a/PROJECT
+++ b/PROJECT
@@ -38,4 +38,12 @@ resources:
webhooks:
validation: true
webhookVersion: v1
+- api:
+ crdVersion: v1
+ namespaced: true
+ domain: netobserv.io
+ group: flows
+ kind: FlowCollectorSlice
+ path: github.com/netobserv/network-observability-operator/api/flowcollectorslice/v1alpha1
+ version: v1alpha1
version: "3"
diff --git a/api/flowcollector/v1beta2/flowcollector_types.go b/api/flowcollector/v1beta2/flowcollector_types.go
index 16582d616..67d419cdb 100644
--- a/api/flowcollector/v1beta2/flowcollector_types.go
+++ b/api/flowcollector/v1beta2/flowcollector_types.go
@@ -697,6 +697,10 @@ type FlowCollectorFLP struct {
// but with a lesser improvement in performance.
Filters []FLPFilterSet `json:"filters"`
+ // Global configuration managing FlowCollectorSlices custom resources.
+ //+optional
+ SlicesConfig *SlicesConfig `json:"slicesConfig,omitempty"`
+
// `advanced` allows setting some aspects of the internal configuration of the flow processor.
// This section is aimed mostly for debugging and fine-grained performance optimizations,
// such as `GOGC` and `GOMAXPROCS` environment variables. Set these values at your own risk.
@@ -787,6 +791,33 @@ type FlowCollectorHPA struct {
Metrics []ascv2.MetricSpec `json:"metrics"`
}
+type SliceCollectionMode string
+
+const (
+ CollectionAlwaysCollect SliceCollectionMode = "AlwaysCollect"
+ CollectionAllowList SliceCollectionMode = "AllowList"
+)
+
+type SlicesConfig struct {
+ // `enable` determines if the FlowCollectorSlice feature is enabled. If not, all resources of kind FlowCollectorSlice are simply ignored.
+ //+kubebuilder:default:=false
+ //+kubebuilder:validation:Required
+ Enable bool `json:"enable,omitempty"`
+
+ // `collectionMode` determines how the FlowCollectorSlice custom resources impacts the flow collection process:
+ // - When set to `AlwaysCollect`, all flows are collected regardless of the presence of FlowCollectorSlice.
+ // - When set to `AllowList`, only the flows related to namespaces where a FlowCollectorSlice resource is present, or configured via the global `namespacesAllowList`, are collected.
+ //+kubebuilder:validation:Enum=AlwaysCollect;AllowList
+ //+kubebuilder:default:="AlwaysCollect"
+ CollectionMode SliceCollectionMode `json:"collectionMode,omitempty"`
+
+ // `namespacesAllowList` is a list of namespaces for which flows are always collected, regardless of the presence of FlowCollectorSlice in those namespaces.
+ // An entry enclosed by slashes, such as `/openshift-.*/`, is matched as a regular expression.
+ // This setting is ignored if `collectionMode` is different from `AllowList`.
+ //+kubebuilder:validation:optional
+ NamespacesAllowList []string `json:"namespacesAllowList,omitempty"`
+}
+
type LokiAuthToken string
const (
diff --git a/api/flowcollector/v1beta2/helper.go b/api/flowcollector/v1beta2/helper.go
index 190d33ff5..ffa626b4e 100644
--- a/api/flowcollector/v1beta2/helper.go
+++ b/api/flowcollector/v1beta2/helper.go
@@ -227,3 +227,7 @@ func (spec *FlowCollectorConsolePlugin) IsUnmanagedConsolePluginReplicas() bool
}
return spec.Autoscaler.IsHPAEnabled()
}
+
+func (spec *FlowCollectorSpec) IsSliceEnabled() bool {
+ return spec.Processor.SlicesConfig != nil && spec.Processor.SlicesConfig.Enable
+}
diff --git a/api/flowcollector/v1beta2/zz_generated.deepcopy.go b/api/flowcollector/v1beta2/zz_generated.deepcopy.go
index cbc20a6cf..1733992e6 100644
--- a/api/flowcollector/v1beta2/zz_generated.deepcopy.go
+++ b/api/flowcollector/v1beta2/zz_generated.deepcopy.go
@@ -723,6 +723,11 @@ func (in *FlowCollectorFLP) DeepCopyInto(out *FlowCollectorFLP) {
*out = make([]FLPFilterSet, len(*in))
copy(*out, *in)
}
+ if in.SlicesConfig != nil {
+ in, out := &in.SlicesConfig, &out.SlicesConfig
+ *out = new(SlicesConfig)
+ (*in).DeepCopyInto(*out)
+ }
if in.Advanced != nil {
in, out := &in.Advanced, &out.Advanced
*out = new(AdvancedProcessorConfig)
@@ -1361,6 +1366,26 @@ func (in *ServerTLS) DeepCopy() *ServerTLS {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SlicesConfig) DeepCopyInto(out *SlicesConfig) {
+ *out = *in
+ if in.NamespacesAllowList != nil {
+ in, out := &in.NamespacesAllowList, &out.NamespacesAllowList
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlicesConfig.
+func (in *SlicesConfig) DeepCopy() *SlicesConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(SlicesConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SubnetLabel) DeepCopyInto(out *SubnetLabel) {
*out = *in
diff --git a/api/flowcollectorslice/v1alpha1/doc.go b/api/flowcollectorslice/v1alpha1/doc.go
new file mode 100644
index 000000000..a5191cf9a
--- /dev/null
+++ b/api/flowcollectorslice/v1alpha1/doc.go
@@ -0,0 +1,2 @@
+// Package v1aplha1 contains the v1alpha1 API implementation.
+package v1alpha1
diff --git a/api/flowcollectorslice/v1alpha1/flowcollectorslice_types.go b/api/flowcollectorslice/v1alpha1/flowcollectorslice_types.go
new file mode 100644
index 000000000..8fe939395
--- /dev/null
+++ b/api/flowcollectorslice/v1alpha1/flowcollectorslice_types.go
@@ -0,0 +1,65 @@
+package v1alpha1
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// FlowCollectorSliceSpec defines the desired state of FlowCollectorSlice
+type FlowCollectorSliceSpec struct {
+ // `subnetLabels` allows to customize subnets and IPs labelling, such as to identify cluster-external workloads or web services.
+ // Beware that the subnet labels configured in FlowCollectorSlice are not limited to the flows of the related namespace: any flow
+ // in the whole cluster can be labelled using this configuration. However, subnet labels defined in the cluster-scoped FlowCollector take
+ // precedence in case of conflicting rules.
+ //+optional
+ SubnetLabels []SubnetLabel `json:"subnetLabels,omitempty"`
+
+ // `sampling` is an optional sampling interval to apply to this slice. For example, a value of `50` means that 1 matching flow in 50 is sampled.
+ //+kubebuilder:validation:Minimum=0
+ // +optional
+ Sampling int32 `json:"sampling,omitempty"`
+}
+
+// SubnetLabel allows to label subnets and IPs, such as to identify cluster-external workloads or web services.
+type SubnetLabel struct {
+ // List of CIDRs, such as `["1.2.3.4/32"]`.
+ //+required
+ CIDRs []string `json:"cidrs,omitempty"` // Note, starting with k8s 1.31 / ocp 4.16 there's a new way to validate CIDR such as `+kubebuilder:validation:XValidation:rule="isCIDR(self)",message="field should be in CIDR notation format"`. But older versions would reject the CRD so we cannot implement it now to maintain compatibility.
+ // Label name, used to flag matching flows.
+ //+required
+ Name string `json:"name,omitempty"`
+}
+
+// FlowCollectorSliceStatus defines the observed state of FlowCollectorSlice
+type FlowCollectorSliceStatus struct {
+ // `conditions` represent the latest available observations of an object's state
+ Conditions []metav1.Condition `json:"conditions"`
+ // Filter that is applied for flow collection
+ // +optional
+ FilterApplied string `json:"filterApplied"`
+ // Number of subnet labels configured
+ // +optional
+ SubnetLabelsConfigured int `json:"subnetLabelsConfigured"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+// FlowMetric is the API allowing to create custom metrics from the collected flow logs.
+type FlowCollectorSlice struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec FlowCollectorSliceSpec `json:"spec,omitempty"`
+ Status FlowCollectorSliceStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// FlowCollectorSliceList contains a list of FlowCollectorSlice
+type FlowCollectorSliceList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []FlowCollectorSlice `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&FlowCollectorSlice{}, &FlowCollectorSliceList{})
+}
diff --git a/api/flowcollectorslice/v1alpha1/groupversion_info.go b/api/flowcollectorslice/v1alpha1/groupversion_info.go
new file mode 100644
index 000000000..c23689d0a
--- /dev/null
+++ b/api/flowcollectorslice/v1alpha1/groupversion_info.go
@@ -0,0 +1,20 @@
+// Package v1alpha1 contains API Schema definitions for the flows v1alpha1 API group
+// +kubebuilder:object:generate=true
+// +groupName=flows.netobserv.io
+package v1alpha1
+
+import (
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects
+ GroupVersion = schema.GroupVersion{Group: "flows.netobserv.io", Version: "v1alpha1"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
diff --git a/api/flowcollectorslice/v1alpha1/zz_generated.deepcopy.go b/api/flowcollectorslice/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 000000000..7e6849289
--- /dev/null
+++ b/api/flowcollectorslice/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,149 @@
+//go:build !ignore_autogenerated
+
+/*
+Copyright 2021.
+
+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 controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ "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 *FlowCollectorSlice) DeepCopyInto(out *FlowCollectorSlice) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowCollectorSlice.
+func (in *FlowCollectorSlice) DeepCopy() *FlowCollectorSlice {
+ if in == nil {
+ return nil
+ }
+ out := new(FlowCollectorSlice)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *FlowCollectorSlice) 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 *FlowCollectorSliceList) DeepCopyInto(out *FlowCollectorSliceList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]FlowCollectorSlice, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowCollectorSliceList.
+func (in *FlowCollectorSliceList) DeepCopy() *FlowCollectorSliceList {
+ if in == nil {
+ return nil
+ }
+ out := new(FlowCollectorSliceList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *FlowCollectorSliceList) 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 *FlowCollectorSliceSpec) DeepCopyInto(out *FlowCollectorSliceSpec) {
+ *out = *in
+ if in.SubnetLabels != nil {
+ in, out := &in.SubnetLabels, &out.SubnetLabels
+ *out = make([]SubnetLabel, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowCollectorSliceSpec.
+func (in *FlowCollectorSliceSpec) DeepCopy() *FlowCollectorSliceSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(FlowCollectorSliceSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *FlowCollectorSliceStatus) DeepCopyInto(out *FlowCollectorSliceStatus) {
+ *out = *in
+ if in.Conditions != nil {
+ in, out := &in.Conditions, &out.Conditions
+ *out = make([]v1.Condition, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowCollectorSliceStatus.
+func (in *FlowCollectorSliceStatus) DeepCopy() *FlowCollectorSliceStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(FlowCollectorSliceStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SubnetLabel) DeepCopyInto(out *SubnetLabel) {
+ *out = *in
+ if in.CIDRs != nil {
+ in, out := &in.CIDRs, &out.CIDRs
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetLabel.
+func (in *SubnetLabel) DeepCopy() *SubnetLabel {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetLabel)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml
index b741295ad..0a12132c7 100644
--- a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml
+++ b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml
@@ -6108,6 +6108,37 @@ spec:
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
type: object
+ slicesConfig:
+ description: Global configuration managing FlowCollectorSlices
+ custom resources.
+ properties:
+ collectionMode:
+ default: AlwaysCollect
+ description: |-
+ `collectionMode` determines how the FlowCollectorSlice custom resources impacts the flow collection process:
+ - When set to `AlwaysCollect`, all flows are collected regardless of the presence of FlowCollectorSlice.
+ - When set to `AllowList`, only the flows related to namespaces where a FlowCollectorSlice resource is present, or configured via the global `namespacesAllowList`, are collected.
+ enum:
+ - AlwaysCollect
+ - AllowList
+ type: string
+ enable:
+ default: false
+ description: '`enable` determines if the FlowCollectorSlice
+ feature is enabled. If not, all resources of kind FlowCollectorSlice
+ are simply ignored.'
+ type: boolean
+ namespacesAllowList:
+ description: |-
+ `namespacesAllowList` is a list of namespaces for which flows are always collected, regardless of the presence of FlowCollectorSlice in those namespaces.
+ An entry enclosed by slashes, such as `/openshift-.*/`, is matched as a regular expression.
+ This setting is ignored if `collectionMode` is different from `AllowList`.
+ items:
+ type: string
+ type: array
+ required:
+ - enable
+ type: object
subnetLabels:
description: |-
`subnetLabels` allows to define custom labels on subnets and IPs or to enable automatic labelling of recognized subnets in OpenShift, which is used to identify cluster external traffic.
diff --git a/bundle/manifests/flows.netobserv.io_flowcollectorslices.yaml b/bundle/manifests/flows.netobserv.io_flowcollectorslices.yaml
new file mode 100644
index 000000000..5983127bc
--- /dev/null
+++ b/bundle/manifests/flows.netobserv.io_flowcollectorslices.yaml
@@ -0,0 +1,154 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.16.2
+ creationTimestamp: null
+ name: flowcollectorslices.flows.netobserv.io
+spec:
+ group: flows.netobserv.io
+ names:
+ kind: FlowCollectorSlice
+ listKind: FlowCollectorSliceList
+ plural: flowcollectorslices
+ singular: flowcollectorslice
+ scope: Namespaced
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: FlowMetric is the API allowing to create custom metrics from
+ the collected flow logs.
+ 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
+ metadata:
+ type: object
+ spec:
+ description: FlowCollectorSliceSpec defines the desired state of FlowCollectorSlice
+ properties:
+ sampling:
+ description: '`sampling` is an optional sampling interval to apply
+ to this slice. For example, a value of `50` means that 1 matching
+ flow in 50 is sampled.'
+ format: int32
+ minimum: 0
+ type: integer
+ subnetLabels:
+ description: |-
+ `subnetLabels` allows to customize subnets and IPs labelling, such as to identify cluster-external workloads or web services.
+ Beware that the subnet labels configured in FlowCollectorSlice are not limited to the flows of the related namespace: any flow
+ in the whole cluster can be labelled using this configuration. However, subnet labels defined in the cluster-scoped FlowCollector take
+ precedence in case of conflicting rules.
+ items:
+ description: SubnetLabel allows to label subnets and IPs, such as
+ to identify cluster-external workloads or web services.
+ properties:
+ cidrs:
+ description: List of CIDRs, such as `["1.2.3.4/32"]`.
+ items:
+ type: string
+ type: array
+ name:
+ description: Label name, used to flag matching flows.
+ type: string
+ required:
+ - cidrs
+ - name
+ type: object
+ type: array
+ type: object
+ status:
+ description: FlowCollectorSliceStatus defines the observed state of FlowCollectorSlice
+ properties:
+ conditions:
+ description: '`conditions` represent the latest available observations
+ of an object''s state'
+ items:
+ description: Condition contains details for one aspect of the current
+ state of this API Resource.
+ properties:
+ lastTransitionTime:
+ description: |-
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+ This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
+ format: date-time
+ type: string
+ message:
+ description: |-
+ message is a human readable message indicating details about the transition.
+ This may be an empty string.
+ maxLength: 32768
+ type: string
+ observedGeneration:
+ description: |-
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+ For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+ with respect to the current state of the instance.
+ format: int64
+ minimum: 0
+ type: integer
+ reason:
+ description: |-
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+ Producers of specific condition types may define expected values and meanings for this field,
+ and whether the values are considered a guaranteed API.
+ The value should be a CamelCase string.
+ This field may not be empty.
+ maxLength: 1024
+ minLength: 1
+ pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+ type: string
+ status:
+ description: status of the condition, one of True, False, Unknown.
+ enum:
+ - "True"
+ - "False"
+ - Unknown
+ type: string
+ type:
+ description: type of condition in CamelCase or in foo.example.com/CamelCase.
+ maxLength: 316
+ pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+ type: string
+ required:
+ - lastTransitionTime
+ - message
+ - reason
+ - status
+ - type
+ type: object
+ type: array
+ filterApplied:
+ description: Filter that is applied for flow collection
+ type: string
+ subnetLabelsConfigured:
+ description: Number of subnet labels configured
+ type: integer
+ required:
+ - conditions
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: null
+ storedVersions: null
diff --git a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml
index c2b67a38b..d9a224c2b 100644
--- a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml
+++ b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml
@@ -4,61 +4,28 @@ metadata:
annotations:
alm-examples: |-
[
+ {
+ "apiVersion": "flows.netobserv.io/v1alpha1",
+ "kind": "FlowCollectorSlice",
+ "metadata": {
+ "name": "flowcollectorslice-sample"
+ },
+ "spec": {
+ "sampling": 1
+ }
+ },
{
"apiVersion": "flows.netobserv.io/v1alpha1",
"kind": "FlowMetric",
"metadata": {
- "labels": {
- "app.kubernetes.io/created-by": "netobserv-operator",
- "app.kubernetes.io/instance": "flowmetric-sample",
- "app.kubernetes.io/managed-by": "kustomize",
- "app.kubernetes.io/name": "flowmetric",
- "app.kubernetes.io/part-of": "netobserv-operator"
- },
"name": "flowmetric-sample"
},
"spec": {
- "charts": [
- {
- "dashboardName": "Main",
- "queries": [
- {
- "legend": "",
- "promQL": "sum(rate($METRIC[2m]))"
- }
- ],
- "title": "External ingress traffic",
- "type": "SingleStat",
- "unit": "Bps"
- },
- {
- "dashboardName": "Main",
- "queries": [
- {
- "legend": "{{DstK8S_Namespace}} / {{DstK8S_OwnerName}}",
- "promQL": "sum(rate($METRIC{DstK8S_Namespace!=\"\"}[2m])) by (DstK8S_Namespace, DstK8S_OwnerName)"
- }
- ],
- "sectionName": "External",
- "title": "Top external ingress traffic per workload",
- "type": "StackArea",
- "unit": "Bps"
- }
- ],
"direction": "Ingress",
- "filters": [
- {
- "field": "SrcSubnetLabel",
- "matchType": "Absence"
- }
- ],
"labels": [
- "DstK8S_HostName",
- "DstK8S_Namespace",
- "DstK8S_OwnerName",
- "DstK8S_OwnerType"
+ "SrcK8S_Namespace",
+ "DstK8S_Namespace"
],
- "metricName": "cluster_external_ingress_bytes_total",
"type": "Counter",
"valueField": "Bytes"
}
@@ -237,6 +204,13 @@ metadata:
"cpu": "100m",
"memory": "100Mi"
}
+ },
+ "slicesConfig": {
+ "collectionMode": "AllowList",
+ "enable": false,
+ "namespacesAllowList": [
+ "/openshift-.*|netobserv.*/"
+ ]
}
},
"prometheus": {
@@ -253,7 +227,7 @@ metadata:
categories: Monitoring, Networking, Observability
console.openshift.io/plugins: '["netobserv-plugin"]'
containerImage: quay.io/netobserv/network-observability-operator:1.10.0-community
- createdAt: "2025-11-26T13:16:01Z"
+ createdAt: "2025-12-11T14:18:07Z"
description: Network flows collector and monitoring solution
operatorframework.io/initialization-resource: '{"apiVersion":"flows.netobserv.io/v1beta2",
"kind":"FlowCollector","metadata":{"name":"cluster"},"spec": {}}'
@@ -628,6 +602,14 @@ spec:
path: processor.metrics.includeList
- displayName: Port
path: processor.metrics.server.port
+ - displayName: Slices config
+ path: processor.slicesConfig
+ - displayName: Collection mode
+ path: processor.slicesConfig.collectionMode
+ - displayName: Enable
+ path: processor.slicesConfig.enable
+ - displayName: Namespaces allow list
+ path: processor.slicesConfig.namespacesAllowList
- displayName: Subnet labels
path: processor.subnetLabels
- displayName: Custom labels
@@ -663,6 +645,12 @@ spec:
x-descriptors:
- urn:alm:descriptor:io.kubernetes.conditions
version: v1beta2
+ - description: '`FlowCollectorSlice` is the schema allowing delegated configuration
+ per namespace.'
+ displayName: Flow Collector Slice
+ kind: FlowCollectorSlice
+ name: flowcollectorslices.flows.netobserv.io
+ version: v1alpha1
- description: '`FlowMetric` is the schema for the custom metrics API, which allows
to generate more metrics out of flow logs. You can find examples here: https://github.com/netobserv/network-observability-operator/tree/main/config/samples/flowmetrics'
displayName: Flow Metric
@@ -913,6 +901,7 @@ spec:
- flows.netobserv.io
resources:
- flowcollectors
+ - flowcollectorslices
- flowmetrics
verbs:
- create
@@ -932,6 +921,7 @@ spec:
- flows.netobserv.io
resources:
- flowcollectors/status
+ - flowcollectorslices/status
- flowmetrics/status
verbs:
- get
diff --git a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml
index 3addd7bc5..dd70a309a 100644
--- a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml
+++ b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml
@@ -5645,6 +5645,34 @@ spec:
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
type: object
+ slicesConfig:
+ description: Global configuration managing FlowCollectorSlices custom resources.
+ properties:
+ collectionMode:
+ default: AlwaysCollect
+ description: |-
+ `collectionMode` determines how the FlowCollectorSlice custom resources impacts the flow collection process:
+ - When set to `AlwaysCollect`, all flows are collected regardless of the presence of FlowCollectorSlice.
+ - When set to `AllowList`, only the flows related to namespaces where a FlowCollectorSlice resource is present, or configured via the global `namespacesAllowList`, are collected.
+ enum:
+ - AlwaysCollect
+ - AllowList
+ type: string
+ enable:
+ default: false
+ description: '`enable` determines if the FlowCollectorSlice feature is enabled. If not, all resources of kind FlowCollectorSlice are simply ignored.'
+ type: boolean
+ namespacesAllowList:
+ description: |-
+ `namespacesAllowList` is a list of namespaces for which flows are always collected, regardless of the presence of FlowCollectorSlice in those namespaces.
+ An entry enclosed by slashes, such as `/openshift-.*/`, is matched as a regular expression.
+ This setting is ignored if `collectionMode` is different from `AllowList`.
+ items:
+ type: string
+ type: array
+ required:
+ - enable
+ type: object
subnetLabels:
description: |-
`subnetLabels` allows to define custom labels on subnets and IPs or to enable automatic labelling of recognized subnets in OpenShift, which is used to identify cluster external traffic.
diff --git a/config/crd/bases/flows.netobserv.io_flowcollectorslices.yaml b/config/crd/bases/flows.netobserv.io_flowcollectorslices.yaml
new file mode 100644
index 000000000..dde78403c
--- /dev/null
+++ b/config/crd/bases/flows.netobserv.io_flowcollectorslices.yaml
@@ -0,0 +1,148 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.16.2
+ name: flowcollectorslices.flows.netobserv.io
+spec:
+ group: flows.netobserv.io
+ names:
+ kind: FlowCollectorSlice
+ listKind: FlowCollectorSliceList
+ plural: flowcollectorslices
+ singular: flowcollectorslice
+ scope: Namespaced
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: FlowMetric is the API allowing to create custom metrics from
+ the collected flow logs.
+ 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
+ metadata:
+ type: object
+ spec:
+ description: FlowCollectorSliceSpec defines the desired state of FlowCollectorSlice
+ properties:
+ sampling:
+ description: '`sampling` is an optional sampling interval to apply
+ to this slice. For example, a value of `50` means that 1 matching
+ flow in 50 is sampled.'
+ format: int32
+ minimum: 0
+ type: integer
+ subnetLabels:
+ description: |-
+ `subnetLabels` allows to customize subnets and IPs labelling, such as to identify cluster-external workloads or web services.
+ Beware that the subnet labels configured in FlowCollectorSlice are not limited to the flows of the related namespace: any flow
+ in the whole cluster can be labelled using this configuration. However, subnet labels defined in the cluster-scoped FlowCollector take
+ precedence in case of conflicting rules.
+ items:
+ description: SubnetLabel allows to label subnets and IPs, such as
+ to identify cluster-external workloads or web services.
+ properties:
+ cidrs:
+ description: List of CIDRs, such as `["1.2.3.4/32"]`.
+ items:
+ type: string
+ type: array
+ name:
+ description: Label name, used to flag matching flows.
+ type: string
+ required:
+ - cidrs
+ - name
+ type: object
+ type: array
+ type: object
+ status:
+ description: FlowCollectorSliceStatus defines the observed state of FlowCollectorSlice
+ properties:
+ conditions:
+ description: '`conditions` represent the latest available observations
+ of an object''s state'
+ items:
+ description: Condition contains details for one aspect of the current
+ state of this API Resource.
+ properties:
+ lastTransitionTime:
+ description: |-
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+ This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
+ format: date-time
+ type: string
+ message:
+ description: |-
+ message is a human readable message indicating details about the transition.
+ This may be an empty string.
+ maxLength: 32768
+ type: string
+ observedGeneration:
+ description: |-
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+ For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+ with respect to the current state of the instance.
+ format: int64
+ minimum: 0
+ type: integer
+ reason:
+ description: |-
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+ Producers of specific condition types may define expected values and meanings for this field,
+ and whether the values are considered a guaranteed API.
+ The value should be a CamelCase string.
+ This field may not be empty.
+ maxLength: 1024
+ minLength: 1
+ pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+ type: string
+ status:
+ description: status of the condition, one of True, False, Unknown.
+ enum:
+ - "True"
+ - "False"
+ - Unknown
+ type: string
+ type:
+ description: type of condition in CamelCase or in foo.example.com/CamelCase.
+ maxLength: 316
+ pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+ type: string
+ required:
+ - lastTransitionTime
+ - message
+ - reason
+ - status
+ - type
+ type: object
+ type: array
+ filterApplied:
+ description: Filter that is applied for flow collection
+ type: string
+ subnetLabelsConfigured:
+ description: Number of subnet labels configured
+ type: integer
+ required:
+ - conditions
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index 05d72ac6d..5d743e06a 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -7,6 +7,7 @@ kind: Kustomization
resources:
- bases/flows.netobserv.io_flowcollectors.yaml
- bases/flows.netobserv.io_flowmetrics.yaml
+- bases/flows.netobserv.io_flowcollectorslices.yaml
#+kubebuilder:scaffold:crdkustomizeresource
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
diff --git a/config/csv/bases/netobserv-operator.clusterserviceversion.yaml b/config/csv/bases/netobserv-operator.clusterserviceversion.yaml
index 080a2400a..5aabf970c 100644
--- a/config/csv/bases/netobserv-operator.clusterserviceversion.yaml
+++ b/config/csv/bases/netobserv-operator.clusterserviceversion.yaml
@@ -297,6 +297,11 @@ spec:
kind: FlowMetric
name: flowmetrics.flows.netobserv.io
version: v1alpha1
+ - description: '`FlowCollectorSlice` is the schema allowing delegated configuration per namespace.'
+ displayName: Flow Collector Slice
+ kind: FlowCollectorSlice
+ name: flowcollectorslices.flows.netobserv.io
+ version: v1alpha1
description: ':full-description:'
displayName: NetObserv Operator
icon:
diff --git a/config/openshift/patch.yaml b/config/openshift/patch.yaml
index 62a77a5a0..034d0bebc 100644
--- a/config/openshift/patch.yaml
+++ b/config/openshift/patch.yaml
@@ -28,4 +28,4 @@ kind: CustomResourceDefinition
metadata:
annotations:
service.beta.openshift.io/inject-cabundle: "true"
- name: flowmetrics.flows.netobserv.io
\ No newline at end of file
+ name: flowmetrics.flows.netobserv.io
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index 63d7a49c4..e370c951a 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -139,6 +139,7 @@ rules:
- flows.netobserv.io
resources:
- flowcollectors
+ - flowcollectorslices
- flowmetrics
verbs:
- create
@@ -158,6 +159,7 @@ rules:
- flows.netobserv.io
resources:
- flowcollectors/status
+ - flowcollectorslices/status
- flowmetrics/status
verbs:
- get
diff --git a/config/samples/flows_v1alpha1_flowcollectorslice.yaml b/config/samples/flows_v1alpha1_flowcollectorslice.yaml
new file mode 100644
index 000000000..c85e25eb2
--- /dev/null
+++ b/config/samples/flows_v1alpha1_flowcollectorslice.yaml
@@ -0,0 +1,10 @@
+apiVersion: flows.netobserv.io/v1alpha1
+kind: FlowCollectorSlice
+metadata:
+ name: flowcollectorslice-sample
+spec:
+ sampling: 1
+ # subnetLabels:
+ # - name: my-database
+ # cidrs:
+ # - 1.2.3.4/24
diff --git a/config/samples/flows_v1alpha1_flowmetric.yaml b/config/samples/flows_v1alpha1_flowmetric.yaml
index d048bd32f..223bef56a 100644
--- a/config/samples/flows_v1alpha1_flowmetric.yaml
+++ b/config/samples/flows_v1alpha1_flowmetric.yaml
@@ -1,36 +1,29 @@
apiVersion: flows.netobserv.io/v1alpha1
kind: FlowMetric
metadata:
- labels:
- app.kubernetes.io/name: flowmetric
- app.kubernetes.io/instance: flowmetric-sample
- app.kubernetes.io/part-of: netobserv-operator
- app.kubernetes.io/managed-by: kustomize
- app.kubernetes.io/created-by: netobserv-operator
name: flowmetric-sample
spec:
# More examples in https://github.com/netobserv/network-observability-operator/tree/main/config/samples/flowmetrics
- metricName: cluster_external_ingress_bytes_total
type: Counter
valueField: Bytes
direction: Ingress
- labels: [DstK8S_HostName,DstK8S_Namespace,DstK8S_OwnerName,DstK8S_OwnerType]
- filters:
- - field: SrcSubnetLabel
- matchType: Absence
- charts:
- - dashboardName: Main
- title: External ingress traffic
- unit: Bps
- type: SingleStat
- queries:
- - promQL: "sum(rate($METRIC[2m]))"
- legend: ""
- - dashboardName: Main
- sectionName: External
- title: Top external ingress traffic per workload
- unit: Bps
- type: StackArea
- queries:
- - promQL: "sum(rate($METRIC{DstK8S_Namespace!=\"\"}[2m])) by (DstK8S_Namespace, DstK8S_OwnerName)"
- legend: "{{DstK8S_Namespace}} / {{DstK8S_OwnerName}}"
+ labels: [SrcK8S_Namespace,DstK8S_Namespace]
+ # filters:
+ # - field: SrcSubnetLabel
+ # matchType: Absence
+ # charts:
+ # - dashboardName: Main
+ # title: External ingress traffic
+ # unit: Bps
+ # type: SingleStat
+ # queries:
+ # - promQL: "sum(rate($METRIC[2m]))"
+ # legend: ""
+ # - dashboardName: Main
+ # sectionName: External
+ # title: Top external ingress traffic per workload
+ # unit: Bps
+ # type: StackArea
+ # queries:
+ # - promQL: "sum(rate($METRIC{DstK8S_Namespace!=\"\"}[2m])) by (DstK8S_Namespace, DstK8S_OwnerName)"
+ # legend: "{{DstK8S_Namespace}} / {{DstK8S_OwnerName}}"
diff --git a/config/samples/flows_v1beta2_flowcollector.yaml b/config/samples/flows_v1beta2_flowcollector.yaml
index 451261884..c6f2ed994 100644
--- a/config/samples/flows_v1beta2_flowcollector.yaml
+++ b/config/samples/flows_v1beta2_flowcollector.yaml
@@ -121,6 +121,11 @@ spec:
# info: "5"
# groupBy: Namespace
# lowVolumeThreshold: "5"
+ slicesConfig:
+ enable: false
+ collectionMode: AllowList
+ namespacesAllowList:
+ - /openshift-.*|netobserv.*/
# Kafka consumer stage configuration
kafkaConsumerReplicas: 3
kafkaConsumerAutoscaler: null
diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml
index 57c851a8a..47d8c88fb 100644
--- a/config/samples/kustomization.yaml
+++ b/config/samples/kustomization.yaml
@@ -4,3 +4,4 @@ kind: Kustomization
resources:
- flows_v1beta2_flowcollector.yaml
- flows_v1alpha1_flowmetric.yaml
+- flows_v1alpha1_flowcollectorslice.yaml
diff --git a/docs/Architecture.md b/docs/Architecture.md
index 39770c45b..07ce5f3be 100644
--- a/docs/Architecture.md
+++ b/docs/Architecture.md
@@ -22,7 +22,7 @@ The components are:
- Different views include metrics overview, a network topology and a table listing raw flows logs.
- It supports multi-tenant access, making it relevant for various use cases: cluster/network admins, SREs, development teams...
- [An operator](https://github.com/netobserv/network-observability-operator) that manages all of the above.
- - It provides two APIs (CRD), one called [FlowCollector](https://github.com/netobserv/network-observability-operator/blob/main/docs/FlowCollector.md), which configures and pilots the whole deployment, and another called [FlowMetrics](https://github.com/netobserv/network-observability-operator/blob/main/docs/FlowMetric.md) which allows to customize which metrics to generate out of flow logs.
+ - It provides three APIs (CRD), one called [FlowCollector](https://github.com/netobserv/network-observability-operator/blob/main/docs/FlowCollector.md), which configures and pilots the whole deployment, another called [FlowCollectorSlice](https://github.com/netobserv/network-observability-operator/blob/main/docs/FlowCollectorSlice.md) for per-tenant configuration, and lastly [FlowMetrics](https://github.com/netobserv/network-observability-operator/blob/main/docs/FlowMetric.md) which allows to customize which metrics to generate out of flow logs.
- As an [OLM operator](https://olm.operatorframework.io/), it is designed with `operator-sdk`, and allows subscriptions for easy updates.
- [A CLI](https://github.com/netobserv/network-observability-cli) that also manages some of the above components, for on-demand monitoring and packet capture.
- It is provided as a `kubectl` or `oc` plugin, allowing to capture flows (similar to what the operator does, except it's on-demand and in the terminal), full packets (much like a `tcpdump` command) or metrics.
diff --git a/docs/FlowCollector.md b/docs/FlowCollector.md
index 1abc9937f..06ce563d8 100644
--- a/docs/FlowCollector.md
+++ b/docs/FlowCollector.md
@@ -8538,6 +8538,13 @@ For more information, see https://kubernetes.io/docs/concepts/configuration/mana
Default: map[limits:map[memory:800Mi] requests:map[cpu:100m memory:100Mi]]
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| enable | +boolean | +
+ `enable` determines if the FlowCollectorSlice feature is enabled. If not, all resources of kind FlowCollectorSlice are simply ignored. + + Default: false + |
+ true | +
| collectionMode | +enum | +
+ `collectionMode` determines how the FlowCollectorSlice custom resources impacts the flow collection process: +- When set to `AlwaysCollect`, all flows are collected regardless of the presence of FlowCollectorSlice. +- When set to `AllowList`, only the flows related to namespaces where a FlowCollectorSlice resource is present, or configured via the global `namespacesAllowList`, are collected. + + Enum: AlwaysCollect, AllowList + Default: AlwaysCollect + |
+ false | +
| namespacesAllowList | +[]string | +
+ `namespacesAllowList` is a list of namespaces for which flows are always collected, regardless of the presence of FlowCollectorSlice in those namespaces.
+An entry enclosed by slashes, such as `/openshift-.*/`, is matched as a regular expression.
+This setting is ignored if `collectionMode` is different from `AllowList`. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| apiVersion | +string | +flows.netobserv.io/v1alpha1 | +true | +
| kind | +string | +FlowCollectorSlice | +true | +
| metadata | +object | +Refer to the Kubernetes API documentation for the fields of the `metadata` field. | +true | +
| spec | +object | +
+ FlowCollectorSliceSpec defines the desired state of FlowCollectorSlice + |
+ false | +
| status | +object | +
+ FlowCollectorSliceStatus defines the observed state of FlowCollectorSlice + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| sampling | +integer | +
+ `sampling` is an optional sampling interval to apply to this slice. For example, a value of `50` means that 1 matching flow in 50 is sampled. + + Format: int32 + Minimum: 0 + |
+ false | +
| subnetLabels | +[]object | +
+ `subnetLabels` allows to customize subnets and IPs labelling, such as to identify cluster-external workloads or web services.
+Beware that the subnet labels configured in FlowCollectorSlice are not limited to the flows of the related namespace: any flow
+in the whole cluster can be labelled using this configuration. However, subnet labels defined in the cluster-scoped FlowCollector take
+precedence in case of conflicting rules. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| cidrs | +[]string | +
+ List of CIDRs, such as `["1.2.3.4/32"]`. + |
+ true | +
| name | +string | +
+ Label name, used to flag matching flows. + |
+ true | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| conditions | +[]object | +
+ `conditions` represent the latest available observations of an object's state + |
+ true | +
| filterApplied | +string | +
+ Filter that is applied for flow collection + |
+ false | +
| subnetLabelsConfigured | +integer | +
+ Number of subnet labels configured + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| lastTransitionTime | +string | +
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + + Format: date-time + |
+ true | +
| message | +string | +
+ message is a human readable message indicating details about the transition.
+This may be an empty string. + |
+ true | +
| reason | +string | +
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+Producers of specific condition types may define expected values and meanings for this field,
+and whether the values are considered a guaranteed API.
+The value should be a CamelCase string.
+This field may not be empty. + |
+ true | +
| status | +enum | +
+ status of the condition, one of True, False, Unknown. + + Enum: True, False, Unknown + |
+ true | +
| type | +string | +
+ type of condition in CamelCase or in foo.example.com/CamelCase. + |
+ true | +
| observedGeneration | +integer | +
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+with respect to the current state of the instance. + + Format: int64 + Minimum: 0 + |
+ false | +