Repository navigation
Conversation
Extend the v3 DynamicResolvableParametersFactory to scan each resource's
service-keys[].config for {ds/...} credential references, in addition to
the existing top-level parameter/property scan. Scoped recursion only
into service-keys[].config, preserving the existing depth-one contract
for all other parameters.
Add ServiceKeyCredentialResolver, which replaces
{ds/<resource>/service-keys.<key>.credentials.<field>} references in a
service key's credentials by reading the referenced (already created)
service key's credentials from the Cloud Controller and extracting the
addressed field. Missing fields fail loudly with a clear message.
Wire it in via a new idempotent ResolveServiceKeyCredentialReferencesStep,
inserted in create-service-key.bpmn between the operation-in-progress
check and createServiceKey, so a referenced resource's key (guaranteed to
be in an earlier, already-completed batch by processed-after) is read back
just before the consuming key is created.
ResolveServiceKeyCredentialReferencesStep now builds the relationship->service-instance-name map from the deployment descriptor, using each resource's service-name parameter (falling back to the resource name). Previously it passed an empty map, so the credential read-back used the resource name as the service instance name and failed for resources whose service-name differs from their resource name.
411c202 to
12700f7
Compare
Extend the dynamic service-key credential feature to a module's service-binding parameters (requires[].parameters.config), not only service-keys[].config. Factor the map-level resolution out of ServiceKeyCredentialResolver into resolveReferencesInMap, and add an idempotent ResolveBindingCredentialReferencesStep that rewrites SERVICE_BINDING_PARAMETERS just before BindServiceToApplicationStep, wired into manage-app-service-bindings.bpmn on the bind path (the POLL re-entry edge still targets the bind task directly; resolution is a no-op once no references remain). This supports the client scenario of injecting a produced service key's credential (e.g. ZTIS issuer/subject) into another service's binding config. The reference must name a service key; a bare managed-service reference has no retrievable credential output in CF.
The binding-resolution step runs inside the manageAppServiceBindingSubProcess Flowable sub-process, which does not inherit COMPLETE_DEPLOYMENT_DESCRIPTOR. Build the relationship->service-instance-name map from Variables.SERVICES_TO_BIND (each CloudServiceInstanceExtended carries getResourceName() and getName()), which is passed into the sub-process and already precomputes the resolved CF service instance names. The referenced resource must be among the module's required dependencies so it appears in SERVICES_TO_BIND.
| return StepPhase.DONE; | ||
| } | ||
|
|
||
| private Map<String, String> buildServiceInstanceNamesByRelationship(ProcessContext context) { |
There was a problem hiding this comment.
This method and teh method in ResolveServiceKeyCredentialReferencesStep are doing almost the same thing. Can you somehow combine them?
There was a problem hiding this comment.
Done — extracted and as static factory methods on . Both steps now call the shared method, so the logic lives in one place. The two methods still exist separately because they read from incompatible sources (descriptor vs. ), but the duplication in the codebase is gone.
| for (CloudServiceInstanceExtended service : servicesToBind) { | ||
| serviceInstanceNamesByRelationship.put(service.getResourceName(), service.getName()); | ||
| } |
There was a problem hiding this comment.
In the other method you also check for serviceName. Don't we need there the same validation?
There was a problem hiding this comment.
Fixed — the same serviceName instanceof String guard is now applied inside buildServiceInstanceNamesFromServicesToBind in the shared static method. In practice the binding step reads from CloudServiceInstanceExtended.getName() which always returns a String, but the consistency is correct.
|
|
||
| @Override | ||
| protected StepPhase executeStep(ProcessContext context) { | ||
| CloudServiceKey serviceKeyToProcess = context.getVariable(Variables.SERVICE_KEY_TO_PROCESS); |
There was a problem hiding this comment.
Is it requierd to have a validation if serviceKeyToProcess is set or we will go in this step only if its set?
There was a problem hiding this comment.
Removed. Per the BPMN flow in create-service-key.bpmn, resolveServiceKeyCredentialReferences is on the default (non-POLL) path and SERVICE_KEY_TO_PROCESS is always set before this step runs. Other steps in the same subprocess (CreateServiceKeyStep, DeleteServiceKeyStep) follow the same pattern without a null-check.
| String credentialFieldPath = DynamicParameterUtil.getCredentialFieldPath(parameterName); | ||
|
|
||
| String serviceInstanceName = serviceInstanceNamesByRelationship.getOrDefault(relationshipName, relationshipName); | ||
| CloudServiceKey referencedKey = client.getServiceKey(serviceInstanceName, serviceKeyName); |
There was a problem hiding this comment.
Can you get the service key from the flowable context so we don't have to make extra API calls?
There was a problem hiding this comment.
The API call is necessary here. SERVICE_KEY_TO_PROCESS in the Flowable context is the key being created in this subprocess — it has config but no credentials yet. The API call fetches a different, already-created key (the one referenced by the {ds/...} expression) to read its credentials. There is no way to avoid this call: the referenced key belongs to a different resource and its credentials are not available in the process context.
| Map<String, Object> resolved = new LinkedHashMap<>(values); | ||
| boolean changed = false; | ||
| for (Map.Entry<String, Object> entry : values.entrySet()) { | ||
| if (!isServiceKeyCredentialReference(entry.getValue())) { | ||
| continue; | ||
| } | ||
| resolved.put(entry.getKey(), resolveReference((String) entry.getValue())); | ||
| changed = true; | ||
| } |
There was a problem hiding this comment.
Can't we just return values if nothing was changed and work with the values map instead of creating a new one resolved?
There was a problem hiding this comment.
Done — the map is now allocated lazily: it is only created when the first reference is found, so there is no unnecessary copy when nothing needs resolving. The previous code already returned the original map instance when unchanged (changed ? resolved : values), but it still allocated the copy upfront. That allocation is now deferred.
…zy map allocation - Extract buildServiceInstanceNamesFromDescriptor/buildServiceInstanceNamesFromServicesToBind as static factory methods on ServiceKeyCredentialResolver so both steps share the logic instead of duplicating it (addresses comment on duplication) - Remove defensive null-check for SERVICE_KEY_TO_PROCESS in ResolveServiceKeyCredentialReferencesStep; it is always set when the step runs per the BPMN flow (createServiceKeySubProcess default path) - Make the resolved map in resolveReferencesInMap lazy-allocated: only allocate when at least one reference is found, avoiding an unnecessary copy when nothing needs resolving
| for (Map.Entry<String, Object> entry : values.entrySet()) { | ||
| if (!isServiceKeyCredentialReference(entry.getValue())) { | ||
| continue; | ||
| } | ||
| if (resolved == null) { | ||
| resolved = new LinkedHashMap<>(values); | ||
| } | ||
| resolved.put(entry.getKey(), resolveReference((String) entry.getValue())); | ||
| } | ||
| return resolved != null ? resolved : values; | ||
| } |
There was a problem hiding this comment.
I think the second (if(resolved == null)) can be removed and initialize the map on line 80. We don't need this if. If we remove the if inside the for loop then can be remove the condition in the return statement and return resolved every time
No description provided.