Skip to content

rebase to 1.7 #15100

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

Closed
wants to merge 82 commits into from
Closed

rebase to 1.7 #15100

wants to merge 82 commits into from

Conversation

deads2k
Copy link
Contributor

@deads2k deads2k commented Jul 7, 2017

Pull to rebase to 1.7.

Failing e2es

  1. Extended.[k8s.io] Services should be able to create a functioning NodePort service - sjennings thought this wouldn't work without a cloud provider. - I've disabled for now, added to post rebase list.
  2. Extended.[k8s.io] StatefulSet [k8s.io] Basic StatefulSet functionality [StatefulSetBasic] should adopt matching orphans and release non-matching pods - this passes, but cleanup fails, so it takes 10 minutes
  3. Extended.[k8s.io] StatefulSet [k8s.io] Basic StatefulSet functionality [StatefulSetBasic] should not deadlock when a pod's predecessor fails - this passes, but cleanup fails, so it takes 10 minutes
  4. Extended.[k8s.io] SchedulerPriorities [Serial] Pod should be schedule to node that don't match the PodAntiAffinity terms - I've disabled for now, added to post rebase list.

Flake

  1. Extended.[k8s.io] SchedulerPriorities [Serial] Pod should perfer to scheduled to nodes pod can tolerate observed https://ci.openshift.redhat.com/jenkins/job/test_pull_request_origin_extended_conformance_gce/4329/
  2. end-to-end-docker.sh is flaking a lot on Flake: github.com/openshift/origin/test/end-to-end/core.test/end-to-end/core.sh:389 #14897

@deads2k deads2k mentioned this pull request Jul 7, 2017
@deads2k
Copy link
Contributor Author

deads2k commented Jul 7, 2017

@rootfs @liggitt @sttts @derekwaynecarr @bparees @fabianofranz @juanvallejo @danwinship You all have commits with your names in them. Please review them for correctness. I will re-ping as new commits are added for particular people.

@@ -241,7 +241,7 @@ func (h *binaryInstantiateHandler) handle(r io.Reader) (runtime.Object, error) {
if err != nil {
return nil, errors.NewInternalError(fmt.Errorf("unable to connect to node, could not retrieve TLS client config: %v", err))
}
upgrader := spdy.NewRoundTripper(tlsClientConfig)
upgrader := spdy.NewRoundTripper(tlsClientConfig, false)
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the question/what does false represent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what's the question/what does false represent?

FollowRedirects. You don't follow all of your upstream dependencies? I'm shocked! :)

Copy link
Contributor

Choose a reason for hiding this comment

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

all? any! :)

anyway i guess we wouldn't anticipate a redirect on this codepath, but i'm not sure there's a good reason not to follow a redirect if there is one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

anyway i guess we wouldn't anticipate a redirect on this codepath, but i'm not sure there's a good reason not to follow a redirect if there is one?

It requires peeking and guessing at what the content is. I think I'd default to off.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok

