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

Fix service update which would changed the nodeport #2284

Merged
merged 14 commits into from
May 7, 2020
1 change: 1 addition & 0 deletions pkg/manager/member/tidb_member_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ func (tmm *tidbMemberManager) syncTiDBService(tc *v1alpha1.TidbCluster) error {
return err
}
oldSvc := oldSvcTmp.DeepCopy()
util.RemainNodeport(newSvc, oldSvc)

equal, err := controller.ServiceEqual(newSvc, oldSvc)
if err != nil {
Expand Down
16 changes: 16 additions & 0 deletions pkg/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,19 @@ func IsOwnedByTidbCluster(obj metav1.Object) (bool, *metav1.OwnerReference) {
}
return ref.Kind == v1alpha1.TiDBClusterKind && gv.Group == v1alpha1.SchemeGroupVersion.Group, ref
}

// RemainNodeport is to make service nodeport unchanged during each reconciliation
func RemainNodeport(desiredSvc, existedSvc *corev1.Service) {
if desiredSvc.Spec.Type != corev1.ServiceTypeNodePort && desiredSvc.Spec.Type != corev1.ServiceTypeLoadBalancer {
return
}
for id, dport := range desiredSvc.Spec.Ports {
for _, eport := range existedSvc.Spec.Ports {
if dport.Port == eport.Port && dport.Protocol == eport.Protocol {
dport.NodePort = eport.NodePort
desiredSvc.Spec.Ports[id] = dport
break
}
}
}
}
86 changes: 86 additions & 0 deletions tests/e2e/tidbcluster/tidbcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,92 @@ var _ = ginkgo.Describe("[tidb-operator] TiDBCluster", func() {
})

framework.ExpectNoError(err)

// Create TidbCluster with NodePort to check whether node port would change
nodeTc := fixture.GetTidbCluster(ns, "nodeport", utilimage.TiDBV3Version)
nodeTc.Spec.PD.Replicas = 1
nodeTc.Spec.TiKV.Replicas = 1
nodeTc.Spec.TiDB.Replicas = 1
nodeTc.Spec.TiDB.Service = &v1alpha1.TiDBServiceSpec{
ServiceSpec: v1alpha1.ServiceSpec{
Type: corev1.ServiceTypeNodePort,
},
}
err = genericCli.Create(context.TODO(), nodeTc)
framework.ExpectNoError(err, "Expected TiDB cluster created")
err = oa.WaitForTidbClusterReady(tc, 30*time.Minute, 15*time.Second)
framework.ExpectNoError(err, "Expected TiDB cluster ready")

var s *corev1.Service
err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) {
s, err = c.CoreV1().Services(ns).Get("nodeport-tidb", metav1.GetOptions{})
if err != nil {
klog.Errorf(err.Error())
Copy link
Contributor

Choose a reason for hiding this comment

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

better to use framework.Logf which writes to ginkgo writer and the logs can be printed into ginkgo test report if failed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated.

return false, nil
}
if s.Spec.Type != corev1.ServiceTypeNodePort {
return false, fmt.Errorf("nodePort tidbcluster tidb service type isn't NodePort")
}
return true, nil
})
framework.ExpectNoError(err)
ports := s.Spec.Ports

// check node port unchanged for 5mins
Copy link
Contributor

Choose a reason for hiding this comment

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

Update some attributes of the service and then check no change for nodeport?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

1 minute IMO is enough because our reconciliation period is 30 seconds.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

s, err := c.CoreV1().Services(ns).Get("nodeport-tidb", metav1.GetOptions{})
if err != nil {
klog.Errorf(err.Error())
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

Copy link
Contributor

Choose a reason for hiding this comment

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

actually, you can return these errors in this wait function. this will make this function shorter and errors will be printed if the test fails because what you expect is Timeout error.

return true, nil
}
if s.Spec.Type != corev1.ServiceTypeNodePort {
klog.Error("nodePort tidbcluster tidb service type isn't NodePort")
return true, nil
}
for _, dport := range s.Spec.Ports {
for _, eport := range ports {
if dport.Port == eport.Port && dport.NodePort != eport.NodePort {
klog.Error("nodePort tidbcluster tidb service NodePort changed")
return true, nil
}
}
}
return false, nil
})
framework.ExpectError(err)
Copy link
Contributor

Choose a reason for hiding this comment

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

framework.ExpectEqual(err, wait.ErrWaitTimeout)

Copy link
Contributor

Choose a reason for hiding this comment

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

actually, you can return these errors in this wait function. this will make this function shorter and errors will be printed if the test fails because what you expect is Timeout error.

klog.Info("nodePort tidbcluster tidb service NodePort haven't changed")

tc, err = cli.PingcapV1alpha1().TidbClusters(ns).Get("nodeport", metav1.GetOptions{})
framework.ExpectNoError(err)
tc.Spec.TiDB.Service.Annotations = map[string]string{
"foo": "bar",
}
_, err = cli.PingcapV1alpha1().TidbClusters(ns).Update(tc)
framework.ExpectNoError(err)
Copy link
Contributor

Choose a reason for hiding this comment

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

use previous nodeTC and controller.GuaranteedUpdate, e.g.

        err = controller.GuaranteedUpdate(genericCli, nodeTc, func() error {
            nodeTc.Spec.TiDB.Service.Annotations = map[string]string{
			    "foo": "bar",
    	    }  
            return nil
        }) 

controller.GuaranteedUpdate( can help resolve conflicts (status of TidbCluster objects are updated by controller frequently) and make our test stable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated.


err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) {
s, err = c.CoreV1().Services(ns).Get("nodeport-tidb", metav1.GetOptions{})
if err != nil {
return false, nil
}
if s.Annotations == nil {
return false, nil
}
v, ok := s.Annotations["foo"]
if !ok || v != "bar" {
return false, nil
}
for _, oport := range ports {
for _, eport := range s.Spec.Ports {
if oport.Port == eport.Port && oport.Protocol == eport.Protocol && oport.NodePort != eport.NodePort {
return false, fmt.Errorf("node port has been changed")
}
}
}
return true, nil
})
framework.ExpectNoError(err)
Copy link
Contributor

@cofyc cofyc Apr 26, 2020

Choose a reason for hiding this comment

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

you should wait for Timeout error to happen (NodePort not changed after the update in a few minutes). IMO you can reuse previous wait function. Testing the update of service succeeds or not is out of the scope of this test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated.

klog.Info("nodePort tidbcluster tidb service NodePort haven't changed after update")
})

updateStrategy := v1alpha1.ConfigUpdateStrategyInPlace
Expand Down