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

Add NominatedNodeName field to PodStatus #58990

Merged
merged 2 commits into from
Feb 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/openapi-spec/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions api/swagger-spec/v1.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions docs/api-reference/v1/definitions.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/apis/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2724,6 +2724,13 @@ type PodStatus struct {
// A brief CamelCase message indicating details about why the pod is in this state. e.g. 'Evicted'
// +optional
Reason string
// nominatedNodeName is set when this pod preempts other pods on the node, but it cannot be
// scheduled right away as preemption victims receive their graceful termination periods.
// This field does not guarantee that the pod will be scheduled on this node. Scheduler may decide
// to place the pod elsewhere if other nodes become available sooner. Scheduler may also decide to
// give the resources on this node to a higher priority pod that is created after preemption.
// +optional
NominatedNodeName string

// +optional
HostIP string
Expand Down
3 changes: 2 additions & 1 deletion pkg/apis/core/v1/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
"spec.restartPolicy",
"spec.schedulerName",
"status.phase",
"status.podIP":
"status.podIP",
"status.nominatedNodeName":
return label, value, nil
// This is for backwards compatibility with old v1 clients which send spec.host
case "spec.host":
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/core/v1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/apis/core/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3374,6 +3374,12 @@ func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) field.ErrorList {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "may not be changed directly"))
}

if newPod.Status.NominatedNodeName != oldPod.Status.NominatedNodeName && len(newPod.Status.NominatedNodeName) > 0 {
for _, msg := range ValidateNodeName(newPod.Status.NominatedNodeName, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("nominatedNodeName"), newPod.Status.NominatedNodeName, msg))
}
}

// If pod should not restart, make sure the status update does not transition
// any terminated containers to a non-terminated state.
allErrs = append(allErrs, ValidateContainerStateTransition(newPod.Status.ContainerStatuses, oldPod.Status.ContainerStatuses, fldPath.Child("containerStatuses"), oldPod.Spec.RestartPolicy)...)
Expand Down
123 changes: 123 additions & 0 deletions pkg/apis/core/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7756,6 +7756,129 @@ func TestValidatePodUpdate(t *testing.T) {
}
}

func TestValidatePodStatusUpdate(t *testing.T) {
tests := []struct {
new core.Pod
old core.Pod
err string
test string
}{
{
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
NodeName: "node1",
},
Status: core.PodStatus{
NominatedNodeName: "node1",
},
},
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
NodeName: "node1",
},
Status: core.PodStatus{},
},
"",
"removed nominatedNodeName",
},
{
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
NodeName: "node1",
},
},
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
NodeName: "node1",
},
Status: core.PodStatus{
NominatedNodeName: "node1",
},
},
"",
"add valid nominatedNodeName",
},
{
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
NodeName: "node1",
},
Status: core.PodStatus{
NominatedNodeName: "Node1",
},
},
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
NodeName: "node1",
},
},
"nominatedNodeName",
"Add invalid nominatedNodeName",
},
{
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
NodeName: "node1",
},
Status: core.PodStatus{
NominatedNodeName: "node1",
},
},
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
NodeName: "node1",
},
Status: core.PodStatus{
NominatedNodeName: "node2",
},
},
"",
"Update nominatedNodeName",
},
}

for _, test := range tests {
test.new.ObjectMeta.ResourceVersion = "1"
test.old.ObjectMeta.ResourceVersion = "1"
errs := ValidatePodStatusUpdate(&test.new, &test.old)
if test.err == "" {
if len(errs) != 0 {
t.Errorf("unexpected invalid: %s (%+v)\nA: %+v\nB: %+v", test.test, errs, test.new, test.old)
}
} else {
if len(errs) == 0 {
t.Errorf("unexpected valid: %s\nA: %+v\nB: %+v", test.test, test.new, test.old)
} else if actualErr := errs.ToAggregate().Error(); !strings.Contains(actualErr, test.err) {
t.Errorf("unexpected error message: %s\nExpected error: %s\nActual error: %s", test.test, test.err, actualErr)
}
}
}
}

func makeValidService() core.Service {
return core.Service{
ObjectMeta: metav1.ObjectMeta{
Expand Down
3 changes: 3 additions & 0 deletions pkg/printers/internalversion/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,9 @@ func describePod(pod *api.Pod, events *api.EventList) (string, error) {
if controlledBy := printController(pod); len(controlledBy) > 0 {
w.Write(LEVEL_0, "Controlled By:\t%s\n", controlledBy)
}
if len(pod.Status.NominatedNodeName) > 0 {
w.Write(LEVEL_0, "NominatedNodeName:\t%s\n", pod.Status.NominatedNodeName)
}

if len(pod.Spec.InitContainers) > 0 {
describeContainers("Init Containers", pod.Spec.InitContainers, pod.Status.InitContainerStatuses, EnvValueRetriever(pod), w, "")
Expand Down
6 changes: 5 additions & 1 deletion pkg/printers/internalversion/describe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ func TestDescribePodNode(t *testing.T) {
NodeName: "all-in-one",
},
Status: api.PodStatus{
HostIP: "127.0.0.1",
HostIP: "127.0.0.1",
NominatedNodeName: "nodeA",
},
})
c := &describeClient{T: t, Namespace: "foo", Interface: fake}
Expand All @@ -92,6 +93,9 @@ func TestDescribePodNode(t *testing.T) {
if !strings.Contains(out, "all-in-one/127.0.0.1") {
t.Errorf("unexpected out: %s", out)
}
if !strings.Contains(out, "nodeA") {
t.Errorf("unexpected out: %s", out)
}
}

func TestDescribePodTolerations(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions pkg/printers/internalversion/printers.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,9 @@ func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1alpha1.Table
nodeName = "<none>"
}
row.Cells = append(row.Cells, podIP, nodeName)
if len(pod.Status.NominatedNodeName) > 0 {
row.Cells = append(row.Cells, pod.Status.NominatedNodeName)
}
}

return []metav1alpha1.TableRow{row}, nil
Expand Down
3 changes: 2 additions & 1 deletion pkg/printers/internalversion/printers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1704,9 +1704,10 @@ func TestPrintPodwide(t *testing.T) {
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
{RestartCount: 3},
},
NominatedNodeName: "node1",
},
},
[]metav1alpha1.TableRow{{Cells: []interface{}{"test1", "1/2", "podPhase", 6, "<unknown>", "1.1.1.1", "test1"}}},
[]metav1alpha1.TableRow{{Cells: []interface{}{"test1", "1/2", "podPhase", 6, "<unknown>", "1.1.1.1", "test1", "node1"}}},
},
{
// Test when the NodeName and PodIP are none
Expand Down
1 change: 1 addition & 0 deletions pkg/registry/core/pod/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ func PodToSelectableFields(pod *api.Pod) fields.Set {
podSpecificFieldsSet["spec.schedulerName"] = string(pod.Spec.SchedulerName)
podSpecificFieldsSet["status.phase"] = string(pod.Status.Phase)
podSpecificFieldsSet["status.podIP"] = string(pod.Status.PodIP)
podSpecificFieldsSet["status.nominatedNodeName"] = string(pod.Status.NominatedNodeName)
return generic.AddObjectMetaFieldsSet(podSpecificFieldsSet, &pod.ObjectMeta, true)
}

Expand Down
15 changes: 14 additions & 1 deletion pkg/registry/core/pod/strategy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,20 @@ func TestMatchPod(t *testing.T) {
fieldSelector: fields.ParseSelectorOrDie("status.podIP=4.3.2.1"),
expectMatch: false,
},
}
{
in: &api.Pod{
Status: api.PodStatus{NominatedNodeName: "node1"},
},
fieldSelector: fields.ParseSelectorOrDie("status.nominatedNodeName=node1"),
expectMatch: true,
},
{
in: &api.Pod{
Status: api.PodStatus{NominatedNodeName: "node1"},
},
fieldSelector: fields.ParseSelectorOrDie("status.nominatedNodeName=node2"),
expectMatch: false,
}}
for _, testCase := range testCases {
m := MatchPod(labels.Everything(), testCase.fieldSelector)
result, err := m.Matches(testCase.in)
Expand Down