if volume.VolumeSource.Metadata != nil {
return true
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

not sure why this is in the commit w/ my name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not sure why this is in the commit w/ my name?

I wondered what happened to @enj's commit.

@@ -502,6 +502,9 @@ func CompleteAppConfig(config *newcmd.AppConfig, f *clientcmd.Factory, c *cobra.
if config.ClientMapper == nil {
config.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping)
}
if config.CategoryExpander == nil {
config.CategoryExpander = f.CategoryExpander()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

not sure what this is but if it's needed for the resourcebuilder now, it seems reasonable enough to me.

@danwinship
Copy link
Contributor

I think separate: DANW: router metrics changed/disabled! was supposed to be tagged @smarterclayton not me. (At least, he originally wrote the code that gets modified by that commit, and I know nothing about it.)

@deads2k
Copy link
Contributor Author

deads2k commented Jul 7, 2017

I think separate: DANW: router metrics changed/disabled! was supposed to be tagged @smarterclayton not me. (At least, he originally wrote the code that gets modified by that commit, and I know nothing about it.)

Ok. I'll update for that then. I just chose you based on package name.

@deads2k
Copy link
Contributor Author

deads2k commented Jul 7, 2017

Alright, I've gotten down to just #15104 and #15101 stopping progress on compiling the main process, blocking e2e, test-integration.sh, and test-cmd.sh.

[deads@deads-dev-01 origin]$ nice make 2>&1 | tee ../build.log
hack/build-go.sh  
++ Building go targets for linux/amd64: cmd/openshift cmd/oc cmd/kubefed pkg/sdn/plugin/sdn-cni-plugin vendor/github.com/containernetworking/cni/plugins/ipam/host-local vendor/github.com/containernetworking/cni/plugins/main/loopback
# github.com/openshift/origin/pkg/proxy/hybrid
pkg/proxy/hybrid/proxy.go:97: not enough arguments in call to p.unidlingProxy.OnServiceUpdate
	have ([]*"github.com/openshift/origin/vendor/k8s.io/kubernetes/pkg/api".Service)
	want (*"github.com/openshift/origin/vendor/k8s.io/kubernetes/pkg/api".Service, *"github.com/openshift/origin/vendor/k8s.io/kubernetes/pkg/api".Service)
# github.com/openshift/origin/pkg/sdn/plugin/sdn-cni-plugin
pkg/sdn/plugin/sdn-cni-plugin/openshift-sdn.go:91: invalid pointer type *types.Result for composite literal
pkg/sdn/plugin/sdn-cni-plugin/openshift-sdn.go:106: result.Print undefined (type *types.Result is pointer to interface, not interface)
# github.com/openshift/origin/pkg/proxy/unidler
pkg/proxy/unidler/unidlersocket.go:265: svcInfo.ServiceRef undefined (type *userspace.ServiceInfo has no field or method ServiceRef)
pkg/proxy/unidler/unidlersocket.go:345: svcInfo.ServiceRef undefined (type *userspace.ServiceInfo has no field or method ServiceRef)
# github.com/openshift/origin/pkg/sdn/plugin
pkg/sdn/plugin/pod_linux.go:174: result.IP4 undefined (type "github.com/openshift/origin/vendor/github.com/containernetworking/cni/pkg/types".Result has no field or method IP4)
pkg/sdn/plugin/pod_linux.go:178: cannot use result (type "github.com/openshift/origin/vendor/github.com/containernetworking/cni/pkg/types".Result) as type *"github.com/openshift/origin/vendor/github.com/containernetworking/cni/pkg/types".Result in return argument:
	*"github.com/openshift/origin/vendor/github.com/containernetworking/cni/pkg/types".Result is pointer to interface, not interface
pkg/sdn/plugin/pod_linux.go:242: ipamResult.IP4 undefined (type *"github.com/openshift/origin/vendor/github.com/containernetworking/cni/pkg/types".Result is pointer to interface, not interface)
pkg/sdn/plugin/pod_linux.go:276: contVeth.Attrs undefined (type "net".Interface has no field or method Attrs)
pkg/sdn/plugin/pod_linux.go:276: cannot assign netlink.Link to contVeth (type "net".Interface) in multiple assignment
pkg/sdn/plugin/pod_linux.go:282: ipamResult.IP4 undefined (type *"github.com/openshift/origin/vendor/github.com/containernetworking/cni/pkg/types".Result is pointer to interface, not interface)
pkg/sdn/plugin/pod_linux.go:283: cannot use ipamResult (type *"github.com/openshift/origin/vendor/github.com/containernetworking/cni/pkg/types".Result) as type *current.Result in argument to ipam.ConfigureIface
pkg/sdn/plugin/pod_linux.go:295: hostVeth.Attrs undefined (type "net".Interface has no field or method Attrs)
pkg/sdn/plugin/pod_linux.go:296: contVeth.Attrs undefined (type "net".Interface has no field or method Attrs)

mainServicesHandler config.ServiceConfigHandler
unidlingLoadBalancer EndpointsConfigHandler
mainEndpointsHandler EndpointsConfigHandler
mainServicesHandler ServiceConfigHandler
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like the upstream types were renamed to EndpointsHandler and ServiceHandler. This is going to need a bunch of work though because the interfaces have grown and HybridProxier needs to implement the new functions. I guess you already filed #15101 for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like the upstream types were renamed to EndpointsHandler and ServiceHandler. This is going to need a bunch of work though because the interfaces have grown and HybridProxier needs to implement the new functions. I guess you already filed #15101 for this.

Yeah. Sounds like I may as well revert that commit and let a real fix come. The guts changed a lot.

Copy link
Contributor

Choose a reason for hiding this comment

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

The hybrid proxy is gonna suck. They split things up so you no longer get the full endpoint set, you get add/remove/change/etc events. And that makes it harder for the hybrid proxy.

if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*RollingDeploymentStrategyParams))(in)
}
SetDefaults_RollingDeploymentStrategyParams(in)
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't think any defaulting was supposed to happen in conversion now

Copy link
Contributor Author

Choose a reason for hiding this comment

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

liggitt 11 hours ago Member
I didn't think any defaulting was supposed to happen in conversion now

I'm uncertain about changing behavior. This is prexisting.

if obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides.Burst <= 0 {
obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides.Burst = 300
}
setDefault_ClientConnectionOverrides(obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides)
Copy link
Contributor

Choose a reason for hiding this comment

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

should this function be renamed so it is found by the defaulter generation?

@@ -67,7 +66,7 @@ func (l *ldapClientConfig) Connect() (ldap.Client, error) {
// Ensure tlsConfig specifies the server we're connecting to
if tlsConfig != nil && !tlsConfig.InsecureSkipVerify && len(tlsConfig.ServerName) == 0 {
// Add to a copy of the tlsConfig to avoid mutating the original
c := utilnet.CloneTLSConfig(tlsConfig)
c := tlsConfig.Clone()
Copy link
Contributor

Choose a reason for hiding this comment

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

are you switching to go1.8 in this PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

nm, I see the build update commit

@@ -67,12 +67,12 @@ func (strategy) ValidateUpdate(ctx apirequest.Context, obj, old runtime.Object)
}

// GetAttrs returns labels and fields of a given object for filtering purposes
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

pls document the bool.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

pls document the bool.

My post-rebase list has us rethinking our lives after manually updating 50 or identical methods to match the kube ones (also done manually by clayton). Yay initializers

@@ -83,12 +83,12 @@ func (strategy) ValidateUpdate(ctx apirequest.Context, obj, old runtime.Object)
}

// GetAttrs returns labels and fields of a given object for filtering purposes
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

godoc for the bool

"github.com/golang/glog"

"github.com/emicklei/go-restful-swagger12"
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: no new line above

_ "github.com/openshift/origin/pkg/quota/admission/runonceduration"
_ "github.com/openshift/origin/pkg/scheduler/admission/podnodeconstraints"
_ "github.com/openshift/origin/pkg/security/admission"
_ "k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we call NewAdmissionOptions to register the ns lifecycle plugin? There is also RegisterAllAdmissionPlugins in k8s.io/apiserver.

@deads2k
Copy link
Contributor Author

deads2k commented Jul 10, 2017

Now with working compilation.

@danwinship @dcbw ptal at fix/followup: DANW: sdn types no longer match. I have removed the SDN to keep moving forward. Can you try to reconcile the old and new interfaces? It's more in-depth than my knowledge goes.

@DirectXMan12 ptal at separate: SROSS: DISABLE UNIDLER. To move past #15101, I've completely disabled the unidler. Same request for a commit that reconciles old and and new.

@bparees new commit for you to review: separate: BPAREES: directly depend on the scc admission plugin

sccAdmission := sccadmission.NewConstraint()
sccAdmission.SetSecurityInformers(ctx.SecurityInformers)
sccAdmission.SetInternalKubeClientSet(ctx.ClientBuilder.KubeInternalClientOrDie(bootstrappolicy.InfraBuildControllerServiceAccountName))
if err := sccAdmission.Validate(); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

looks like this resolves #14909 ?

Copy link
Contributor

Choose a reason for hiding this comment

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

wait nevermind.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

looks like this resolves #14909 ?

No, this just makes the hack fail closer to compile time instead of a random failure at runtime.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok back to my original statement. looks like it resolves #14909.

lgtm.

@deads2k
Copy link
Contributor Author

deads2k commented Jul 10, 2017

Now with a running server! Also, don't tell @smarterclayton that I just had to bump that 10 second timeout because my all in one didn't start.....

@@ -139,7 +139,7 @@ func (o *BuildHookOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, ar
o.Cmd = cmd

mapper, typer := f.Object()
o.Builder = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
o.Builder = resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
Copy link
Contributor

Choose a reason for hiding this comment

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

hm, I believe the NewBuilder func added to the factory_builder should be in kube 1.7.

Any reason why we are still using resource.NewBuilder?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any reason why we are still using resource.NewBuilder?

It's a rebase and smaller changes are easier. Not all the methods have access to the factory.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@juanvallejo you're in the list here: #14647

Copy link
Contributor

Choose a reason for hiding this comment

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

you're in the list here: #14647

ack

@@ -25,7 +25,7 @@ func ImportObjects(f *clientcmd.Factory, ns, location string) error {
return err
}
glog.V(8).Infof("Importing data:\n%s\n", string(data))
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
Copy link
Contributor

Choose a reason for hiding this comment

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

Same question as 7a9f25d#r126534856

return nil, err
}
// Resolve cmd flags to add any user overrides
if err := cmdflags.Resolve(options.ProxyArguments, proxyOptions.AddFlags); len(err) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did this get moved to the start of the function? The goal is that options.ProxyArguments is supposed to override the defaults that get set here. In particular, you're supposed to be able to add:

proxyArguments:
  proxy-mode: ["userspace"]

to node-config.yaml to override the default value of proxyconfig.Mode that gets set below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Eventually we want to enter with the config, not the options. Not all the overrides being expressed will have args. I'll see if I can bring the remaining ones back into options.

