-
Notifications
You must be signed in to change notification settings - Fork 48
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
Add tests for custom number of fernet keys #492
Add tests for custom number of fernet keys #492
Conversation
Skipping CI for Draft Pull Request. |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: afaranha The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@@ -1109,6 +1110,112 @@ var _ = Describe("Keystone controller", func() { | |||
}) | |||
}) | |||
|
|||
When("When the fernet keys are created with fernetMaxActiveKeys as 3", func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both this test and the one below are pretty much similar, is there a way to reuse it?
(While waiting for an answer I'll try to figure it out, but it may take some time)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of the separate test bellow, maybe it would be better to test that when updating the keystone parameter from 3 -> 6 we see that the config and the secret got additional keys? Like have a nested when update keys from 3->6 it ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that I still don't know how to simulate a change on the spec.
I start with this one: DeferCleanup(th.DeleteInstance, CreateKeystoneAPI(keystoneAPIName, GetKeystoneAPISpec(3)))
But even if I call this again with a different value on the It(), it doesn't seem to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could do it like this
When("When the fernet keys are created", func() {
BeforeEach(func() {
DeferCleanup(
k8sClient.Delete, ctx, CreateKeystoneMessageBusSecret(namespace, "rabbitmq-secret"))
// with fernetMaxActiveKeys as 3
DeferCleanup(th.DeleteInstance, CreateKeystoneAPI(keystoneAPIName, GetKeystoneAPISpec(3)))
DeferCleanup(
k8sClient.Delete, ctx, CreateKeystoneAPISecret(namespace, SecretName))
DeferCleanup(infra.DeleteMemcached, infra.CreateMemcached(namespace, "memcached", memcachedSpec))
DeferCleanup(
mariadb.DeleteDBService,
mariadb.CreateDBService(
namespace,
GetKeystoneAPI(keystoneAPIName).Spec.DatabaseInstance,
corev1.ServiceSpec{
Ports: []corev1.ServicePort{{Port: 3306}},
},
),
)
mariadb.SimulateMariaDBAccountCompleted(keystoneAccountName)
mariadb.SimulateMariaDBDatabaseCompleted(keystoneDatabaseName)
infra.SimulateTransportURLReady(types.NamespacedName{
Name: fmt.Sprintf("%s-keystone-transport", keystoneAPIName.Name),
Namespace: namespace,
})
infra.SimulateMemcachedReady(types.NamespacedName{
Name: "memcached",
Namespace: namespace,
})
th.SimulateJobSuccess(dbSyncJobName)
th.SimulateJobSuccess(bootstrapJobName)
th.SimulateDeploymentReplicaReady(deploymentName)
})
It("creates 3 keys", func() {
secret := th.GetSecret(types.NamespacedName{Namespace: keystoneAPIName.Namespace, Name: "keystone"})
Expect(secret).ToNot(BeNil())
Eventually(func(g Gomega) {
Expect(maps.Keys(secret.Data)).To(ContainElements("FernetKeys0", "FernetKeys1", "FernetKeys2"))
Expect(maps.Keys(secret.Data)).ToNot(ContainElement("FernetKeys3"))
for i := 0; i < 3; i++ {
g.Expect(secret.Data["FernetKeys"+strconv.Itoa(i)]).NotTo(BeZero())
}
}, timeout, interval).Should(Succeed())
})
When("When the fernet keys get updated to 6", func() {
BeforeEach(func() {
keystone := GetKeystoneAPI(keystoneAPIName)
Expect(*keystone.Spec.FernetMaxActiveKeys).To(Equal(int32(3)))
keystone.Spec.FernetMaxActiveKeys = ptr.To(int32(6))
_, err := controllerutil.CreateOrPatch(
th.Ctx, th.K8sClient, keystone, func() error { return nil })
Expect(err).ToNot(HaveOccurred())
})
It("creates 6 keys", func() {
secret := th.GetSecret(types.NamespacedName{Namespace: keystoneAPIName.Namespace, Name: "keystone"})
Expect(secret).ToNot(BeNil())
Eventually(func(g Gomega) {
Expect(maps.Keys(secret.Data)).To(ContainElements("FernetKeys0", "FernetKeys1", "FernetKeys2", "FernetKeys3", "FernetKeys4", "FernetKeys5"))
Expect(maps.Keys(secret.Data)).ToNot(ContainElement("FernetKeys6"))
for i := 0; i < 6; i++ {
g.Expect(secret.Data["FernetKeys"+strconv.Itoa(i)]).NotTo(BeZero())
}
}, timeout, interval).Should(Succeed())
})
})
})
when you run this it fails with
[FAILED] Expected
<[]string | len:5, cap:5>: ["FernetKeys2", "CredentialKeys0", "CredentialKeys1", "FernetKeys0", "FernetKeys1"]
to contain elements
<[]string | len:6, cap:6>: ["FernetKeys0", "FernetKeys1", "FernetKeys2", "FernetKeys3", "FernetKeys4", "FernetKeys5"]
the missing elements were
<[]string | len:3, cap:3>: ["FernetKeys3", "FernetKeys4", "FernetKeys5"]
In [It] at: src/github.com/openstack-k8s-operators/keystone-operator/tests/functional/keystoneapi_controller_test.go:1178 @ 10/25/24 12:34:45.138
so I think there might be a bug with the logic which adds additional keys?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the tip on updating the spec.
Regarding the test part:
Expect(maps.Keys(secret.Data)).To(ContainElements("FernetKeys0", "FernetKeys1", "FernetKeys2"))
Expect(maps.Keys(secret.Data)).ToNot(ContainElement("FernetKeys3"))
I prefer to make sure there's no leftovers, for example, if we decrease from 6 to 3 keys, if somehow we ended up in this scenario: FernetKeys0, 1, 2, 5; I wanna make sure ALL the 'FernetKeys%d' are what we expect, so I`m counting how many FK we have and that they are all what we expect. Other way to do this (That I know of) would be to get each FK and see if they are valid; to check that they are valid would be to iterate over a range of fernetMaxKeys, create a string like 'FernetKeys%d' and add it to a list.
I preferred just to count the FernetKeys keys on the secret.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not saying you should use from above, but you could still do the same with that, like what I did that a key must not exist. I prefer that as it is easy to read. e.g. when you go from 6 to 3, you:
- expect these
Expect(maps.Keys(secret.Data)).To(ContainElements("FernetKeys0", "FernetKeys1", "FernetKeys2")) - you expect that those are gone
Expect(maps.Keys(secret.Data)).ToNot(ContainElements("FernetKeys3", "FernetKeys4", "FernetKeys5"))
What you probably want to enhance, e.g. when you go from 3 to 6 that the last key is the expected one. iiuc in this scenario, the old key[2] should become the key[5], right?
This is a draft because I still need to add tests changing the fernetMaxActiveKeys and having it reflected on the environment. |
} | ||
|
||
Expect(numberFernetKeys).Should(BeNumerically("==", 3)) | ||
for i := 0; i < 2; i++ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i < 3
or i <= 2
|
||
Expect(numberFernetKeys).Should(BeNumerically("==", 3)) | ||
for i := 0; i < 2; i++ { | ||
g.Expect(secret.Data["FernetKeys"+strconv.Itoa(i)]).NotTo(BeNil()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this won't be nil when the key exists. the value could be the empty string, so probably we want instead of BeNil()
check for BeZero()
@@ -1109,6 +1110,112 @@ var _ = Describe("Keystone controller", func() { | |||
}) | |||
}) | |||
|
|||
When("When the fernet keys are created with fernetMaxActiveKeys as 3", func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of the separate test bellow, maybe it would be better to test that when updating the keystone parameter from 3 -> 6 we see that the config and the secret got additional keys? Like have a nested when update keys from 3->6 it ...
secret := th.GetSecret(types.NamespacedName{Namespace: keystoneAPIName.Namespace, Name: "keystone"}) | ||
Expect(secret).ToNot(BeNil()) | ||
|
||
Eventually(func(g Gomega) { | ||
numberFernetKeys := 0 | ||
for k, _ := range secret.Data { | ||
if strings.HasPrefix(k, "FernetKeys") { | ||
numberFernetKeys++ | ||
} | ||
} | ||
|
||
Expect(numberFernetKeys).Should(BeNumerically("==", 3)) | ||
for i := 0; i < 2; i++ { | ||
g.Expect(secret.Data["FernetKeys"+strconv.Itoa(i)]).NotTo(BeNil()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of the looping, could do this check for the expected Fernet keys 0-2 and not to have a key3
Expect(maps.Keys(secret.Data)).To(ContainElements("FernetKeys0", "FernetKeys1", "FernetKeys2"))
Expect(maps.Keys(secret.Data)).ToNot(ContainElement("FernetKeys3"))
for i := 0; i < 3; i++ {
g.Expect(secret.Data["FernetKeys"+strconv.Itoa(i)]).NotTo(BeZero())
}
@@ -22,7 +22,7 @@ enforce_scope = {{ .enableSecureRBAC }} | |||
|
|||
[fernet_tokens] | |||
key_repository=/etc/keystone/fernet-keys | |||
max_active_keys=2 | |||
max_active_keys={{ .fernetMaxActiveKeys }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This setting is only used for Fernet key rotation [1], which we implemented in go. I guess we can keep your change, to be consistent... An alternative could be to just remove it from keystone.conf.
|
||
keystone := GetKeystoneAPI(keystoneAPIName) | ||
keystone.Spec.FernetMaxActiveKeys = ptr.To(int32(6)) | ||
_, err := controllerutil.CreateOrPatch( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not raising an error but the test doesn't work, still keeps 6 keys, maybe that's a bug. I`ll investigate it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why should this raise an error, with this you update the keystoneapi CR to have the value changed from 3 to 6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Im not expecting an error here, the next line is to enforce there was no issue during the update of values:
Expect(err).ToNot(HaveOccurred())`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes correct, I was reading your first message here that you'd expect an error. sorry misunderstood that.
00ae7c7
to
05e2403
Compare
05e2403
to
448471c
Compare
@afaranha: The following tests failed, say
Full PR test history. Your PR dashboard. 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-sigs/prow repository. I understand the commands that are listed here. |
c56b14c
to
d109a7f
Compare
Closing this PR because I messed up the rebase. |
No description provided.