Skip to content

Commit a8fd6c5

Browse files
authored
Fix cfn-mutability for inherited identifiers (#1465)
* Fix cfn-mutability for inherited identifiers For resources with parent resources, identifiers that are inherited should be marked with create-and-read mutability instead of the defaults for that resource. This fixes that case, and adjusts the test cases to verify the correct behavior
1 parent f12a737 commit a8fd6c5

File tree

4 files changed

+33
-9
lines changed

4 files changed

+33
-9
lines changed

smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceIndex.java

+25-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import java.util.Optional;
2424
import java.util.Set;
2525
import java.util.function.Function;
26+
import java.util.stream.Collectors;
2627
import software.amazon.smithy.model.Model;
28+
import software.amazon.smithy.model.knowledge.BottomUpIndex;
2729
import software.amazon.smithy.model.knowledge.IdentifierBindingIndex;
2830
import software.amazon.smithy.model.knowledge.KnowledgeIndex;
2931
import software.amazon.smithy.model.knowledge.OperationIndex;
@@ -36,6 +38,7 @@
3638
import software.amazon.smithy.model.shapes.StructureShape;
3739
import software.amazon.smithy.model.shapes.ToShapeId;
3840
import software.amazon.smithy.utils.MapUtils;
41+
import software.amazon.smithy.utils.OptionalUtils;
3942
import software.amazon.smithy.utils.SetUtils;
4043

4144
/**
@@ -48,6 +51,8 @@ public final class CfnResourceIndex implements KnowledgeIndex {
4851

4952
static final Set<Mutability> FULLY_MUTABLE = SetUtils.of(
5053
Mutability.CREATE, Mutability.READ, Mutability.WRITE);
54+
static final Set<Mutability> INHERITED_MUTABILITY = SetUtils.of(
55+
Mutability.CREATE, Mutability.READ);
5156

5257
private final Map<ShapeId, CfnResource> resourceDefinitions = new HashMap<>();
5358

@@ -85,15 +90,22 @@ public enum Mutability {
8590

8691
public CfnResourceIndex(Model model) {
8792
OperationIndex operationIndex = OperationIndex.of(model);
93+
BottomUpIndex bottomUpIndex = BottomUpIndex.of(model);
8894
model.shapes(ResourceShape.class)
8995
.filter(shape -> shape.hasTrait(CfnResourceTrait.ID))
9096
.forEach(resource -> {
9197
CfnResource.Builder builder = CfnResource.builder();
9298
ShapeId resourceId = resource.getId();
9399

100+
Set<ResourceShape> parentResources = model.getServiceShapes()
101+
.stream()
102+
.map(service -> bottomUpIndex.getResourceBinding(service, resourceId))
103+
.flatMap(OptionalUtils::stream)
104+
.collect(Collectors.toSet());
105+
94106
// Start with the explicit resource identifiers.
95107
builder.primaryIdentifiers(resource.getIdentifiers().keySet());
96-
setIdentifierMutabilities(builder, resource);
108+
setIdentifierMutabilities(builder, resource, parentResources);
97109

98110
// Use the read lifecycle's input to collect the additional identifiers
99111
// and its output to collect readable properties.
@@ -164,13 +176,22 @@ public Optional<CfnResource> getResource(ToShapeId resource) {
164176
return Optional.ofNullable(resourceDefinitions.get(resource.toShapeId()));
165177
}
166178

167-
private void setIdentifierMutabilities(CfnResource.Builder builder, ResourceShape resource) {
168-
Set<Mutability> mutability = getDefaultIdentifierMutabilities(resource);
179+
private boolean identifierIsInherited(String identifier, Set<ResourceShape> parentResources) {
180+
return parentResources.stream()
181+
.anyMatch(parentResource -> parentResource.getIdentifiers().containsKey(identifier));
182+
}
183+
184+
private void setIdentifierMutabilities(
185+
CfnResource.Builder builder,
186+
ResourceShape resource,
187+
Set<ResourceShape> parentResources) {
188+
Set<Mutability> defaultIdentifierMutability = getDefaultIdentifierMutabilities(resource);
169189

170190
resource.getIdentifiers().forEach((name, shape) -> {
171191
builder.putPropertyDefinition(name, CfnResourceProperty.builder()
172192
.hasExplicitMutability(true)
173-
.mutabilities(mutability)
193+
.mutabilities(identifierIsInherited(name, parentResources)
194+
? INHERITED_MUTABILITY : defaultIdentifierMutability)
174195
.addShapeId(shape)
175196
.build());
176197
});

smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceProperty.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ public ShapeId getShapeId() {
6666
* by the use of a trait instead of derived through its lifecycle
6767
* bindings within a resource.
6868
*
69-
* @return Returns true if the mutability is explicitly defined by a trait.
69+
* <p> Also returns true for identifiers, since their mutability is inherent
70+
*
71+
* @return Returns true if the mutability is explicitly defined by a trait or
72+
* if property is an identifier
7073
*
7174
* @see CfnMutabilityTrait
7275
*/

smithy-aws-cloudformation-traits/src/test/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceIndexTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,15 @@ public static Collection<ResourceData> data() {
9999
bazResource.identifiers = SetUtils.of("barId", "bazId");
100100
bazResource.additionalIdentifiers = ListUtils.of();
101101
bazResource.mutabilities = MapUtils.of(
102-
"barId", SetUtils.of(Mutability.READ),
102+
"barId", SetUtils.of(Mutability.CREATE, Mutability.READ),
103103
"bazId", SetUtils.of(Mutability.READ),
104104
"bazExplicitMutableProperty", CfnResourceIndex.FULLY_MUTABLE,
105105
"bazImplicitFullyMutableProperty", CfnResourceIndex.FULLY_MUTABLE,
106106
"bazImplicitCreateProperty", SetUtils.of(Mutability.CREATE, Mutability.READ),
107107
"bazImplicitReadProperty", SetUtils.of(Mutability.READ),
108108
"bazImplicitWriteProperty", SetUtils.of(Mutability.CREATE, Mutability.WRITE));
109-
bazResource.createOnlyProperties = SetUtils.of("bazImplicitCreateProperty");
110-
bazResource.readOnlyProperties = SetUtils.of("barId", "bazId", "bazImplicitReadProperty");
109+
bazResource.createOnlyProperties = SetUtils.of("barId", "bazImplicitCreateProperty");
110+
bazResource.readOnlyProperties = SetUtils.of("bazId", "bazImplicitReadProperty");
111111
bazResource.writeOnlyProperties = SetUtils.of("bazImplicitWriteProperty");
112112

113113
return ListUtils.of(fooResource, barResource, bazResource);

smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/smithy-testservice-basil.cfn.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525
}
2626
},
2727
"readOnlyProperties": [
28-
"/properties/BarId",
2928
"/properties/BazId",
3029
"/properties/BazImplicitReadProperty"
3130
],
3231
"writeOnlyProperties": [
3332
"/properties/BazImplicitWriteProperty"
3433
],
3534
"createOnlyProperties": [
35+
"/properties/BarId",
3636
"/properties/BazImplicitCreateProperty"
3737
],
3838
"primaryIdentifier": [

0 commit comments

Comments
 (0)