@@ -476,8 +476,6 @@ func (c *NodeConfig) RunProxy() {
endpointsConfig.RegisterEventHandler(endpointsHandler)
go endpointsConfig.Run(utilwait.NeverStop)

recorder.Eventf(c.ProxyConfig.NodeRef, kapi.EventTypeNormal, "Starting", "Starting kube-proxy.")
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't look like anything would have ever modified c.ProxyConfig.NodeRef after it was created in the old code. So you could just move its creation to here and do

nodeRef := &kclientv1.ObjectReference{
        Kind:      "Node",
        Name:      hostname,
        UID:       ktypes.UID(hostname),
        Namespace: "",
}
recorder.Eventf(nodeRef, kapi.EventTypeNormal, "Starting", "Starting kube-proxy.")

(based on the current NodeRef definition in kubernetes/cmd/kube-proxy/app/server.go)

@danwinship
Copy link
Contributor

@deads2k revert 7ab20cb fix/followup: DANW: sdn types no longer match and the pkg/sdn/plugin/proxy.go part of c61da76 separate: DANW: endpointsconfighandler changes and grab danwinship@3b64be7

@openshift-bot
Copy link
Contributor

Evaluated for origin test up to fe8b4e7

"plugin",
"resize",
"rollingupdate",
"run-container",
Copy link
Contributor

Choose a reason for hiding this comment

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

run-container is deprecated. why does it suddenly show up?

Copy link
Contributor

Choose a reason for hiding this comment

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

all of these are deprecated in fact.

Copy link
Contributor

Choose a reason for hiding this comment

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

post-rebase todo exists.

@@ -59,7 +68,7 @@ kubectlLoop:
continue
}

t.Errorf("missing %q in oc", kubecmd.Name())
t.Errorf("missing %q,", kubecmd.Name())
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: comma?

return fmt.Errorf("invalid --registry-url flag: %v", err)
}
// golang validation tighten and our code actually expects this to be scheme-less
// TODO figure out how to validate
Copy link
Contributor

@sttts sttts Jul 17, 2017

Choose a reason for hiding this comment

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

added to post-rebase todos if we leave this in.

@@ -719,6 +719,13 @@ func startControllers(options configapi.MasterConfig, allocationController origi
return err
}

// the service account passed for the recyclable volume plugins needs to exist. We want to do this via the init function, but its a kube init function
// for the rebase, create that service account here
// TODO make this a lot cleaner
Copy link
Contributor

Choose a reason for hiding this comment

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

added to post-rebase todos. ugly, but ok for now.

Expansions: map[string][]schema.GroupResource{
"all": legacyOpenshiftUserResources,
},
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Comparing with the upstream variant, lgtm

@sttts
Copy link
Contributor

sttts commented Jul 17, 2017

These commits look ok:

  • "separate: defer adding new commands until after the rebase", post-rebase todo exists
  • "disable registry url validation in prune", post-rebase todo exists
  • "squash to wiring: create SA needed for recycling", ugly, post-rebase todo exists
  • "squash to api server wiring", lgtm
  • "separate: client factory fitting", lgtm

return true, nil
}

type PersistentVolumeAttachDetachControllerConfig struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

this was dead code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

persistentvolumecontroller.ControllerParameters{
KubeClient: ctx.ClientBuilder.ClientOrDie("persistent-volume-binder"),
SyncPeriod: ctx.Options.PVClaimBinderSyncPeriod.Duration,
AlphaProvisioner: alphaProvisioner,
Copy link
Contributor

Choose a reason for hiding this comment

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

lgtm comparing with upstream's kubernetes/kubernetes#44090

@sttts
Copy link
Contributor

sttts commented Jul 17, 2017

  • "separate with controllers: storage controller changes". lgtm

@openshift-bot
Copy link
Contributor

continuous-integration/openshift-jenkins/test FAILURE (https://ci.openshift.redhat.com/jenkins/job/test_pull_request_origin/3193/) (Base Commit: 22888b2) (PR Branch Commit: fe8b4e7)

@deads2k
Copy link
Contributor Author

deads2k commented Jul 17, 2017

@stevekuznetsov can you help me get my e2e disablement working?

I want to disable these:

Extended.[k8s.io] StatefulSet [k8s.io] Basic StatefulSet functionality [StatefulSetBasic] should adopt matching orphans and release non-matching pods
Extended.[k8s.io] StatefulSet [k8s.io] Basic StatefulSet functionality [StatefulSetBasic] should not deadlock when a pod's predecessor fails

@deads2k
Copy link
Contributor Author

deads2k commented Jul 17, 2017

"separate with controllers: storage controller changes". lgtm

Alright, I think that's fully reviewed. I've rebased and the pull against master is here: #15234

@deads2k
Copy link
Contributor Author

deads2k commented Jul 17, 2017

Just the stateful set errors. fully reviewed. I'm moving #15234

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.