Change:
Is this a BUG REPORT or FEATURE REQUEST?: /kind bug What happened: When running , and passing the flag which was introduced in , the following error occurs: What you expected to happen: The proxy should work as it used to, supporting this mode. How to reproduce it (as minimally and precisely as possible): ./kube- --proxy-mode=kernelspace Anything else we need to know?: This was introduced after the validation was refactored in which regressed validation for . IPVS validation (and thus support) was later , but we need another mode for Windows. Environment: Kubernetes version (use ): v1.10.0-alpha.0.684+ Cloud provider or hardware configuration: n/a OS (e.g. from ): Windows Server Core 1709 Kernel (e.g. ): Install tools: Others:
/sig windows /sig network
Tentatively adding milestone so we can track getting consensus on release-blocking status.
/priority critical-urgent
[MILESTONENOTIFIER] Milestone Issue Needs Approval Action required: This issue must have the label applied by a SIG maintainer. <details<summaryIssue Labels</summary- : Issue will be escalated to these SIGs if needed. : Never automatically move issue out of a release milestone; continually escalate to contributor and SIG through all available channels. : Fixes a bug discovered during the current release. </details<details<summaryHelp</summary<ul<li<a href=""Additional instructions</a</li<li<a href=""Commands for setting labels</a</li</ul</details

Discussion:
ConfigSyncPeriod metav1.Duration } <del> // Currently two modes of proxying are available: 'userspace' (older, stable) or 'iptables' // (newer, faster). If blank, use the best-available proxy (currently iptables, but may // change in future versions).  If the iptables proxy is selected, regardless of how, but // the system's kernel or iptables versions are insufficient, this always falls back to the // userspace proxy. </del> <ins> // Currently, four modes of proxying are available total: 'userspace' (older, stable), 'iptables' // (newer, faster), 'ipvs', and 'kernelspace' (Windows only, newer). // // If blank, use the best-available proxy (currently iptables, but may change in // future versions). If the iptables proxy is selected, regardless of how, but // the system's kernel or iptables versions are insufficient, this always falls // back to the userspace proxy. </ins> type ProxyMode string const ( <del> ProxyModeUserspace ProxyMode = "userspace" ProxyModeIPTables  ProxyMode = "iptables" ProxyModeIPVS      ProxyMode = "ipvs" </del> <ins> ProxyModeUserspace   ProxyMode = "userspace" ProxyModeIPTables    ProxyMode = "iptables" ProxyModeIPVS        ProxyMode = "ipvs" ProxyModeKernelspace ProxyMode = "kernelspace" </ins> ) // IPVSSchedulerMethod is the algorithm for allocating TCP connections and

import ( "fmt" "net" <ins> "runtime" </ins> "strconv" "strings"

} func validateProxyMode(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList { <ins> if runtime.GOOS == "windows" { return validateProxyModeWindows(mode, fldPath) } return validateProxyModeLinux(mode, fldPath) } func validateProxyModeLinux(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList { </ins> allErrs := field.ErrorList{} switch mode { case kubeproxyconfig.ProxyModeUserspace: case kubeproxyconfig.ProxyModeIPTables:

case "": default: modes := []string{string(kubeproxyconfig.ProxyModeUserspace), string(kubeproxyconfig.ProxyModeIPTables), string(kubeproxyconfig.ProxyModeIPVS)} <del> errMsg := fmt.Sprintf("must be %s or blank (blank means the best-available proxy (currently iptables)", strings.Join(modes, ",")) </del> <ins> errMsg := fmt.Sprintf("must be %s or blank (blank means the best-available proxy [currently iptables])", strings.Join(modes, ",")) allErrs = append(allErrs, field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg)) } return allErrs } func validateProxyModeWindows(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} switch mode { case kubeproxyconfig.ProxyModeUserspace: case kubeproxyconfig.ProxyModeKernelspace: default: modes := []string{string(kubeproxyconfig.ProxyModeUserspace), string(kubeproxyconfig.ProxyModeKernelspace)} errMsg := fmt.Sprintf("must be %s or blank (blank means the most-available proxy [currently userspace])", strings.Join(modes, ",")) </ins> allErrs = append(allErrs, field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg)) } return allErrs

import ( "fmt" <ins> "runtime" </ins> "strings" "testing" "time"

newPath := field.NewPath("KubeProxyConfiguration") successCases := []kubeproxyconfig.ProxyMode{ kubeproxyconfig.ProxyModeUserspace, <del> kubeproxyconfig.ProxyModeIPTables, kubeproxyconfig.ProxyModeIPVS, </del> kubeproxyconfig.ProxyMode(""), } <ins> if runtime.GOOS == "windows" { successCases = append(successCases, kubeproxyconfig.ProxyModeKernelspace) } else { successCases = append(successCases, kubeproxyconfig.ProxyModeIPTables, kubeproxyconfig.ProxyModeIPVS) } </ins> for _, successCase := range successCases { if errs := validateProxyMode(successCase, newPath.Child("ProxyMode")); len(errs) != 0 { t.Errorf("expected success: %v", errs)

}{ { mode: kubeproxyconfig.ProxyMode("non-existing"), <del> msg:  "or blank (blank means the best-available proxy (currently iptables)", </del> <ins> msg:  "or blank (blank means the", </ins> }, } for _, errorCase := range errorCases { if errs := validateProxyMode(errorCase.mode, newPath.Child("ProxyMode")); len(errs) == 0 { <del> t.Errorf("expected failure for %s", errorCase.msg) </del> <ins> t.Errorf("expected failure %s for %v", errorCase.msg, errorCase.mode) </ins> } else if !strings.Contains(errs[0].Error(), errorCase.msg) { t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg) }