Skip to content

Commit 537e4a0

Browse files
Add configurable logging to CiscoDevice API (#74)
Co-authored-by: Richard Cunningham <cunningr@cisco.com>
1 parent e8a5b2b commit 537e4a0

8 files changed

Lines changed: 107 additions & 6 deletions

File tree

api/v1alpha1/types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ type DeviceSpec struct {
117117
// +kubebuilder:validation:Optional
118118
Zone string `json:"zone,omitempty" mapstructure:"zone,omitempty"`
119119

120+
// LogLevel sets the logging verbosity for the VK instance.
121+
// Valid values are: debug, info, warn, error.
122+
// +kubebuilder:validation:Optional
123+
// +kubebuilder:validation:Enum=debug;info;warn;error
124+
// +kubebuilder:default=info
125+
LogLevel string `json:"logLevel,omitempty" mapstructure:"logLevel"`
126+
120127
// ResourceLimits defines default and maximum resource allocations.
121128
// +kubebuilder:validation:Optional
122129
ResourceLimits ResourceConfig `json:"resourceLimits,omitempty" mapstructure:"resourceLimits"`

charts/cisco-virtual-kubelet/crds/cisco.vk_ciscodevices.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,17 @@ spec:
9696
type: string
9797
description: Labels to apply to the virtual kubelet node.
9898
type: object
99+
logLevel:
100+
default: info
101+
description: |-
102+
LogLevel sets the logging verbosity for the VK instance.
103+
Valid values are: debug, info, warn, error.
104+
enum:
105+
- debug
106+
- info
107+
- warn
108+
- error
109+
type: string
99110
maxPods:
100111
default: 16
101112
description: MaxPods is the maximum number of pods the device can

cmd/cisco-vk/run.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,14 @@ func runVirtualKubelet(cmd *cobra.Command, args []string) error {
139139
},
140140
})
141141

142-
// Log level: flag > env > default
142+
// Log level: flag > env > config > default
143143
lvl := logLevel
144144
if lvl == "" {
145145
lvl = os.Getenv("LOG_LEVEL")
146146
}
147+
if lvl == "" {
148+
lvl = appCfg.Device.LogLevel
149+
}
147150
if err := validateLogLevel(lvl); err != nil {
148151
return err
149152
}

config/crd/cisco.vk_ciscodevices.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,17 @@ spec:
9696
type: string
9797
description: Labels to apply to the virtual kubelet node.
9898
type: object
99+
logLevel:
100+
default: info
101+
description: |-
102+
LogLevel sets the logging verbosity for the VK instance.
103+
Valid values are: debug, info, warn, error.
104+
enum:
105+
- debug
106+
- info
107+
- warn
108+
- error
109+
type: string
99110
maxPods:
100111
default: 16
101112
description: MaxPods is the maximum number of pods the device can

dev/deviceConfig.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ spec:
1212
tls:
1313
enabled: true
1414
insecureSkipVerify: true
15+
logLevel: info
1516
podCIDR: "10.0.0.0/24"
1617
xe:
1718
networking:

internal/config/testdata/valid_config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ device:
44
port: 80
55
username: admin
66
password: admin
7+
logLevel: debug
78
tls:
89
enabled: true
910
insecureSkipVerify: true

internal/controller/ciscodevice_controller.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,7 @@ func (r *CiscoDeviceReconciler) Reconcile(ctx context.Context, req ctrl.Request)
178178
{
179179
Name: "cisco-vk",
180180
Image: image,
181-
Args: []string{
182-
"run",
183-
"--config", configMountPath + "/" + configFileName,
184-
"--nodename", device.Name,
185-
},
181+
Args: vkContainerArgs(device.Name, device.Spec.LogLevel),
186182
VolumeMounts: []corev1.VolumeMount{
187183
{
188184
Name: "device-config",
@@ -255,6 +251,20 @@ func renderDeviceConfig(spec *ciskov1.DeviceSpec) (string, error) {
255251
return string(out), nil
256252
}
257253

254+
// vkContainerArgs builds the argument list for the VK container.
255+
// If logLevel is set on the CiscoDevice spec it is forwarded via --log-level.
256+
func vkContainerArgs(deviceName, logLevel string) []string {
257+
args := []string{
258+
"run",
259+
"--config", configMountPath + "/" + configFileName,
260+
"--nodename", deviceName,
261+
}
262+
if logLevel != "" {
263+
args = append(args, "--log-level", logLevel)
264+
}
265+
return args
266+
}
267+
258268
// shortHash returns the first 8 hex chars of an FNV-1a hash of s.
259269
// Used as a cheap change-detector for pod template annotations.
260270
func shortHash(s string) string {

internal/controller/ciscodevice_controller_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,63 @@ func TestReconcile_OwnerReferenceSet(t *testing.T) {
326326
}
327327
}
328328

329+
// ─────────────────────────────────────────────────────────────────────────────
330+
// vkContainerArgs helper
331+
// ─────────────────────────────────────────────────────────────────────────────
332+
333+
func TestVkContainerArgs_NoLogLevel(t *testing.T) {
334+
args := vkContainerArgs("router-x", "")
335+
for _, a := range args {
336+
if a == "--log-level" {
337+
t.Fatal("--log-level should not be present when logLevel is empty")
338+
}
339+
}
340+
if args[0] != "run" {
341+
t.Errorf("expected first arg 'run', got %q", args[0])
342+
}
343+
}
344+
345+
func TestVkContainerArgs_WithLogLevel(t *testing.T) {
346+
args := vkContainerArgs("router-x", "debug")
347+
found := false
348+
for i, a := range args {
349+
if a == "--log-level" && i+1 < len(args) && args[i+1] == "debug" {
350+
found = true
351+
break
352+
}
353+
}
354+
if !found {
355+
t.Errorf("expected --log-level debug in args, got %v", args)
356+
}
357+
}
358+
359+
func TestReconcile_LogLevelPassedToDeployment(t *testing.T) {
360+
device := newDevice("router-ll", "default")
361+
device.Spec.LogLevel = "debug"
362+
r := reconcilerFor(t, device)
363+
ctx := context.Background()
364+
365+
if _, err := r.Reconcile(ctx, reconcileRequest("default", "router-ll")); err != nil {
366+
t.Fatalf("Reconcile error: %v", err)
367+
}
368+
369+
var deploy appsv1.Deployment
370+
if err := r.Get(ctx, types.NamespacedName{Namespace: "default", Name: "router-ll" + deploymentSuffix}, &deploy); err != nil {
371+
t.Fatalf("Deployment not found: %v", err)
372+
}
373+
args := deploy.Spec.Template.Spec.Containers[0].Args
374+
found := false
375+
for i, a := range args {
376+
if a == "--log-level" && i+1 < len(args) && args[i+1] == "debug" {
377+
found = true
378+
break
379+
}
380+
}
381+
if !found {
382+
t.Errorf("expected --log-level debug in container args, got %v", args)
383+
}
384+
}
385+
329386
// ─────────────────────────────────────────────────────────────────────────────
330387
// Pure helper: renderDeviceConfig
331388
// ─────────────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)