diff --git a/config/crd/bases/config.nri_balloonspolicies.yaml b/config/crd/bases/config.nri_balloonspolicies.yaml index a49c020aa..c0601b9f0 100644 --- a/config/crd/bases/config.nri_balloonspolicies.yaml +++ b/config/crd/bases/config.nri_balloonspolicies.yaml @@ -40,6 +40,18 @@ spec: spec: description: BalloonsPolicySpec describes a balloons policy. properties: + agent: + default: + nodeResourceTopology: true + description: AgentConfig provides access to configuration data for + the agent. + properties: + nodeResourceTopology: + description: |- + NodeResourceTopology enables support for exporting resource usage using + NodeResourceTopology Custom Resources. + type: boolean + type: object allocatorTopologyBalancing: description: |- If AllocatorTopologyBalancing is true, balloons are diff --git a/config/crd/bases/config.nri_templatepolicies.yaml b/config/crd/bases/config.nri_templatepolicies.yaml index cea85dc1d..125e5ccb7 100644 --- a/config/crd/bases/config.nri_templatepolicies.yaml +++ b/config/crd/bases/config.nri_templatepolicies.yaml @@ -40,6 +40,18 @@ spec: spec: description: TemplatePolicySpec describes a template policy. properties: + agent: + default: + nodeResourceTopology: true + description: AgentConfig provides access to configuration data for + the agent. + properties: + nodeResourceTopology: + description: |- + NodeResourceTopology enables support for exporting resource usage using + NodeResourceTopology Custom Resources. + type: boolean + type: object availableResources: additionalProperties: type: string diff --git a/config/crd/bases/config.nri_topologyawarepolicies.yaml b/config/crd/bases/config.nri_topologyawarepolicies.yaml index a7c215f1d..5d2e6e100 100644 --- a/config/crd/bases/config.nri_topologyawarepolicies.yaml +++ b/config/crd/bases/config.nri_topologyawarepolicies.yaml @@ -40,6 +40,18 @@ spec: spec: description: TopologyAwarePolicySpec describes a topology-aware policy. properties: + agent: + default: + nodeResourceTopology: true + description: AgentConfig provides access to configuration data for + the agent. + properties: + nodeResourceTopology: + description: |- + NodeResourceTopology enables support for exporting resource usage using + NodeResourceTopology Custom Resources. + type: boolean + type: object availableResources: additionalProperties: type: string diff --git a/deployment/helm/balloons/crds/config.nri_balloonspolicies.yaml b/deployment/helm/balloons/crds/config.nri_balloonspolicies.yaml index a49c020aa..c0601b9f0 100644 --- a/deployment/helm/balloons/crds/config.nri_balloonspolicies.yaml +++ b/deployment/helm/balloons/crds/config.nri_balloonspolicies.yaml @@ -40,6 +40,18 @@ spec: spec: description: BalloonsPolicySpec describes a balloons policy. properties: + agent: + default: + nodeResourceTopology: true + description: AgentConfig provides access to configuration data for + the agent. + properties: + nodeResourceTopology: + description: |- + NodeResourceTopology enables support for exporting resource usage using + NodeResourceTopology Custom Resources. + type: boolean + type: object allocatorTopologyBalancing: description: |- If AllocatorTopologyBalancing is true, balloons are diff --git a/deployment/helm/template/crds/config.nri_templatepolicies.yaml b/deployment/helm/template/crds/config.nri_templatepolicies.yaml index cea85dc1d..125e5ccb7 100644 --- a/deployment/helm/template/crds/config.nri_templatepolicies.yaml +++ b/deployment/helm/template/crds/config.nri_templatepolicies.yaml @@ -40,6 +40,18 @@ spec: spec: description: TemplatePolicySpec describes a template policy. properties: + agent: + default: + nodeResourceTopology: true + description: AgentConfig provides access to configuration data for + the agent. + properties: + nodeResourceTopology: + description: |- + NodeResourceTopology enables support for exporting resource usage using + NodeResourceTopology Custom Resources. + type: boolean + type: object availableResources: additionalProperties: type: string diff --git a/deployment/helm/topology-aware/crds/config.nri_topologyawarepolicies.yaml b/deployment/helm/topology-aware/crds/config.nri_topologyawarepolicies.yaml index a7c215f1d..5d2e6e100 100644 --- a/deployment/helm/topology-aware/crds/config.nri_topologyawarepolicies.yaml +++ b/deployment/helm/topology-aware/crds/config.nri_topologyawarepolicies.yaml @@ -40,6 +40,18 @@ spec: spec: description: TopologyAwarePolicySpec describes a topology-aware policy. properties: + agent: + default: + nodeResourceTopology: true + description: AgentConfig provides access to configuration data for + the agent. + properties: + nodeResourceTopology: + description: |- + NodeResourceTopology enables support for exporting resource usage using + NodeResourceTopology Custom Resources. + type: boolean + type: object availableResources: additionalProperties: type: string diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 334b298b2..f0f6b9cd5 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -268,37 +268,39 @@ func (a *Agent) hasLocalConfig() bool { func (a *Agent) setupClients() error { if a.hasLocalConfig() { + log.Warn("running with local configuration, skipping cluster access client setup...") return nil } - cfg, err := a.getRESTConfig() - if err != nil { - return err - } + // Create HTTP/REST client and K8s client on initial startup. Any failure + // to create these is a failure start up. + if a.httpCli == nil { + log.Info("setting up HTTP/REST client...") + restCfg, err := a.getRESTConfig() + if err != nil { + return err + } - a.httpCli, err = rest.HTTPClientFor(cfg) - if err != nil { - return fmt.Errorf("failed to setup kubernetes HTTP client: %w", err) - } + a.httpCli, err = rest.HTTPClientFor(restCfg) + if err != nil { + return fmt.Errorf("failed to setup kubernetes HTTP client: %w", err) + } - a.k8sCli, err = k8sclient.NewForConfigAndClient(cfg, a.httpCli) - if err != nil { - a.cleanupClients() - return fmt.Errorf("failed to setup kubernetes client: %w", err) - } + log.Info("setting up K8s client...") + a.k8sCli, err = k8sclient.NewForConfigAndClient(restCfg, a.httpCli) + if err != nil { + a.cleanupClients() + return fmt.Errorf("failed to setup kubernetes client: %w", err) + } - restCfg := *cfg - a.nrtCli, err = nrtapi.NewForConfigAndClient(&restCfg, a.httpCli) - if err != nil { - a.cleanupClients() - return fmt.Errorf("failed to setup NRT client: %w", err) + kubeCfg := *restCfg + err = a.cfgIf.SetKubeClient(a.httpCli, &kubeCfg) + if err != nil { + return fmt.Errorf("failed to setup kubernetes config resource client: %w", err) + } } - restCfg = *cfg - err = a.cfgIf.SetKubeClient(a.httpCli, &restCfg) - if err != nil { - return fmt.Errorf("failed to setup kubernetes config resource client: %w", err) - } + a.configure(a.currentCfg) return nil } @@ -312,6 +314,51 @@ func (a *Agent) cleanupClients() { a.nrtCli = nil } +var ( + defaultConfig = &cfgapi.AgentConfig{ + NodeResourceTopology: true, + } +) + +func getAgentConfig(newConfig metav1.Object) *cfgapi.AgentConfig { + cfg := cfgapi.GetAgentConfig(newConfig) + if cfg == nil { + return defaultConfig + } + return cfg +} + +func (a *Agent) configure(newConfig metav1.Object) { + if a.hasLocalConfig() { + log.Warn("running with local configuration, skipping client setup...") + return + } + + cfg := getAgentConfig(newConfig) + + // Reconfigure NRT client, both on initial startup and reconfiguration. + // Failure to create a client is not a fatal error. + switch { + case cfg.NodeResourceTopology && a.nrtCli == nil: + log.Info("enabling NRT client") + cfg, err := a.getRESTConfig() + if err != nil { + log.Error("failed to setup NRT client: %w", err) + break + } + cli, err := nrtapi.NewForConfigAndClient(cfg, a.httpCli) + if err != nil { + log.Error("failed to setup NRT client: %w", err) + break + } + a.nrtCli = cli + + case !cfg.NodeResourceTopology && a.nrtCli != nil: + log.Info("disabling NRT client") + a.nrtCli = nil + } +} + func (a *Agent) getRESTConfig() (*rest.Config, error) { var ( cfg *rest.Config @@ -556,6 +603,7 @@ func (a *Agent) updateConfig(cfg metav1.Object) { } a.currentCfg = cfg + a.configure(cfg) } func (a *Agent) patchConfigStatus(prev, curr metav1.Object, errors error) { diff --git a/pkg/apis/config/v1alpha1/agent.go b/pkg/apis/config/v1alpha1/agent.go new file mode 100644 index 000000000..c01b9305a --- /dev/null +++ b/pkg/apis/config/v1alpha1/agent.go @@ -0,0 +1,31 @@ +// Copyright The NRI Plugins Authors. All Rights Reserved. +// +// 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 + +// AgentConfig provides access to configuration data for the agent. +type AgentConfig struct { + // NodeResourceTopology enables support for exporting resource usage using + // NodeResourceTopology Custom Resources. + // +optional + NodeResourceTopology bool `json:"nodeResourceTopology,omitempty"` +} + +// GetAgentConfig returns the agent-specific configuration if we have one. +func GetAgentConfig(cfg interface{}) *AgentConfig { + if ac, ok := cfg.(interface{ AgentConfig() *AgentConfig }); ok { + return ac.AgentConfig() + } + return nil +} diff --git a/pkg/apis/config/v1alpha1/balloons-policy.go b/pkg/apis/config/v1alpha1/balloons-policy.go index 9622b6b43..70fcb1423 100644 --- a/pkg/apis/config/v1alpha1/balloons-policy.go +++ b/pkg/apis/config/v1alpha1/balloons-policy.go @@ -18,6 +18,16 @@ var ( _ ResmgrConfig = &BalloonsPolicy{} ) +func (c *BalloonsPolicy) AgentConfig() *AgentConfig { + if c == nil { + return nil + } + + a := c.Spec.Agent + + return &a +} + func (c *BalloonsPolicy) CommonConfig() *CommonConfig { if c == nil { return nil diff --git a/pkg/apis/config/v1alpha1/resmgr.go b/pkg/apis/config/v1alpha1/resmgr.go index e89d4d2c9..d026f3a0c 100644 --- a/pkg/apis/config/v1alpha1/resmgr.go +++ b/pkg/apis/config/v1alpha1/resmgr.go @@ -29,6 +29,7 @@ import ( // +kubebuilder:object:generate=false type ResmgrConfig interface { metav1.ObjectMetaAccessor + AgentConfig() *AgentConfig CommonConfig() *CommonConfig PolicyConfig() interface{} } diff --git a/pkg/apis/config/v1alpha1/template-policy.go b/pkg/apis/config/v1alpha1/template-policy.go index 97258c947..3a598a742 100644 --- a/pkg/apis/config/v1alpha1/template-policy.go +++ b/pkg/apis/config/v1alpha1/template-policy.go @@ -18,6 +18,16 @@ var ( _ ResmgrConfig = &TemplatePolicy{} ) +func (c *TemplatePolicy) AgentConfig() *AgentConfig { + if c == nil { + return nil + } + + a := c.Spec.Agent + + return &a +} + func (c *TemplatePolicy) CommonConfig() *CommonConfig { if c == nil { return nil diff --git a/pkg/apis/config/v1alpha1/topology-aware-policy.go b/pkg/apis/config/v1alpha1/topology-aware-policy.go index 75df70498..2d4984649 100644 --- a/pkg/apis/config/v1alpha1/topology-aware-policy.go +++ b/pkg/apis/config/v1alpha1/topology-aware-policy.go @@ -18,6 +18,16 @@ var ( _ ResmgrConfig = &TopologyAwarePolicy{} ) +func (c *TopologyAwarePolicy) AgentConfig() *AgentConfig { + if c == nil { + return nil + } + + a := c.Spec.Agent + + return &a +} + func (c *TopologyAwarePolicy) CommonConfig() *CommonConfig { if c == nil { return nil diff --git a/pkg/apis/config/v1alpha1/types.go b/pkg/apis/config/v1alpha1/types.go index 07730aea2..5acc9ba70 100644 --- a/pkg/apis/config/v1alpha1/types.go +++ b/pkg/apis/config/v1alpha1/types.go @@ -46,6 +46,9 @@ type TopologyAwarePolicySpec struct { Log log.Config `json:"log,omitempty"` // +optional Instrumentation instrumentation.Config `json:"instrumentation,omitempty"` + // +optional + // +kubebuilder:default={"nodeResourceTopology": true } + Agent AgentConfig `json:"agent,omitempty"` } // TopologyAwarePolicyList represents a list of TopologyAwarePolicies. @@ -78,6 +81,9 @@ type BalloonsPolicySpec struct { Log log.Config `json:"log,omitempty"` // +optional Instrumentation instrumentation.Config `json:"instrumentation,omitempty"` + // +optional + // +kubebuilder:default={"nodeResourceTopology": true } + Agent AgentConfig `json:"agent,omitempty"` } // BalloonsPolicyList represents a list of BalloonsPolicies. @@ -110,6 +116,9 @@ type TemplatePolicySpec struct { Log log.Config `json:"log,omitempty"` // +optional Instrumentation instrumentation.Config `json:"instrumentation,omitempty"` + // +optional + // +kubebuilder:default={"nodeResourceTopology": true } + Agent AgentConfig `json:"agent,omitempty"` } // TemplatePolicyList represents a list of TemplatePolicies. diff --git a/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go index 2ca084794..21f01a9e6 100644 --- a/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go @@ -22,6 +22,21 @@ import ( 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 *AgentConfig) DeepCopyInto(out *AgentConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentConfig. +func (in *AgentConfig) DeepCopy() *AgentConfig { + if in == nil { + return nil + } + out := new(AgentConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BalloonsPolicy) DeepCopyInto(out *BalloonsPolicy) { *out = *in @@ -88,6 +103,7 @@ func (in *BalloonsPolicySpec) DeepCopyInto(out *BalloonsPolicySpec) { in.Control.DeepCopyInto(&out.Control) in.Log.DeepCopyInto(&out.Log) in.Instrumentation.DeepCopyInto(&out.Instrumentation) + out.Agent = in.Agent } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BalloonsPolicySpec. @@ -227,6 +243,7 @@ func (in *TemplatePolicySpec) DeepCopyInto(out *TemplatePolicySpec) { in.Control.DeepCopyInto(&out.Control) in.Log.DeepCopyInto(&out.Log) in.Instrumentation.DeepCopyInto(&out.Instrumentation) + out.Agent = in.Agent } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplatePolicySpec. @@ -305,6 +322,7 @@ func (in *TopologyAwarePolicySpec) DeepCopyInto(out *TopologyAwarePolicySpec) { in.Control.DeepCopyInto(&out.Control) in.Log.DeepCopyInto(&out.Log) in.Instrumentation.DeepCopyInto(&out.Instrumentation) + out.Agent = in.Agent } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyAwarePolicySpec.