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 feature flags for affinity/nodeSelector/tolerations #8645

Merged
merged 1 commit into from
Jul 17, 2020

Conversation

emaildanwilson
Copy link
Contributor

@emaildanwilson emaildanwilson commented Jul 15, 2020

Fixes #1816

Proposed Changes

  • Adds a flag kubernetes.podspec-affinity in config-features with a default of disabled
  • Adds a flag kubernetes.podspec-nodeselector in config-features with a default of disabled
  • Adds a flag kubernetes.podspec-tolerations in config-features with a default of disabled
  • Updates FromContextOrDefaults function to supply defaults for config-default, config-features and config-autoscaler individually when the context is missing any of those sections. A code path was discovered where features is nil.
  • Adds unit tests for each feature flag, some test consolidation was done to remove some boilerplate.

Release Note

Feature flags are now available to enable affinity, nodeSelector and tolerations for Knative Services. See config-features for details.

@knative-prow-robot knative-prow-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 15, 2020
@googlebot googlebot added the cla: yes Indicates the PR's author has signed the CLA. label Jul 15, 2020
@knative-prow-robot knative-prow-robot added needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jul 15, 2020
Copy link
Contributor

@knative-prow-robot knative-prow-robot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emaildanwilson: 0 warnings.

In response to this:

Fixes #1816

Proposed Changes

  • Adds a flag kubernetes.podspec-affinity in config-features with a default of disabled
  • Adds a flag kubernetes.podspec-nodeselector in config-features with a default of disabled
  • Adds a flag kubernetes.podspec-tolerations in config-features with a default of disabled
  • Updates FromContextOrDefaults function to supply defaults for config-default, config-features and config-autoscaler individually when the context is missing any of those sections. A code path was discovered where features is nil.
  • Adds unit tests for each feature flag, some test consolidation was done to remove some boilerplate.

Release Note

Feature flags are now available to enable affinity, nodeSelector and tolerations for Knative Services. See config-features for details.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@knative-prow-robot knative-prow-robot added area/API API objects and controllers needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Jul 15, 2020
@knative-prow-robot
Copy link
Contributor

Welcome @emaildanwilson! It looks like this is your first PR to knative/serving 🎉

@knative-prow-robot
Copy link
Contributor

Hi @emaildanwilson. Thanks for your PR.

I'm waiting for a knative member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

Copy link
Member

@mattmoor mattmoor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Produced via:
gofmt -s -w $(find -path './vendor' -prune -o -path './third_party' -prune -o -name '*.pb.go' -prune -o -type f -name '*.go' -print)
goimports -w $(find -name '*.go' | grep -v vendor | grep -v third_party | grep -v .pb.go | grep -v wire_gen.go)

@knative-prow-robot knative-prow-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 15, 2020
@emaildanwilson emaildanwilson changed the title WIP: add feature flags for affinity/nodeSelector/tolerations Add feature flags for affinity/nodeSelector/tolerations Jul 15, 2020
@knative-prow-robot knative-prow-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 15, 2020
@emaildanwilson
Copy link
Contributor Author

/assign @dprotaso

