|
1 | 1 | package it.aboutbits.postgresql.core; |
2 | 2 |
|
| 3 | +import com.fasterxml.jackson.databind.ObjectMapper; |
3 | 4 | import io.fabric8.kubernetes.client.KubernetesClient; |
4 | 5 | import it.aboutbits.postgresql.crd.clusterconnection.ClusterConnection; |
5 | 6 | import jakarta.inject.Singleton; |
| 7 | +import lombok.RequiredArgsConstructor; |
6 | 8 | import org.jspecify.annotations.NullMarked; |
| 9 | +import org.jspecify.annotations.Nullable; |
7 | 10 |
|
| 11 | +import java.io.IOException; |
8 | 12 | import java.nio.charset.Charset; |
| 13 | +import java.nio.file.Files; |
| 14 | +import java.nio.file.NoSuchFileException; |
| 15 | +import java.nio.file.Path; |
9 | 16 | import java.util.Base64; |
10 | 17 |
|
11 | 18 | @Singleton |
| 19 | +@RequiredArgsConstructor |
12 | 20 | @NullMarked |
13 | 21 | public final class KubernetesService { |
| 22 | + private final ObjectMapper objectMapper; |
| 23 | + |
| 24 | + private record FileCredentials( |
| 25 | + @Nullable String username, |
| 26 | + @Nullable String password |
| 27 | + ) { |
| 28 | + } |
| 29 | + |
14 | 30 | public static final String SECRET_TYPE_BASIC_AUTH = "kubernetes.io/basic-auth"; |
15 | 31 | public static final String SECRET_DATA_BASIC_AUTH_USERNAME_KEY = "username"; |
16 | 32 | public static final String SECRET_DATA_BASIC_AUTH_PASSWORD_KEY = "password"; |
17 | 33 |
|
18 | | - public Credentials getSecretRefCredentials( |
| 34 | + public Credentials getAdminCredentials( |
19 | 35 | KubernetesClient kubernetesClient, |
20 | 36 | ClusterConnection clusterConnection |
21 | 37 | ) { |
22 | | - return getSecretRefCredentials( |
23 | | - kubernetesClient, |
24 | | - clusterConnection.getSpec().getAdminSecretRef(), |
25 | | - clusterConnection.getMetadata().getNamespace() |
26 | | - ); |
| 38 | + var spec = clusterConnection.getSpec(); |
| 39 | + if (spec.getAdminSecretRef() != null) { |
| 40 | + var secretRef = spec.getAdminSecretRef(); |
| 41 | + var defaultNamespace = clusterConnection.getMetadata().getNamespace(); |
| 42 | + var credentials = getSecretRefCredentials(kubernetesClient, secretRef, defaultNamespace); |
| 43 | + if (credentials.username() == null) { |
| 44 | + var secretNamespace = getSecretNamespace(secretRef, defaultNamespace); |
| 45 | + throw new IllegalStateException( |
| 46 | + "The Secret reference is missing required data username [secret.namespace=%s, secret.name=%s]".formatted( |
| 47 | + secretNamespace, secretRef.getName())); |
| 48 | + } |
| 49 | + return credentials; |
| 50 | + } else if (spec.getAdminSecretFileRef() != null) { |
| 51 | + return getSecretFileRefCredentials(spec.getAdminSecretFileRef()); |
| 52 | + } |
| 53 | + |
| 54 | + throw new IllegalStateException("Exactly one of 'adminSecretRef' or 'adminSecretFileRef' must be provided"); |
| 55 | + } |
| 56 | + |
| 57 | + public Credentials getSecretFileRefCredentials(FileRef fileRef) { |
| 58 | + var path = Path.of(fileRef.getPath()); |
| 59 | + |
| 60 | + try (var in = Files.newInputStream(path)) { |
| 61 | + var file = objectMapper.readValue(in, FileCredentials.class); |
| 62 | + if (file.username() == null) { |
| 63 | + throw new IllegalStateException( |
| 64 | + "Credentials file is missing required field 'username' [path=%s]".formatted(path)); |
| 65 | + } |
| 66 | + if (file.password() == null) { |
| 67 | + throw new IllegalStateException( |
| 68 | + "Credentials file is missing required field 'password' [path=%s]".formatted(path)); |
| 69 | + } |
| 70 | + return new Credentials(file.username(), file.password()); |
| 71 | + } catch (NoSuchFileException e) { |
| 72 | + throw new IllegalStateException( |
| 73 | + "Credentials file not found [path=%s]".formatted(path), e); |
| 74 | + } catch (IOException e) { |
| 75 | + throw new IllegalStateException( |
| 76 | + "Failed to read the credentials file [path=%s]".formatted(path), e); |
| 77 | + } |
27 | 78 | } |
28 | 79 |
|
29 | 80 | public Credentials getSecretRefCredentials( |
30 | 81 | KubernetesClient kubernetesClient, |
31 | 82 | ResourceRef secretRef, |
32 | 83 | String defaultNamespace |
33 | 84 | ) { |
34 | | - var secretNamespace = secretRef.getNamespace() != null |
35 | | - ? secretRef.getNamespace() |
36 | | - : defaultNamespace; |
| 85 | + var secretNamespace = getSecretNamespace(secretRef, defaultNamespace); |
37 | 86 |
|
38 | 87 | var secretName = secretRef.getName(); |
39 | 88 |
|
@@ -91,4 +140,10 @@ public Credentials getSecretRefCredentials( |
91 | 140 | password |
92 | 141 | ); |
93 | 142 | } |
| 143 | + |
| 144 | + private String getSecretNamespace(ResourceRef secretRef, String defaultNamespace) { |
| 145 | + return secretRef.getNamespace() != null |
| 146 | + ? secretRef.getNamespace() |
| 147 | + : defaultNamespace; |
| 148 | + } |
94 | 149 | } |
0 commit comments