diff --git a/integration_tests/aiven_credentials.lua b/integration_tests/aiven_credentials.lua index a8d1d6aaa..e86cdf0a4 100644 --- a/integration_tests/aiven_credentials.lua +++ b/integration_tests/aiven_credentials.lua @@ -4,6 +4,10 @@ local nonMember = User.new("nonmember", "other@user.com") local team = Team.new("credteam", "purpose", "#slack_channel") team:addMember(user) +-- Load K8s fixtures so that instance existence checks pass for known instances. +-- The fixtures provide opensearch-credteam-my-opensearch and valkey-credteam-my-valkey in the "dev" cluster. +Helper.readK8sResources("k8s_resources/aiven_credentials") + -- Authorization: non-member cannot create OpenSearch credentials Test.gql("Non-member cannot create OpenSearch credentials", function(t) t.addHeader("x-user-email", nonMember:email()) @@ -114,6 +118,118 @@ Test.gql("Cannot create credentials for non-existing team", function(t) } end) +-- Instance not found: OpenSearch +Test.gql("Cannot create OpenSearch credentials for non-existing instance", function(t) + t.addHeader("x-user-email", user:email()) + t.query(string.format([[ + mutation { + createOpenSearchCredentials(input: { + teamSlug: "%s" + environmentName: "dev" + instanceName: "does-not-exist" + permission: READ + ttl: "1d" + }) { + credentials { username } + } + } + ]], team:slug())) + + t.check { + errors = { + { + message = Contains("not found"), + path = { "createOpenSearchCredentials" }, + }, + }, + data = Null, + } +end) + +-- Instance not found: Valkey +Test.gql("Cannot create Valkey credentials for non-existing instance", function(t) + t.addHeader("x-user-email", user:email()) + t.query(string.format([[ + mutation { + createValkeyCredentials(input: { + teamSlug: "%s" + environmentName: "dev" + instanceName: "does-not-exist" + permission: READ + ttl: "1d" + }) { + credentials { username } + } + } + ]], team:slug())) + + t.check { + errors = { + { + message = Contains("not found"), + path = { "createValkeyCredentials" }, + }, + }, + data = Null, + } +end) + +-- Instance not found: non-existing environment for OpenSearch +Test.gql("Cannot create OpenSearch credentials in non-existing environment", function(t) + t.addHeader("x-user-email", user:email()) + t.query(string.format([[ + mutation { + createOpenSearchCredentials(input: { + teamSlug: "%s" + environmentName: "prod" + instanceName: "my-opensearch" + permission: READ + ttl: "1d" + }) { + credentials { username } + } + } + ]], team:slug())) + + t.check { + errors = { + { + message = Contains("not found"), + path = { "createOpenSearchCredentials" }, + }, + }, + data = Null, + } +end) + +-- Instance not found: non-existing environment for Valkey +Test.gql("Cannot create Valkey credentials in non-existing environment", function(t) + t.addHeader("x-user-email", user:email()) + t.query(string.format([[ + mutation { + createValkeyCredentials(input: { + teamSlug: "%s" + environmentName: "prod" + instanceName: "my-valkey" + permission: READ + ttl: "1d" + }) { + credentials { username } + } + } + ]], team:slug())) + + t.check { + errors = { + { + message = Contains("not found"), + path = { "createValkeyCredentials" }, + }, + }, + data = Null, + } +end) + -- Input validation: TTL exceeds maximum (OpenSearch) Test.gql("TTL exceeding 30 days is rejected", function(t) t.addHeader("x-user-email", user:email()) diff --git a/integration_tests/k8s_resources/aiven_credentials/dev/credteam/opensearch.yaml b/integration_tests/k8s_resources/aiven_credentials/dev/credteam/opensearch.yaml new file mode 100644 index 000000000..8719a4195 --- /dev/null +++ b/integration_tests/k8s_resources/aiven_credentials/dev/credteam/opensearch.yaml @@ -0,0 +1,38 @@ +--- +apiVersion: aiven.io/v1alpha1 +kind: OpenSearch +metadata: + annotations: + controllers.aiven.io/generation-was-processed: "1" + controllers.aiven.io/instance-is-running: "true" + labels: + app: app-name + name: opensearch-credteam-my-opensearch +spec: + cloudName: google-europe-north1 + connInfoSecretTarget: + name: "" + disk_space: 525G + plan: business-8 + project: nav-dev + projectVpcId: fff21e17-95d5-408b-8df5-15aacf38f5de + tags: + environment: dev + team: credteam + tenant: nav + terminationProtection: true + userConfig: + opensearch_version: "2" +status: + conditions: + - lastTransitionTime: "2023-11-08T10:36:06Z" + message: Instance was created or update on Aiven side + reason: Updated + status: "True" + type: Initialized + - lastTransitionTime: "2024-01-10T09:40:58Z" + message: Instance is running on Aiven side + reason: CheckRunning + status: "True" + type: Running + state: RUNNING diff --git a/integration_tests/k8s_resources/aiven_credentials/dev/credteam/valkey.yaml b/integration_tests/k8s_resources/aiven_credentials/dev/credteam/valkey.yaml new file mode 100644 index 000000000..232b3c06b --- /dev/null +++ b/integration_tests/k8s_resources/aiven_credentials/dev/credteam/valkey.yaml @@ -0,0 +1,35 @@ +--- +apiVersion: aiven.io/v1alpha1 +kind: Valkey +metadata: + annotations: + controllers.aiven.io/generation-was-processed: "1" + controllers.aiven.io/instance-is-running: "true" + labels: + app: app-name + name: valkey-credteam-my-valkey +spec: + cloudName: google-europe-north1 + connInfoSecretTarget: + name: "" + plan: startup-4 + project: nav-dev + projectVpcId: d405e36a-a577-4dce-af0e-6d217fc47a5c + tags: + environment: dev + team: credteam + tenant: nav + terminationProtection: true +status: + conditions: + - lastTransitionTime: "2023-11-20T19:07:04Z" + message: Instance was created or update on Aiven side + reason: Updated + status: "True" + type: Initialized + - lastTransitionTime: "2024-02-23T14:55:47Z" + message: Instance is running on Aiven side + reason: CheckRunning + status: "True" + type: Running + state: RUNNING diff --git a/internal/persistence/aivencredentials/queries.go b/internal/persistence/aivencredentials/queries.go index 0e1cd771e..af662b123 100644 --- a/internal/persistence/aivencredentials/queries.go +++ b/internal/persistence/aivencredentials/queries.go @@ -104,6 +104,10 @@ func createCredentials(ctx context.Context, req credentialRequest) (any, error) } func CreateOpenSearchCredentials(ctx context.Context, input CreateOpenSearchCredentialsInput) (*CreateOpenSearchCredentialsPayload, error) { + if _, err := opensearch.Get(ctx, input.TeamSlug, input.EnvironmentName, input.InstanceName); err != nil { + return nil, err + } + // Strip "opensearch--" prefix if the user provided the full Kubernetes resource name. // The buildSpec already prepends "opensearch--" for the Aivenator. instanceName := strings.TrimPrefix(input.InstanceName, opensearch.NamePrefix(input.TeamSlug)) @@ -154,6 +158,10 @@ func valkeyEnvVarSuffix(instanceName string) string { } func CreateValkeyCredentials(ctx context.Context, input CreateValkeyCredentialsInput) (*CreateValkeyCredentialsPayload, error) { + if _, err := valkey.Get(ctx, input.TeamSlug, input.EnvironmentName, input.InstanceName); err != nil { + return nil, err + } + // Strip "valkey--" prefix if the user provided the full Kubernetes resource name. // Aivenator expects the short instance name and prepends "valkey--" itself. instanceName := strings.TrimPrefix(input.InstanceName, valkey.NamePrefix(input.TeamSlug))