From e1ebde9f9279cd5cd8a63587bcebc45f8b913f9d Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Wed, 22 Jun 2016 12:27:17 -0400 Subject: [PATCH 1/2] Add spec.nodeName and spec.serviceAccountName to downward env var The serviceAccountName is occasionally useful for clients running on Kube that need to know who they are when talking to other components. The nodeName is useful for PetSet or DaemonSet pods that need to make calls back to the API to fetch info about their node. Both fields are immutable, and cannot easily be retrieved in another way. --- pkg/api/types.go | 3 ++- pkg/api/v1/conversion.go | 13 ++++++------ pkg/api/v1/types.go | 3 ++- pkg/api/v1/types_swagger_doc_generated.go | 2 +- pkg/api/validation/validation.go | 2 +- pkg/api/validation/validation_test.go | 24 ++++++++++++++++++++--- pkg/kubelet/kubelet.go | 4 ++++ pkg/kubelet/kubelet_test.go | 24 +++++++++++++++++++++++ pkg/volume/downwardapi/downwardapi.go | 1 + 9 files changed, 63 insertions(+), 13 deletions(-) diff --git a/pkg/api/types.go b/pkg/api/types.go index 3c01ca773be..62606aef6c2 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -878,7 +878,8 @@ type EnvVar struct { // EnvVarSource represents a source for the value of an EnvVar. // Only one of its fields may be set. type EnvVarSource struct { - // Selects a field of the pod; only name and namespace are supported. + // Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, + // spec.nodeName, spec.serviceAccountName, status.podIP. FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"` // Selects a resource of the container: only resources limits and requests // (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. diff --git a/pkg/api/v1/conversion.go b/pkg/api/v1/conversion.go index d2cb2dc7acb..7e5a7cff6bf 100644 --- a/pkg/api/v1/conversion.go +++ b/pkg/api/v1/conversion.go @@ -192,14 +192,15 @@ func addConversionFuncs(scheme *runtime.Scheme) error { err = scheme.AddFieldLabelConversionFunc("v1", "Pod", func(label, value string) (string, string, error) { switch label { - case "metadata.name", - "metadata.namespace", + case "metadata.annotations", "metadata.labels", - "metadata.annotations", - "status.phase", - "status.podIP", + "metadata.name", + "metadata.namespace", "spec.nodeName", - "spec.restartPolicy": + "spec.restartPolicy", + "spec.serviceAccountName", + "status.phase", + "status.podIP": return label, value, nil // This is for backwards compatibility with old v1 clients which send spec.host case "spec.host": diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go index b7721211b84..6d5de4c5f74 100644 --- a/pkg/api/v1/types.go +++ b/pkg/api/v1/types.go @@ -990,7 +990,8 @@ type EnvVar struct { // EnvVarSource represents a source for the value of an EnvVar. type EnvVarSource struct { - // Selects a field of the pod; only name and namespace are supported. + // Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, + // spec.nodeName, spec.serviceAccountName, status.podIP. FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty" protobuf:"bytes,1,opt,name=fieldRef"` // Selects a resource of the container: only resources limits and requests // (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. diff --git a/pkg/api/v1/types_swagger_doc_generated.go b/pkg/api/v1/types_swagger_doc_generated.go index d1023eb4acc..6b4db441fce 100644 --- a/pkg/api/v1/types_swagger_doc_generated.go +++ b/pkg/api/v1/types_swagger_doc_generated.go @@ -424,7 +424,7 @@ func (EnvVar) SwaggerDoc() map[string]string { var map_EnvVarSource = map[string]string{ "": "EnvVarSource represents a source for the value of an EnvVar.", - "fieldRef": "Selects a field of the pod; only name and namespace are supported.", + "fieldRef": "Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.podIP.", "resourceFieldRef": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.", "configMapKeyRef": "Selects a key of a ConfigMap.", "secretKeyRef": "Selects a key of a secret in the pod's namespace", diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index f44b67dd229..13722e09a4d 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -1208,7 +1208,7 @@ func validateEnv(vars []api.EnvVar, fldPath *field.Path) field.ErrorList { return allErrs } -var validFieldPathExpressionsEnv = sets.NewString("metadata.name", "metadata.namespace", "status.podIP") +var validFieldPathExpressionsEnv = sets.NewString("metadata.name", "metadata.namespace", "spec.nodeName", "spec.serviceAccountName", "status.podIP") var validContainerResourceFieldPathExpressions = sets.NewString("limits.cpu", "limits.memory", "requests.cpu", "requests.memory") func validateEnvVarValueFrom(ev api.EnvVar, fldPath *field.Path) field.ErrorList { diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index b55447fc8d2..bf9cfd2bebd 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -2214,6 +2214,24 @@ func TestValidateEnv(t *testing.T) { }, }, }, + { + Name: "abc", + ValueFrom: &api.EnvVarSource{ + FieldRef: &api.ObjectFieldSelector{ + APIVersion: testapi.Default.GroupVersion().String(), + FieldPath: "spec.nodeName", + }, + }, + }, + { + Name: "abc", + ValueFrom: &api.EnvVarSource{ + FieldRef: &api.ObjectFieldSelector{ + APIVersion: testapi.Default.GroupVersion().String(), + FieldPath: "spec.serviceAccountName", + }, + }, + }, { Name: "secret_value", ValueFrom: &api.EnvVarSource{ @@ -2381,7 +2399,7 @@ func TestValidateEnv(t *testing.T) { }, }, }}, - expectedError: `[0].valueFrom.fieldRef.fieldPath: Unsupported value: "metadata.labels": supported values: metadata.name, metadata.namespace, status.podIP`, + expectedError: `[0].valueFrom.fieldRef.fieldPath: Unsupported value: "metadata.labels": supported values: metadata.name, metadata.namespace, spec.nodeName, spec.serviceAccountName, status.podIP`, }, { name: "invalid fieldPath annotations", @@ -2394,7 +2412,7 @@ func TestValidateEnv(t *testing.T) { }, }, }}, - expectedError: `[0].valueFrom.fieldRef.fieldPath: Unsupported value: "metadata.annotations": supported values: metadata.name, metadata.namespace, status.podIP`, + expectedError: `[0].valueFrom.fieldRef.fieldPath: Unsupported value: "metadata.annotations": supported values: metadata.name, metadata.namespace, spec.nodeName, spec.serviceAccountName, status.podIP`, }, { name: "unsupported fieldPath", @@ -2407,7 +2425,7 @@ func TestValidateEnv(t *testing.T) { }, }, }}, - expectedError: `valueFrom.fieldRef.fieldPath: Unsupported value: "status.phase": supported values: metadata.name, metadata.namespace, status.podIP`, + expectedError: `valueFrom.fieldRef.fieldPath: Unsupported value: "status.phase": supported values: metadata.name, metadata.namespace, spec.nodeName, spec.serviceAccountName, status.podIP`, }, } for _, tc := range errorCases { diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 470e67413a0..3ac93a5dfb7 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -1440,6 +1440,10 @@ func (kl *Kubelet) podFieldSelectorRuntimeValue(fs *api.ObjectFieldSelector, pod return "", err } switch internalFieldPath { + case "spec.nodeName": + return pod.Spec.NodeName, nil + case "spec.serviceAccountName": + return pod.Spec.ServiceAccountName, nil case "status.podIP": return podIP, nil } diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index 4e95769045b..12392b91dae 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -1379,6 +1379,24 @@ func TestMakeEnvironmentVariables(t *testing.T) { }, }, }, + { + Name: "POD_NODE_NAME", + ValueFrom: &api.EnvVarSource{ + FieldRef: &api.ObjectFieldSelector{ + APIVersion: testapi.Default.GroupVersion().String(), + FieldPath: "spec.nodeName", + }, + }, + }, + { + Name: "POD_SERVICE_ACCOUNT_NAME", + ValueFrom: &api.EnvVarSource{ + FieldRef: &api.ObjectFieldSelector{ + APIVersion: testapi.Default.GroupVersion().String(), + FieldPath: "spec.serviceAccountName", + }, + }, + }, { Name: "POD_IP", ValueFrom: &api.EnvVarSource{ @@ -1395,6 +1413,8 @@ func TestMakeEnvironmentVariables(t *testing.T) { expectedEnvs: []kubecontainer.EnvVar{ {Name: "POD_NAME", Value: "dapi-test-pod-name"}, {Name: "POD_NAMESPACE", Value: "downward-api"}, + {Name: "POD_NODE_NAME", Value: "node-name"}, + {Name: "POD_SERVICE_ACCOUNT_NAME", Value: "special"}, {Name: "POD_IP", Value: "1.2.3.4"}, }, }, @@ -1546,6 +1566,10 @@ func TestMakeEnvironmentVariables(t *testing.T) { Namespace: tc.ns, Name: "dapi-test-pod-name", }, + Spec: api.PodSpec{ + ServiceAccountName: "special", + NodeName: "node-name", + }, } podIP := "1.2.3.4" diff --git a/pkg/volume/downwardapi/downwardapi.go b/pkg/volume/downwardapi/downwardapi.go index 679c73114c3..4a640fdcc6a 100644 --- a/pkg/volume/downwardapi/downwardapi.go +++ b/pkg/volume/downwardapi/downwardapi.go @@ -215,6 +215,7 @@ func (d *downwardAPIVolume) collectData(defaultMode *int32) (map[string]volumeut fileProjection.Mode = *defaultMode } if fileInfo.FieldRef != nil { + // TODO: unify with Kubelet.podFieldSelectorRuntimeValue if values, err := fieldpath.ExtractFieldPathAsString(d.pod, fileInfo.FieldRef.FieldPath); err != nil { glog.Errorf("Unable to extract field %s: %s", fileInfo.FieldRef.FieldPath, err.Error()) errlist = append(errlist, err) From abded5c6c5a4f4e93c961688587904376cfe28d7 Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Sat, 20 Aug 2016 15:56:43 -0400 Subject: [PATCH 2/2] generated: Docs --- api/swagger-spec/apps_v1alpha1.json | 2 +- api/swagger-spec/batch_v1.json | 2 +- api/swagger-spec/extensions_v1beta1.json | 2 +- api/swagger-spec/v1.json | 2 +- docs/api-reference/batch/v1/definitions.html | 4 ++-- docs/api-reference/extensions/v1beta1/definitions.html | 4 ++-- docs/api-reference/v1/definitions.html | 4 ++-- pkg/api/v1/generated.proto | 3 ++- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/api/swagger-spec/apps_v1alpha1.json b/api/swagger-spec/apps_v1alpha1.json index a458269d136..6675ec5a533 100644 --- a/api/swagger-spec/apps_v1alpha1.json +++ b/api/swagger-spec/apps_v1alpha1.json @@ -2169,7 +2169,7 @@ "properties": { "fieldRef": { "$ref": "v1.ObjectFieldSelector", - "description": "Selects a field of the pod; only name and namespace are supported." + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.podIP." }, "resourceFieldRef": { "$ref": "v1.ResourceFieldSelector", diff --git a/api/swagger-spec/batch_v1.json b/api/swagger-spec/batch_v1.json index b01d01e195e..ba334774d5c 100644 --- a/api/swagger-spec/batch_v1.json +++ b/api/swagger-spec/batch_v1.json @@ -2174,7 +2174,7 @@ "properties": { "fieldRef": { "$ref": "v1.ObjectFieldSelector", - "description": "Selects a field of the pod; only name and namespace are supported." + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.podIP." }, "resourceFieldRef": { "$ref": "v1.ResourceFieldSelector", diff --git a/api/swagger-spec/extensions_v1beta1.json b/api/swagger-spec/extensions_v1beta1.json index 01af27aedcd..a57c6501ec8 100644 --- a/api/swagger-spec/extensions_v1beta1.json +++ b/api/swagger-spec/extensions_v1beta1.json @@ -9338,7 +9338,7 @@ "properties": { "fieldRef": { "$ref": "v1.ObjectFieldSelector", - "description": "Selects a field of the pod; only name and namespace are supported." + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.podIP." }, "resourceFieldRef": { "$ref": "v1.ResourceFieldSelector", diff --git a/api/swagger-spec/v1.json b/api/swagger-spec/v1.json index 597b35d08b5..6ce2935e05d 100644 --- a/api/swagger-spec/v1.json +++ b/api/swagger-spec/v1.json @@ -18271,7 +18271,7 @@ "properties": { "fieldRef": { "$ref": "v1.ObjectFieldSelector", - "description": "Selects a field of the pod; only name and namespace are supported." + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.podIP." }, "resourceFieldRef": { "$ref": "v1.ResourceFieldSelector", diff --git a/docs/api-reference/batch/v1/definitions.html b/docs/api-reference/batch/v1/definitions.html index 0b4f5ad1f9d..3fbdcd8fa2c 100755 --- a/docs/api-reference/batch/v1/definitions.html +++ b/docs/api-reference/batch/v1/definitions.html @@ -2838,7 +2838,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i

fieldRef

-

Selects a field of the pod; only name and namespace are supported.

+

Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.podIP.

false

v1.ObjectFieldSelector

@@ -4207,7 +4207,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i diff --git a/docs/api-reference/extensions/v1beta1/definitions.html b/docs/api-reference/extensions/v1beta1/definitions.html index 69a45b62896..86631d3fd68 100755 --- a/docs/api-reference/extensions/v1beta1/definitions.html +++ b/docs/api-reference/extensions/v1beta1/definitions.html @@ -2547,7 +2547,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i

fieldRef

-

Selects a field of the pod; only name and namespace are supported.

+

Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.podIP.

false

v1.ObjectFieldSelector

@@ -6595,7 +6595,7 @@ Both these may change in the future. Incoming requests are matched against the h diff --git a/docs/api-reference/v1/definitions.html b/docs/api-reference/v1/definitions.html index e6cc1e4f813..eac771c3d7f 100755 --- a/docs/api-reference/v1/definitions.html +++ b/docs/api-reference/v1/definitions.html @@ -3019,7 +3019,7 @@ The resulting set of endpoints can be viewed as:

fieldRef

-

Selects a field of the pod; only name and namespace are supported.

+

Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.podIP.

false

v1.ObjectFieldSelector

@@ -8285,7 +8285,7 @@ The resulting set of endpoints can be viewed as:
diff --git a/pkg/api/v1/generated.proto b/pkg/api/v1/generated.proto index 83b600868ad..7ce275d638e 100644 --- a/pkg/api/v1/generated.proto +++ b/pkg/api/v1/generated.proto @@ -683,7 +683,8 @@ message EnvVar { // EnvVarSource represents a source for the value of an EnvVar. message EnvVarSource { - // Selects a field of the pod; only name and namespace are supported. + // Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, + // spec.nodeName, spec.serviceAccountName, status.podIP. optional ObjectFieldSelector fieldRef = 1; // Selects a resource of the container: only resources limits and requests