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

feat: Implement the GetHelmRelease endpoint #1534

Merged
merged 4 commits into from Mar 2, 2022

Conversation

yitsushi
Copy link
Contributor

@yitsushi yitsushi commented Feb 25, 2022

Add endpoint to get a single HelmRelease.

Additional changes:

  • Moved ListHelmReleases and GetHelmRelease endpoint definitions into
    their own file, to get a better separation (helm.go).
  • Moved the tests for ListHelmReleases and GetHelmRelease endpoints into
    the corresponding test file (helm_test.go).

For Kustomization, the getInventory function is under types, but to
get the inventory for a HelmRelease, we need a lot of extra queries from
k8s and we already have a lot of helper functions in server.

Refactored tests to use server_test module instead of server.

Benefits:

  • If a branch is not covered with test, it might be deleted, or some
    cases are not tested.
  • We test the same interface as a consumer will use.
  • We can't "reuse" private functions for testing, that way we can see
    during testing if we have to publish a function or not.

Closes #1498

Add endpoint to get a single HelmRelease.

Additional changes:

* Moved `ListHelmReleases` and `GetHelmRelease` endpoint definitions into
  their own file, to get a better separation (`helm.go`).
* Moved the tests for `ListHelmReleases` and `GetHelmRelease` endpoints into
  the corresponding test file (`helm_test.go`).

Closes #1498
Copy link
Contributor

@jpellizzari jpellizzari left a comment

Choose a reason for hiding this comment

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

@yitsushi I would have expected to see some work in types/helmrelease.go to get the inventory stuff working. Is that already taken care of?

@@ -57,25 +56,3 @@ func (cs *coreServer) GetKustomization(ctx context.Context, msg *pb.GetKustomiza

return &pb.GetKustomizationResponse{Kustomization: res}, nil
}

func (cs *coreServer) ListHelmReleases(ctx context.Context, msg *pb.ListHelmReleasesRequest) (*pb.ListHelmReleasesResponse, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Moving this to a new file makes the naming inconsistent. If we are really going for that level of separation, we also need to rename automations to kustomizations, since that is all it contains 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.

I would like to split them up, later on much easier to find and change without worrying about a conflict between PRs. I'll rename the file to helm_release and automations to kustomization

For Kustomization, the getInventory function is under `types`, but to
get the inventory for a `HelmRelease`, we need a lot of extra queries from
k8s and we already have a lot of helper functions in `server`.
@yitsushi
Copy link
Contributor Author

I would be happy to test the inventory part, but I have no idea how to even approach that part, with creating a secret, and create encoded stuff with that secret in there. If required, I'll spend more time and figure it out.

Comment on lines 132 to 134
entry.GetAPIVersion()

idstr := strings.Join([]string{entry.GetAPIVersion(), entry.GetKind()}, "_")
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you know why we call entry.GetAPIVersion here and then again on 134? I can see we are doing it somewhere else in the code, so am curious what repeating but not keeping the value gives us.

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 have no idea, and because I have no idea, I just used the same logic XD

Copy link
Contributor

Choose a reason for hiding this comment

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

does it hurt anything if you remove the first 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.

while testing it does not hurt, but I don't know if it does with real k8s objects coming from a real k8s cluster.

Copy link
Contributor

Choose a reason for hiding this comment

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

ack, makes sense, would be good to prove and remove at somepoint

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed... Why?

entry.GetAPIVersion()

idstr := strings.Join([]string{entry.GetAPIVersion(), entry.GetKind()}, "_")

The function call sequence is:

  1. entry.GetAPIVersion()
  2. entry.GetKind()
  3. strings.Join()

With that extra call the difference is an extra call only:

  1. entry.GetAPIVersion()
  2. entry.GetAPIVersion()
  3. entry.GetKind()
  4. strings.Join()

I see only one case when it can have any effects, if the underlying code is far from optimal and has an internal counter (how many times it was called) or something, and it does not make sense.


var gvk []*pb.GroupVersionKind

found := map[string]bool{}
Copy link
Contributor

Choose a reason for hiding this comment

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

we could probs use map[string]struct{} here if we care about speed and memory, but bool reads better so happy either way.

@@ -0,0 +1,109 @@
package server
Copy link
Contributor

Choose a reason for hiding this comment

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

can we make this server_test? we are testing an exposed interface, so we can test against it from the outside

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'm 100% on the that side (blackbox testing), but the rest of the code follows this logic (whitebox testing), so I did the same.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeh. i would be good to move over while we are starting new so we don;t blur lines

Copy link
Contributor Author

@yitsushi yitsushi Feb 28, 2022

Choose a reason for hiding this comment

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

Did a few pokes on it, all the tests are using the same functions (and global variable 😞 ), so I moved everything and now it's all server_test

g.Expect(res.HelmReleases[0].Name).To(Equal(appName))
}

func TestGetHelmRelease(t *testing.T) {
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 going to test any of the getHelmReleaseInventory bits? it feels important to us that we are populating that bit of the returned value correct

Copy link
Contributor

Choose a reason for hiding this comment

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

ah just literally saw your comment on that 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

@yitsushi Here is how I had to test statuses:

g.Expect(k.Status().Patch(ctx, kust, client.Apply, opt...)).To(Succeed())

Note that this is the second .Patch, after creating the record initially with the first .Patch (instead of .Create).

Copy link
Contributor Author

@yitsushi yitsushi Feb 28, 2022

Choose a reason for hiding this comment

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

My issue with testing that function... well I have to create a full secret + store + data + "i don't know what else", because unlike kustomization, to get helm inventory, we query the api to get a helm secret, get release from the secret storage, decode + unzip (if gzipped), and finally read object from the storage. or something like that... so that would require a huge bootstrapping. I'll try it, because I would like to test it.

black-box testing environment and we test what the consumer will use.

Benefits:
* If a branch is not covered with test, it might be deleted, or some
  cases are not tested.
* We test the same interface as a consumer will use.
* We can't "reuse" private functions for testing, that way we can see
  during testing if we have to publish a function or not.
Copy link
Contributor

@jpellizzari jpellizzari left a comment

Choose a reason for hiding this comment

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

LGTM 👍. Up to you if you want to add more test coverage around Invnentory.

@@ -1,11 +1,12 @@
package server
package server_test
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the opposite of how our team has been structuring packages to this point. I don't really care either way, but we need to decide as an eng org how we want to do this.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's probably a per-codebase decision. It's not the end of the world to white box test some layers, but it is not great practice when it comes to external facing contracts (which these are). Given we are tidying things, now feels like a good time to clean this up.

g.Expect(res.HelmReleases[0].Name).To(Equal(appName))
}

func TestGetHelmRelease(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@yitsushi Here is how I had to test statuses:

g.Expect(k.Status().Patch(ctx, kust, client.Apply, opt...)).To(Succeed())

Note that this is the second .Patch, after creating the record initially with the first .Patch (instead of .Create).

@yitsushi yitsushi merged commit 657e092 into v2 Mar 2, 2022
@ozamosi ozamosi deleted the 1498-get-helm-release-endpoint branch May 12, 2022 17:42
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.

None yet

3 participants