Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Describe: Impl resource resolution for env vars #774

Open
adietish opened this issue Jul 19, 2024 · 0 comments
Open

Describe: Impl resource resolution for env vars #774

adietish opened this issue Jul 19, 2024 · 0 comments

Comments

@adietish
Copy link
Collaborator

adietish commented Jul 19, 2024

related to #553

Env variables in containers (and other resources) can be referenced by expressions.

example:
In Pod > spec > containers > [mycontainer] > env (and other places):

env:
   - name: MY_NODE_NAME
     valueFrom:
         fieldRef:
             fieldPath: spec.nodeName

Those expressions need to be resolved and their value displayed.
kubectl describe would print the resolved value and the expression (in parenthesis):

    Environment:
      MY_POD_NAME:             describe-test (v1:metadata.name)

Kubectl does it using the function resolverFn in the following ways:

1. EnvVarResolverFunc

https://github.com/kubernetes/kubectl/blob/b4d17b87f57c2be12098c13a8510466c1dfd04d1/pkg/describe/describe.go#L1976

case e.ValueFrom.FieldRef != nil:
	var valueFrom string
	if resolverFn != nil {
		valueFrom = resolverFn(e)
	}
	w.Write(LEVEL_3, "%s:\t%s (%s:%s)\n", e.Name, valueFrom, e.ValueFrom.FieldRef.APIVersion, e.ValueFrom.FieldRef.FieldPath)

resolverFn is defined as follows:
https://github.com/kubernetes/kubectl/blob/b4d17b87f57c2be12098c13a8510466c1dfd04d1/pkg/describe/describe.go#L2055

func EnvValueRetriever(pod *corev1.Pod) EnvVarResolverFunc {
	return func(e corev1.EnvVar) string {
		gv, err := schema.ParseGroupVersion(e.ValueFrom.FieldRef.APIVersion)
		if err != nil {
			return ""
		}
		gvk := gv.WithKind("Pod")
		internalFieldPath, _, err := scheme.Scheme.ConvertFieldLabel(gvk, e.ValueFrom.FieldRef.FieldPath, "")
		if err != nil {
			return "" // pod validation should catch this on create
		}

		valueFrom, err := fieldpath.ExtractFieldPathAsString(pod, internalFieldPath)
		if err != nil {
			return "" // pod validation should catch this on create
		}

		return valueFrom
	}
}

2.resourcehelper.ExtractContainerResourceValue

another way to resolve env var expressions is by looking up container resource values:
https://github.com/kubernetes/kubectl/blob/b4d17b87f57c2be12098c13a8510466c1dfd04d1/pkg/describe/describe.go#L1980

case e.ValueFrom.ResourceFieldRef != nil:
	valueFrom, err := resourcehelper.ExtractContainerResourceValue(e.ValueFrom.ResourceFieldRef, &container)
	if err != nil {
		valueFrom = ""
	}

Kubectl does this in the following way:
https://github.com/kubernetes/kubectl/blob/b4d17b87f57c2be12098c13a8510466c1dfd04d1/pkg/util/resource/resource.go#L190

func ExtractContainerResourceValue(fs *corev1.ResourceFieldSelector, container *corev1.Container) (string, error) {
	divisor := resource.Quantity{}
	if divisor.Cmp(fs.Divisor) == 0 {
		divisor = resource.MustParse("1")
	} else {
		divisor = fs.Divisor
	}

	switch fs.Resource {
	case "limits.cpu":
		return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor)
	case "limits.memory":
		return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor)
	case "limits.ephemeral-storage":
		return convertResourceEphemeralStorageToString(container.Resources.Limits.StorageEphemeral(), divisor)
	case "requests.cpu":
		return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor)
	case "requests.memory":
		return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor)
	case "requests.ephemeral-storage":
		return convertResourceEphemeralStorageToString(container.Resources.Requests.StorageEphemeral(), divisor)
	}
	// handle extended standard resources with dynamic names
	// example: requests.hugepages-<pageSize> or limits.hugepages-<pageSize>
	if strings.HasPrefix(fs.Resource, "requests.") {
		resourceName := corev1.ResourceName(strings.TrimPrefix(fs.Resource, "requests."))
		if IsHugePageResourceName(resourceName) {
			return convertResourceHugePagesToString(container.Resources.Requests.Name(resourceName, resource.BinarySI), divisor)
		}
	}
	if strings.HasPrefix(fs.Resource, "limits.") {
		resourceName := corev1.ResourceName(strings.TrimPrefix(fs.Resource, "limits."))
		if IsHugePageResourceName(resourceName) {
			return convertResourceHugePagesToString(container.Resources.Limits.Name(resourceName, resource.BinarySI), divisor)
		}
	}
	return "", fmt.Errorf("Unsupported container resource : %v", fs.Resource)
}
@adietish adietish changed the title Describe: Impl resource resolution for env var Describe: Impl resource resolution for env vars Jul 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant