99import io .scalecube .config .source .LoadedConfigProperty ;
1010import java .util .ArrayList ;
1111import java .util .Arrays ;
12+ import java .util .Collection ;
13+ import java .util .Collections ;
1214import java .util .HashMap ;
1315import java .util .List ;
1416import java .util .Map ;
15- import java .util .Objects ;
17+ import java .util .Optional ;
1618import java .util .function .Function ;
1719import java .util .function .UnaryOperator ;
1820import java .util .stream .Collectors ;
@@ -28,99 +30,119 @@ public class VaultConfigSource implements ConfigSource {
2830
2931 private static final Logger LOGGER = LoggerFactory .getLogger (VaultConfigSource .class );
3032
31- private static final String VAULT_SECRETS_PATH = "VAULT_SECRETS_PATH" ;
33+ private static final EnvironmentLoader ENVIRONMENT_LOADER = new EnvironmentLoader ();
34+
35+ private static final String PATHS_SEPARATOR = ":" ;
3236
3337 private final VaultInvoker vault ;
34- private final List <String > secretsPath ;
38+ private final List <String > secretsPaths ;
3539
36- /**
37- * Create a new {@link VaultConfigSource}.
38- * @param vault vault invoker.
39- * @param secretsPaths secret path-s.
40- */
4140 private VaultConfigSource (VaultInvoker vault , List <String > secretsPaths ) {
4241 this .vault = vault ;
43- this .secretsPath = secretsPaths ;
42+ this .secretsPaths = new ArrayList <>( secretsPaths ) ;
4443 }
4544
4645 @ Override
4746 public Map <String , ConfigProperty > loadConfig () {
4847 Map <String , ConfigProperty > result = new HashMap <>();
49- for (String path : secretsPath ) {
48+ for (String path : secretsPaths ) {
5049 try {
5150 LogicalResponse response = vault .invoke (vault -> vault .logical ().read (path ));
52- final Map <String , LoadedConfigProperty > pathProps = response .getData ().entrySet ().stream ()
53- .map (LoadedConfigProperty ::withNameAndValue )
54- .map (LoadedConfigProperty .Builder ::build )
55- .collect (Collectors .toMap (LoadedConfigProperty ::name , Function .identity ()));
51+ final Map <String , LoadedConfigProperty > pathProps =
52+ response .getData ().entrySet ().stream ()
53+ .map (LoadedConfigProperty ::withNameAndValue )
54+ .map (LoadedConfigProperty .Builder ::build )
55+ .collect (Collectors .toMap (LoadedConfigProperty ::name , Function .identity ()));
5656 result .putAll (pathProps );
5757 } catch (Exception ex ) {
58- LOGGER .warn ("unable to load config properties from {}" ,path , ex );
58+ LOGGER .warn ("Unable to load config properties from {}" , path , ex );
5959 throw new ConfigSourceNotAvailableException (ex );
6060 }
6161 }
6262 return result ;
6363 }
6464
65- /**
66- * This builder method is used internally for test purposes. please use it only for tests. Please
67- * note the following required environment variables are required.
68- *
69- * <ul>
70- * <li><code>VAULT_SECRETS_PATH</code> is the path to use (defaults to <code>secret</code>)
71- * <li><code>VAULT_TOKEN</code> is the {@link VaultConfig#token(String) token} to use
72- * <li><code>VAULT_ADDR</code> is the {@link VaultConfig#address(String) address} of the vault
73- * (API)
74- * </ul>
75- */
7665 public static Builder builder () {
7766 return new Builder ();
7867 }
7968
80- /**
81- * This builder method is used internally for test purposes. please use it only for tests
82- *
83- * @param environmentLoader an {@link EnvironmentLoader}
84- */
85- static Builder builder (EnvironmentLoader environmentLoader ) {
86- final Builder builder = new Builder ();
87- if (environmentLoader != null ) {
88- builder .environmentLoader = environmentLoader ;
89- }
90- return builder ;
91- }
92-
9369 public static final class Builder {
9470
95- private Function <VaultInvoker .Builder , VaultInvoker .Builder > vault = Function .identity ();
71+ private Function <VaultInvoker .Builder , VaultInvoker .Builder > builderFunction = b -> b ;
72+
9673 private VaultInvoker invoker ;
97- private EnvironmentLoader environmentLoader = VaultInvoker .Builder .ENVIRONMENT_LOADER ;
98- private List <String > secretsPaths = new ArrayList <>();
74+
75+ private List <String > secretsPaths =
76+ Optional .ofNullable (ENVIRONMENT_LOADER .loadVariable ("VAULT_SECRETS_PATH" ))
77+ .or (() -> Optional .ofNullable (ENVIRONMENT_LOADER .loadVariable ("VAULT_SECRETS_PATHS" )))
78+ .map (s -> s .split (PATHS_SEPARATOR ))
79+ .map (Arrays ::asList )
80+ .orElseGet (ArrayList ::new );
9981
10082 private Builder () {}
10183
84+ /**
85+ * Appends {@code secretsPath} to {@code secretsPaths}.
86+ *
87+ * @param secretsPath secretsPath (may contain value with paths separated by {@code :})
88+ * @return this builder
89+ * @deprecated will be removed in future releases without notice, use {@link
90+ * #addSecretsPath(String...)} or {@link #secretsPaths(Collection)}.
91+ */
92+ @ Deprecated
10293 public Builder secretsPath (String secretsPath ) {
103- this .secretsPaths .add (secretsPath );
94+ this .secretsPaths .addAll (toSecretsPaths (Collections .singletonList (secretsPath )));
95+ return this ;
96+ }
97+
98+ /**
99+ * Appends one or several secretsPath\es to {@code secretsPaths}.
100+ *
101+ * @param secretsPath one or several secretsPath\es (each value may contain paths separated by
102+ * {@code :})
103+ * @return this builder
104+ */
105+ public Builder addSecretsPath (String ... secretsPath ) {
106+ this .secretsPaths .addAll (toSecretsPaths (Arrays .asList (secretsPath )));
107+ return this ;
108+ }
109+
110+ /**
111+ * Setter for {@code secretsPaths}.
112+ *
113+ * @param secretsPaths collection of secretsPath\es (each value may contain paths separated by
114+ * {@code :})
115+ * @return this builder
116+ */
117+ public Builder secretsPaths (Collection <String > secretsPaths ) {
118+ this .secretsPaths = toSecretsPaths (secretsPaths );
104119 return this ;
105120 }
106121
122+ private static List <String > toSecretsPaths (Collection <String > secretsPaths ) {
123+ return secretsPaths .stream ()
124+ .flatMap (s -> Arrays .stream (s .split (PATHS_SEPARATOR )))
125+ .distinct ()
126+ .collect (Collectors .toList ());
127+ }
128+
107129 public Builder invoker (VaultInvoker invoker ) {
108130 this .invoker = invoker ;
109131 return this ;
110132 }
111133
112134 public Builder vault (UnaryOperator <VaultInvoker .Builder > config ) {
113- this .vault = this .vault .andThen (config );
135+ this .builderFunction = this .builderFunction .andThen (config );
114136 return this ;
115137 }
116138
117139 public Builder config (UnaryOperator <VaultConfig > vaultConfig ) {
118- this .vault = this .vault .andThen (c -> c .options (vaultConfig ));
140+ this .builderFunction = this .builderFunction .andThen (c -> c .options (vaultConfig ));
119141 return this ;
120142 }
121143
122144 public Builder tokenSupplier (VaultTokenSupplier supplier ) {
123- this .vault = this .vault .andThen (c -> c .tokenSupplier (supplier ));
145+ this .builderFunction = this .builderFunction .andThen (c -> c .tokenSupplier (supplier ));
124146 return this ;
125147 }
126148
@@ -130,17 +152,9 @@ public Builder tokenSupplier(VaultTokenSupplier supplier) {
130152 * @return instance of {@link VaultConfigSource}
131153 */
132154 public VaultConfigSource build () {
133- VaultInvoker vaultInvoker =
134- invoker != null
135- ? invoker
136- : vault .apply (new VaultInvoker .Builder (environmentLoader )).build ();
137- if (secretsPaths .isEmpty ()) {
138- String envSecretPath = Objects
139- .requireNonNull (environmentLoader .loadVariable (VAULT_SECRETS_PATH ),
140- "Missing secretsPath" );
141- secretsPaths = Arrays .asList (envSecretPath .split (":" ));
142- }
143- return new VaultConfigSource (vaultInvoker , secretsPaths );
155+ return new VaultConfigSource (
156+ invoker != null ? invoker : builderFunction .apply (new VaultInvoker .Builder ()).build (),
157+ secretsPaths );
144158 }
145159 }
146160}
0 commit comments