Change:
When kube-proxy fails to open a nodeport, it gives up setting up the rest of the iptables rules for the service. Leaving the service not usable. Cannot even use it with clusterIP. Kube-proxy only logs this error in . No useful information can be retrieved with kubectl. Need to record a event at least.
Ideally would the changes be removed and then reported back? Is there a preferred log or place to return the error?
the event maybe a better solution; as other port maybe success.
Need to surface the problem somewhere. An event seems okay
, there's and in ; should we reuse it or create new recorders for ?
Just reuse it. After all, it is within the same component. Are you going to submit a PR?
sure, my pleasure.
Great! Thanks! Let me know when the PR is ready.

Discussion:
// IPTablesMasqueradeBit must be specified or defaulted. return nil, fmt.Errorf("Unable to read IPTablesMasqueradeBit from config") } <del> proxierIPTables, err := iptables.NewProxier(iptInterface, utilsysctl.New(), execer, config.IPTablesSyncPeriod.Duration, config.IPTablesMinSyncPeriod.Duration, config.MasqueradeAll, int(*config.IPTablesMasqueradeBit), config.ClusterCIDR, hostname, getNodeIP(client, hostname)) </del> <ins> proxierIPTables, err := iptables.NewProxier( iptInterface, utilsysctl.New(), execer, config.IPTablesSyncPeriod.Duration, config.IPTablesMinSyncPeriod.Duration, config.MasqueradeAll, int(*config.IPTablesMasqueradeBit), config.ClusterCIDR, hostname, getNodeIP(client, hostname), recorder, ) </ins> if err != nil { glog.Fatalf("Unable to create proxier: %v", err) }

deps = [ "//pkg/api:go_default_library", "//pkg/api/service:go_default_library", <ins> "//pkg/api/v1:go_default_library", "//pkg/client/record:go_default_library", </ins> "//pkg/proxy:go_default_library", "//pkg/proxy/healthcheck:go_default_library", "//pkg/types:go_default_library",

"github.com/golang/glog" "k8s.io/kubernetes/pkg/api" apiservice "k8s.io/kubernetes/pkg/api/service" <ins> "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/client/record" </ins> "k8s.io/kubernetes/pkg/proxy" "k8s.io/kubernetes/pkg/proxy/healthcheck" "k8s.io/kubernetes/pkg/types"

hostname       string nodeIP         net.IP portMapper     portOpener <ins> recorder       record.EventRecorder </ins> } type localPort struct {

// An error will be returned if iptables fails to update or acquire the initial lock. // Once a proxier is created, it will keep iptables up to date in the background and // will not terminate if a particular iptables call fails. <del> func NewProxier(ipt utiliptables.Interface, sysctl utilsysctl.Interface, exec utilexec.Interface, syncPeriod time.Duration, minSyncPeriod time.Duration, masqueradeAll bool, masqueradeBit int, clusterCIDR string, hostname string, nodeIP net.IP) (*Proxier, error) { </del> <ins> func NewProxier(ipt utiliptables.Interface, sysctl utilsysctl.Interface, exec utilexec.Interface, syncPeriod time.Duration, minSyncPeriod time.Duration, masqueradeAll bool, masqueradeBit int, clusterCIDR string, hostname string, nodeIP net.IP, recorder record.EventRecorder, ) (*Proxier, error) { </ins> // check valid user input if minSyncPeriod > syncPeriod { return nil, fmt.Errorf("min-sync (%v) must be < sync(%v)", minSyncPeriod, syncPeriod)

hostname:       hostname, nodeIP:         nodeIP, portMapper:     &listenPortOpener{}, <ins> recorder:       recorder, </ins> }, nil }

} else { socket, err := proxier.portMapper.OpenLocalPort(&lp) if err != nil { <del> glog.Errorf("can't open %s, skipping this externalIP: %v", lp.String(), err) </del> <ins> msg := fmt.Sprintf("can't open %s, skipping this externalIP: %v", lp.String(), err) proxier.recorder.Eventf( &v1.ObjectReference{ Kind:      "Node", Name:      proxier.hostname, UID:       types.UID(proxier.hostname), Namespace: "", }, api.EventTypeWarning, err.Error(), msg) glog.Error(msg) </ins> continue } replacementPortsMap[lp] = socket