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

Adding statefulset functionality #44

Merged
merged 1 commit into from
Apr 24, 2019
Merged

Conversation

SteveKMin
Copy link
Contributor

@SteveKMin SteveKMin commented Apr 4, 2019

This is my first pass at adding statefulsets to wave. Most of the code mirrors the deployment controller, including the tests.

Some tests in the core pkg run against a deployment object, I was not sure if I should create another with a stateful set object.

@pusher-ci
Copy link

Hi @SteveKMin. Thanks for your PR.

I'm waiting for a pusher 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.

@JoelSpeed JoelSpeed requested a review from a team April 4, 2019 16:08
@JoelSpeed
Copy link
Collaborator

I've had an initial scan over this and it looks great! 😄
I'm going to check it out tomorrow and have a proper read through and will get back to you once I've done so.

/ok-to-test

Copy link
Collaborator

@JoelSpeed JoelSpeed left a comment

Choose a reason for hiding this comment

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

@SteveKMin Looks mostly good, got a few changes to request though mainly around consistency with the rest of the codebase and a hint on fixing the tests 😄

Let me know if you have any questions

@@ -0,0 +1,361 @@
package statefulset
Copy link
Collaborator

Choose a reason for hiding this comment

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

This file is misnamed, should be statefulset_controller_test.go.

Could you also please add the license header to this file.

var c client.Client
var m utils.Matcher

var sts *appsv1.StatefulSet
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd prefer if this variable were called statefulset rather than sts, then it is consistent with the deployment controller 😃

- create
- update
- patch
- delete
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should have a new line at the end, can you try running make manifests and committing the result?


func TestMain(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Wave Controller Suite")
Copy link
Collaborator

Choose a reason for hiding this comment

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

The tests won't work right now as we recently changed this line to include JUnit reporters

Suggested change
RunSpecs(t, "Wave Controller Suite")
RunSpecsWithDefaultAndCustomReporters(t, "Wave Controller Suite", reporters.Reporters())

You'll also need to import "github.com/pusher/wave/test/reporters"

@@ -82,3 +82,23 @@ func (d *deployment) SetPodTemplate(template *corev1.PodTemplateSpec) {
func (d *deployment) DeepCopy() podController {
return &deployment{d.Deployment.DeepCopy()}
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be nice to have some comments through the podController stuff that's been added recently but we don't have any right now so can leave them til later

@SteveKMin
Copy link
Contributor Author

SteveKMin commented Apr 9, 2019

I think I've applied the changes you've requested. I did not comment podcontroller because I could not figure out a good wording for describing it 🙁.

I ran the make manifest command, but for whatever reason, I need to replace every instance of $(GO) with go and likewise for the other commands in the makefile to run locally.

Edit: A coworker has helped me resolve my local environment, I can test locally now.

Edit2: I see I will have to work on some of the tests failing as they assume deployment objects. I will work on those now.

Edit3:
I'm getting some errors that I'm not quite sure how to solve. I'm guessing it has something to do with the testing suite and how the deployment/statefulset objects are being handled?
Getting this error once

    <[]v1.OwnerReference | len:1, cap:1>: [
        {
            APIVersion: "apps/v1",
            Kind: "Deployment",
            Name: "example",
            UID: "decd8fb1-5ae2-11e9-830a-0a580a101331",
            Controller: false,
            BlockOwnerDeletion: true,
        },
    ]
to contain element matching
    <v1.OwnerReference>: {
        APIVersion: "apps/v1",
        Kind: "StatefulSet",
        Name: "example",
        UID: "decd8fb1-5ae2-11e9-830a-0a580a101331",
        Controller: false,
        BlockOwnerDeletion: true,
    }

I'm getting this error case for 4 of the tests

object is being deleted: statefulsets.apps "example" already exists

@JoelSpeed
Copy link
Collaborator

JoelSpeed commented Apr 10, 2019

For your OwnerReferences problem, I think this is because the code here does not handle the different types of objects https://github.com/pusher/wave/blob/819439c729036887a3da70c683307b387bfe3651/pkg/core/owner_references.go#L122-L134

Could try adding a switch on the type to set the right Kind (maybe even inside kindOf if you feel like it)?

// kindOf returns the Kind of the given object as a string
func kindOf(obj Object) string {
	switch obj.(type) {
	case *corev1.ConfigMap:
		return "ConfigMap"
	case *corev1.Secret:
		return "Secret"
	case *deployment:
		return "Deployment"
	case *statefulset:
		return "StatefulSet"
	default:
		return "Unknown"
	}
}

I quickly tested that change and it makes the rest of the tests pass too, which is interesting and kind of sad 😢

@SteveKMin
Copy link
Contributor Author

SteveKMin commented Apr 10, 2019

Ah that makes sense. I've done a 2 case switch statement to handle the getOwnerReference(obj podController). I wasn't sure to make it an if or a switch, will there be more PodController objects?

In addition, I'm seeing inconsistent test behavior now. Locally I was getting different test failures every time, I was thinking it was just an error with my environment. Here a couple of the different failures I saw (all of these are from different runs on Go 1.12).

        Expected
            <[]v1.OwnerReference | len:1, cap:1>: [
                {
                    APIVersion: "apps/v1",
                    Kind: "Deployment",
                    Name: "example",
                    UID: "850a2f40-5ba2-11e9-9120-88e9fe7a0a04",
                    Controller: false,
                    BlockOwnerDeletion: true,
                },
            ]
        not to contain element matching
            <v1.OwnerReference>: {
                APIVersion: "apps/v1",
                Kind: "Deployment",
                Name: "example",
                UID: "850a2f40-5ba2-11e9-9120-88e9fe7a0a04",
                Controller: false,
                BlockOwnerDeletion: true,
            }
        Expected success, but got an error:
            <*errors.StatusError | 0xc0003f2d80>: {
                ErrStatus: {
                    TypeMeta: {Kind: "", APIVersion: ""},
                    ListMeta: {SelfLink: "", ResourceVersion: "", Continue: ""},
                    Status: "Failure",
                    Message: "Operation cannot be fulfilled on deployments.apps \"example\": the object has been modified; please apply your changes to the latest version and try again",
                    Reason: "Conflict",
                    Details: {Name: "example", Group: "apps", Kind: "deployments", UID: "", Causes: nil, RetryAfterSeconds: 0},
                    Code: 409,
                },
            }
            Operation cannot be fulfilled on deployments.apps "example": the object has been modified; please apply your changes to the latest version and try again

Copy link
Collaborator

@JoelSpeed JoelSpeed left a comment

Choose a reason for hiding this comment

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

The testing inconsistencies are interesting. The latter is a sporadic thing that happens every so often where the CPU is a bit too slow for the test timeouts, I haven't worked out a good way to fix that yet apart from --flake-attempts as a flag to ginkgo.

The former doesn't seem to happen on my machine, but I'll try running the tests a few times and see if I can find anything, there are a few oddities in these tests at present, they need a little work

case "Deployment":
return metav1.OwnerReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any reason not to just substitute the string here for kindOf(obj), then this switch would be unnecessary right?

Suggested change
Kind: "Deployment",
Kind: kindOf(obj),

@@ -167,12 +167,16 @@ func WithOwnerReferences(matcher gtypes.GomegaMatcher) gtypes.GomegaMatcher {
}, matcher)
}

// WithPodTemplateAnnotations returns the deployments PodTemplate's annotations
// WithPodTemplateAnnotations returns the PodTemplate's annotations
func WithPodTemplateAnnotations(matcher gtypes.GomegaMatcher) gtypes.GomegaMatcher {
return gomega.WithTransform(func(obj Object) map[string]string {
dep, ok := obj.(*appsv1.Deployment)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could this not cast to the podController interface? Would get rid of the need for this double if-else?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Or better still just make the anonymous function accept a podController instead of Object and then the tests will panic by themselves if the incorrect interface is passed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

podController is defined as a private interface. Do you want it to be public so it can be used in this way? We may have to refactor the tests to send a pod controller instead of deployment and statefulset types.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I think that would probably be better to do. Let's make PodController public and I think the tests should just work anyway? As in I think we are already passing PodControllers in in most places. Lets give it a go and see what happens?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you thinking something like this?

func WithPodTemplateAnnotations(matcher gtypes.GomegaMatcher) gtypes.GomegaMatcher {
	return gomega.WithTransform(func(obj core.PodController) map[string]string {
		return obj.GetPodTemplate().GetAnnotations()
	}, matcher)
}

If so

Error: Transform function expects 'core.PodController' but we have '*v1.Deployment'

happens on about ~20 times when the eventually function uses utils.WithPodTemplateAnnotations(HaveKey(core.ConfigHashAnnotation))

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, I've had a deeper look at this, definitely not worth trying to use podController here, it's going to cause so many issues

Instead can we make it a switch as below? I think it will look cleaner, WDYT?

return gomega.WithTransform(func(obj Object) map[string]string {
		switch obj.(type) {
		case *appsv1.Deployment:
			return obj.(*appsv1.Deployment).Spec.Template.GetAnnotations()
		case *appsv1.StatefulSet:
			return obj.(*appsv1.StatefulSet).Spec.Template.GetAnnotations()
		default:
			panic("unknown pod template type")
		}
	}, matcher)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, thats much easier to read. I've updated the PR.

JoelSpeed
JoelSpeed previously approved these changes Apr 23, 2019
Copy link
Collaborator

@JoelSpeed JoelSpeed left a comment

Choose a reason for hiding this comment

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

I'm happy now with these changes, thanks for all your work on this.

Just going to retest the 1.11 suite as it failed for some reason and then I'll merge
/test 1.11

Would you like to rebase and squash the commits at all before we merge? Otherwise I'll just squash it as I merge

@JoelSpeed
Copy link
Collaborator

/retest

3 similar comments
@JoelSpeed
Copy link
Collaborator

/retest

@JoelSpeed
Copy link
Collaborator

/retest

@JoelSpeed
Copy link
Collaborator

/retest

@JoelSpeed
Copy link
Collaborator

/retest

@pusher-ci
Copy link

@SteveKMin: The following tests failed, say /retest to rerun them all:

Test name Commit Details Rerun command
pull-wave-test-ginkgo a8b8799 link /test ginkgo
pull-wave-test-1.11 8fbaa64 link /test 1.11

Full PR test history

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. I understand the commands that are listed here.

@JoelSpeed
Copy link
Collaborator

There is something not right with these tests. The Deployment controller tests don't flake in the same way as the StatefulSet ones. I'm going to spend some time this morning investigating this to see if I can work out why

@JoelSpeed
Copy link
Collaborator

/build docker

I'm working on the flaking tests and am thinking it's probably best to follow up with a separate PR for fixing those, for the meantime I'm going to build a docker image and manually test this on one of our clusters

@JoelSpeed
Copy link
Collaborator

/build docker

Copy link
Collaborator

@JoelSpeed JoelSpeed left a comment

Choose a reason for hiding this comment

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

Im happy enough with this that it's working, will get it merged!

@JoelSpeed JoelSpeed merged commit b03cb69 into wave-k8s:master Apr 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants