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

Separate the humio client from cluster methods, move the kubernetes-related methods to a separate package and add initial unit tests #4

Merged
merged 8 commits into from
Mar 12, 2020

Conversation

jswoods
Copy link
Contributor

@jswoods jswoods commented Mar 10, 2020

No description provided.

kubernetes-related methods to a separate package and add initial unit
tests
@jswoods
Copy link
Contributor Author

jswoods commented Mar 10, 2020

There's not a ton here yet, and this is wip, but the important files are pkg/humio/client.go, pkg/humio/client_test.go, pkg/humio/cluster.go and pkg/humio/cluster_test.go. This is how I was thinking we lay out the client so it is mockable when we write the reconcile tests (as well as any unit tests for the cluster controller). I'd like to also do a similar pattern with the k8s client. Let me know if you had different ideas or if this aligns with what you were thinking as well.

@SaaldjorMike
Copy link
Member

Looks good to me, but I have basically have no experience with writing tests in the Go world (yet). My main thoughts are:

  • We should probably at some point write tests within our API package in our CLI repo, like you started here: Add basic integration tests cli#9. I assume there will be some tests that are better suited to be part of the CLI project rather than within our operator project. In the CLI project, It would also be super cool if we could autogenerate the Go types instead of us having to manually maintain them. Not sure if we have a good approach to do this.
  • Going forward we probably want to have a way to support/define what Humio versions are supported by the operator. I'm thinking that Humio's GraphQL/REST API may change over time, and at some point we probably need to figure out how to support this going forward. For now, it is probably not super important though.
  • We could probably set up github-actions to run the tests on PR's now that the first couple of tests have been added.
  • Do we want to use a mocking framework at some point? Not sure if it would make sense for us to use one right away? As someone that have yet to dig into the whole world of writing tests in Go, I thought I'd ask as I've stumbled upon a ton of places where such frameworks are used.

@jswoods
Copy link
Contributor Author

jswoods commented Mar 10, 2020

Good points. I agree on all fronts.

I have not done a great job about prioritizing the cli tests.. I spent some time adding json outputs so we can use those to run the integration tests but there is still quite a bit of work left.

I had not thought about the different humio versions. This is a really good point and while it may not be needed immediately, we likely will want this. A project that comes to mind where they seem to do a good job with this is the cluster autoscaler, see https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#releases. They have a table that maps the k8s version with the CA version.

+1 on github actions

For the mocking framework, I think may be uses for this where it's hard or a pain to write our own mocks (for example, calling dependent libraries). For the situations where we only have a handfull of calls that we need to mock, I like the idea of using interfaces as it almost forces good composition. I don't always have the discipline of writing nicely composed code when given the luxury of stubs :) Also I think calling methods in tests exactly how they would be called in the real code helps a lot with documenting how they methods are intended to be used.

@jswoods jswoods marked this pull request as ready for review March 12, 2020 00:43
@jswoods
Copy link
Contributor Author

jswoods commented Mar 12, 2020

@SaaldjorMike I think this should be reviewed/merged now before I get too carried away :). I have been slowly pulling in code from the POC and there is now a successful reconcile test that creates humio pods similar to how it was done in the POC. There are separate unit tests for the humio code as well. There are no examples yet of using the mock humio client inside the reconcile test, but I think that can come in the round of changes as we add more to the reconciliation.

}
}

func constructEnvVarList(nodeID int) *[]corev1.EnvVar {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we'll want to refactor this in an upcoming PR so we can merge env vars that are set in the spec (e.g. for things like saml, etc)

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good to me!

Comment on lines +301 to +322
func generateStoragePartitionSchemeCandidate(storageNodeIDs []int, partitionCount, targetReplication int) ([]humioapi.StoragePartitionInput, error) {
replicas := targetReplication
if targetReplication > len(storageNodeIDs) {
replicas = len(storageNodeIDs)
}
if replicas == 0 {
return nil, fmt.Errorf("not possible to use replication factor 0")
}

var ps []humioapi.StoragePartitionInput

for p := 0; p < partitionCount; p++ {
var nodeIds []graphql.Int
for r := 0; r < replicas; r++ {
idx := (p + r) % len(storageNodeIDs)
nodeIds = append(nodeIds, graphql.Int(storageNodeIDs[idx]))
}
ps = append(ps, humioapi.StoragePartitionInput{ID: graphql.Int(p), NodeIDs: nodeIds})
}

return ps, nil
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not 100% convinced that this functionality (as well as generating ingest partition scheme) should be within the operator - at least not in the long run. We hear customers now and then that are not super happy with the rather manual way of adjusting this right now, so we can probably move it to api package in the humioctl project at some point and direct customers (that does not use k8s) towards humioctl to help them spread partition across nodes. That being said, in order to really generate a good candidate for assigning partitions you'd need some rack/availabilityzone information for each of the Humio nodes. For customers running Humio outside k8s, I'm thinking there might be two ways for us to generate a good scheme.

  1. Ensure Humio knows about the rack/AZ and can generate this scheme itself. Maybe just have a "generate and assign partitions" button from within the UI?
  2. If Humio itself is not aware of rack/AZ: add method to Go API that requires you to specify which nodes are in which rack/AZ's.

Option 1 would probably be the best one in the long run, but I also see cases where it would make sense to use the Go API (in projects like this operator) and/or humioctl to generate and assign partitions to nodes.

Without rack/AZ information baked into Humio, I'm thinking that a subcommand of the CLI would be nice to also have where you're required to specify rack/AZ information. If we do decide to allow customers to specify rack/AZ directly in Humio's configurations somehow, we could probably relax this and only require customers to specify rack/AZ if Humio doesn't already have the information.

For now though, I'm good with just going with this. I just thought I'd at least share my thoughts 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Totally agree here. Would you rather start with putting zone awareness in the operator and then migrate it to the cli, or would you want to start with adding it to the cli first? I don't want to generate too much extra work with migrating it but also want to avoid getting too off-track of the operator work.

For getting the actual zones, we have the init container pattern used in the helm chart to pull the zone from the host where the pod is scheduled. I think we can probably reuse that here.

I filed #6 so feel free to put your opinion in there.

Copy link
Member

@SaaldjorMike SaaldjorMike left a comment

Choose a reason for hiding this comment

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

LGTM! Feel free to merge it in whenever you're ready to do so.

Comment on lines +232 to +241
Volumes: []corev1.Volume{
{
Name: "humio-data",
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: fmt.Sprintf("%s-core-%d", hc.Name, nodeID),
},
},
},
},
Copy link
Member

Choose a reason for hiding this comment

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

What do we want to do regarding Humio's data volume? We talked about focussing on our own use-case with ephemeral storage using hostPath, but maybe we'd also want a flag to maybe run with emptyDir when e.g. running it locally in kind/Minikube?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. I filed #5.

Co-Authored-By: Mike Rostermund <mike@humio.com>
@jswoods jswoods merged commit f0c0dce into master Mar 12, 2020
@jswoods jswoods deleted the jestin/unit-tests branch March 12, 2020 16:37
SaaldjorMike added a commit that referenced this pull request Oct 13, 2021
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.

2 participants