Comment on lines 48 to 64
if cfg := FromContext(ctx); cfg != nil {
return cfg
cfg := FromContext(ctx)
if cfg == nil {
cfg = &Config{}
}
defaults, _ := NewDefaultsConfigFromMap(map[string]string{})
features, _ := NewFeaturesConfigFromMap(map[string]string{})
autoscaler, _ := autoscalerconfig.NewConfigFromMap(map[string]string{})
return &Config{
Defaults: defaults,
Features: features,
Autoscaler: autoscaler,

if cfg.Defaults == nil {
defaults, _ := NewDefaultsConfigFromMap(map[string]string{})
cfg.Defaults = defaults
}

if cfg.Features == nil {
features, _ := NewFeaturesConfigFromMap(map[string]string{})
cfg.Features = features
}

if cfg.Autoscaler == nil {
autoscaler, _ := autoscalerconfig.NewConfigFromMap(map[string]string{})
cfg.Autoscaler = autoscaler
}
return cfg
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes a case where cfg is initialized in an autoscaler test with a context containing only autoscaling config. As a result Features is never populated and can panic when referenced. I thought it made sense to stop this from ever happening but if the preference is to add defensive code where Features is being used/or fix the autoscaler test I can make changes accordingly.

@@ -513,6 +507,138 @@ func TestPodSpecMultiContainerValidation(t *testing.T) {
}
}

func TestPodSpecFeatureValidation(t *testing.T) {
Copy link
Contributor Author

@emaildanwilson emaildanwilson Jul 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This iterates each podSpec feature running four tests against each feature. It makes adding new tests for new podSpec features easy and reduces the amount of duplicate test code. If this is acceptable I can move the test for FieldRef into this too. If the preference is to duplicate the code for each of these for clarity I can break them out into a test function for each one. ty.

@mpetason
Copy link

/ok-to-test

@knative-prow-robot knative-prow-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Jul 17, 2020
@knative-test-reporter-robot

The following jobs failed:

Test name Triggers Retries
pull-knative-serving-upgrade-tests 2020-07-17 17:54:30.498 +0000 UTC 1/3

Automatically retrying due to test flakiness...
/test pull-knative-serving-upgrade-tests

@@ -34,16 +35,9 @@ import (

type configOption func(*config.Config) *config.Config

func withMultiContainer() configOption {
func withFeature(feature string) configOption {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func withFeature(feature string) configOption {
func withFeature(feature string) configOption {

Maybe withFeatureEnabled or expand to withFeature(feature string, state Flag)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 - I'll go with withFeatureEnabled for now since the only use case is to enable features at this point.

Copy link
Member

@mattmoor mattmoor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple nits, but otherwise this looks like it will do the trick.

Comment on lines 54 to 55
defaults, _ := NewDefaultsConfigFromMap(map[string]string{})
cfg.Defaults = defaults
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
defaults, _ := NewDefaultsConfigFromMap(map[string]string{})
cfg.Defaults = defaults
cfg.Defaults, _ = NewDefaultsConfigFromMap(map[string]string{})

Comment on lines 59 to 60
features, _ := NewFeaturesConfigFromMap(map[string]string{})
cfg.Features = features
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
features, _ := NewFeaturesConfigFromMap(map[string]string{})
cfg.Features = features
cfg.Features, _ = NewFeaturesConfigFromMap(map[string]string{})

Comment on lines 64 to 65
autoscaler, _ := autoscalerconfig.NewConfigFromMap(map[string]string{})
cfg.Autoscaler = autoscaler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
autoscaler, _ := autoscalerconfig.NewConfigFromMap(map[string]string{})
cfg.Autoscaler = autoscaler
cfg.Autoscaler, _ = autoscalerconfig.NewConfigFromMap(map[string]string{})

@@ -136,7 +137,7 @@ func KeyToPathMask(in *corev1.KeyToPath) *corev1.KeyToPath {
// PodSpecMask performs a _shallow_ copy of the Kubernetes PodSpec object to a new
// Kubernetes PodSpec object bringing over only the fields allowed in the Knative API. This
// does not validate the contents or the bounds of the provided fields.
func PodSpecMask(in *corev1.PodSpec) *corev1.PodSpec {
func PodSpecMask(in *corev1.PodSpec, features *config.Features) *corev1.PodSpec {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How hard would it be to plumb context into here instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be easy enough. I'll give it a go.

func withFieldRef() configOption {
return func(cfg *config.Config) *config.Config {
cfg.Features.PodSpecFieldRef = config.Enabled
reflect.Indirect(reflect.ValueOf(&cfg.Features)).Elem().FieldByName(feature).Set(reflect.ValueOf(config.Enabled))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like if folks hold this wrong (even a typo) they're gonna have a really bad time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed but it's test code only and reduces boiler plate. If you'd still rather I spell each function out then I don't mind.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's spell it out for now.

I can imagine a simpler solution where each feature is a package constant with some helper methods to apply states on configs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, will do.

@evankanderson
Copy link
Member

/assign @whaught

Just to make sure that Weston's review is easily findable when he's working on his approver badge.

Comment on lines 54 to 55
defaults, _ := NewDefaultsConfigFromMap(map[string]string{})
cfg.Defaults = defaults
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
defaults, _ := NewDefaultsConfigFromMap(map[string]string{})
cfg.Defaults = defaults
cfg.Defaults = defaultDefaultsConfig()

Comment on lines 59 to 60
features, _ := NewFeaturesConfigFromMap(map[string]string{})
cfg.Features = features
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
features, _ := NewFeaturesConfigFromMap(map[string]string{})
cfg.Features = features
cfg.Features = defaultFeaturesConfig()

}

if cfg.Autoscaler == nil {
autoscaler, _ := autoscalerconfig.NewConfigFromMap(map[string]string{})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should expose these consistently - but that's a separate issue

Comment on lines 563 to 567
podSpec: corev1.PodSpec{
Containers: []corev1.Container{{
Image: "busybox",
}},
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all the podSpecs are the same so I wonder if we can drop as an input

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most likely. I was thinking there may be cases where it would be needed but clearly I didn't have one :)

@@ -136,11 +139,12 @@ func KeyToPathMask(in *corev1.KeyToPath) *corev1.KeyToPath {
// PodSpecMask performs a _shallow_ copy of the Kubernetes PodSpec object to a new
// Kubernetes PodSpec object bringing over only the fields allowed in the Knative API. This
// does not validate the contents or the bounds of the provided fields.
func PodSpecMask(in *corev1.PodSpec) *corev1.PodSpec {
func PodSpecMask(in *corev1.PodSpec, ctx context.Context) *corev1.PodSpec {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put the context first

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, np.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, np. done.

update formatting

improvements from review feedback

spell out functions to enable features

put context first
@emaildanwilson
Copy link
Contributor Author

Thank you @mattmoor @dprotaso & @whaught for the review!
Feedback is incorporated.

@dprotaso
Copy link
Member

/lgtm
/approve

thanks for the PR @emaildanwilson 🎉

@knative-prow-robot knative-prow-robot added the lgtm Indicates that a PR is ready to be merged. label Jul 17, 2020
@knative-prow-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dprotaso, emaildanwilson

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow-robot knative-prow-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 17, 2020
@knative-metrics-robot
Copy link

The following is the coverage report on the affected files.
Say /test pull-knative-serving-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
pkg/apis/serving/fieldmask.go 97.9% 97.9% 0.0

@whaught
Copy link
Contributor

whaught commented Jul 17, 2020

/lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/API API objects and controllers cla: yes Indicates the PR's author has signed the CLA. lgtm Indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using nodeSelector/tolerations with Serving?
10 participants