Skip to content

Commit 064237a

Browse files
Merge pull request #182 from ahmedtadde/feat/ensure-linkdef-target-maps-to-some-capability-comp
Validate that linkdef targets actually exist in the manifest
2 parents 1321bcd + 786ca22 commit 064237a

File tree

2 files changed

+64
-6
lines changed

2 files changed

+64
-6
lines changed

src/server/handlers.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -809,14 +809,15 @@ impl<P: Publisher> Handler<P> {
809809

810810
// Manifest validation
811811
pub(crate) fn validate_manifest(manifest: Manifest) -> anyhow::Result<()> {
812-
let mut component_details: HashSet<String> = HashSet::new();
812+
let mut name_registry: HashSet<String> = HashSet::new();
813+
let mut required_capability_components: HashSet<String> = HashSet::new();
813814

814815
// Map of link names to a vector of provider references with that link name
815816
let mut linkdef_map: HashMap<String, Vec<String>> = HashMap::new();
816817

817818
for component in manifest.spec.components.iter() {
818819
// Component name validation : each component (actors or providers) should have a unique name
819-
if !component_details.insert(component.name.clone()) {
820+
if !name_registry.insert(component.name.clone()) {
820821
return Err(anyhow!(
821822
"Duplicate component name in manifest: {}",
822823
component.name
@@ -864,7 +865,7 @@ pub(crate) fn validate_manifest(manifest: Manifest) -> anyhow::Result<()> {
864865
properties: ActorProperties { image: image_name },
865866
} = &component.properties
866867
{
867-
if !component_details.insert(image_name.to_string()) {
868+
if !name_registry.insert(image_name.to_string()) {
868869
return Err(anyhow!(
869870
"Duplicate image reference in manifest: {}",
870871
image_name
@@ -888,14 +889,30 @@ pub(crate) fn validate_manifest(manifest: Manifest) -> anyhow::Result<()> {
888889
{
889890
if !linkdef_set.insert(target_name.to_string()) {
890891
return Err(anyhow!(
891-
"Duplicate target for linkdef in manifest: {}",
892-
target_name
892+
"Duplicate target {} for component {} linkdef trait in manifest",
893+
target_name,
894+
component.name,
893895
));
894896
}
897+
898+
// Multiple components{ with type != 'capability'} can declare the same target, so we don't need to check for duplicates on insert
899+
required_capability_components.insert(target_name.to_string());
895900
}
896901
}
897902
}
898903
}
904+
905+
let missing_capability_components = required_capability_components
906+
.difference(&name_registry)
907+
.collect::<Vec<&String>>();
908+
909+
if !missing_capability_components.is_empty() {
910+
return Err(anyhow!(
911+
"The following capability component(s) are missing from the manifest: {:?}",
912+
missing_capability_components
913+
));
914+
}
915+
899916
Ok(())
900917
}
901918

@@ -957,9 +974,17 @@ mod test {
957974

958975
match validate_manifest(manifest) {
959976
Ok(()) => panic!("Should have detected duplicate linkdef"),
977+
Err(e) => assert!(e.to_string().contains("Duplicate target")),
978+
}
979+
980+
let manifest = deserialize_yaml("./test/data/missing_capability_component.yaml")
981+
.expect("Should be able to parse");
982+
983+
match validate_manifest(manifest) {
984+
Ok(()) => panic!("Should have detected missing capability component"),
960985
Err(e) => assert!(e
961986
.to_string()
962-
.contains("Duplicate target for linkdef in manifest")),
987+
.contains("The following capability component(s) are missing from the manifest: ")),
963988
}
964989
}
965990

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
apiVersion: core.oam.dev/v1beta1
2+
kind: Application
3+
metadata:
4+
name: echo-simple
5+
annotations:
6+
version: v0.0.1
7+
description: "This is my app"
8+
spec:
9+
components:
10+
- name: echo
11+
type: actor
12+
properties:
13+
image: wasmcloud.azurecr.io/echo:0.3.7
14+
traits:
15+
- type: spreadscaler
16+
properties:
17+
replicas: 4
18+
- type: linkdef
19+
properties:
20+
# This is a simple typo which should be caught by validation: there is no capability component named "httpservr"
21+
target: httpservr
22+
values:
23+
address: 0.0.0.0:8080
24+
25+
- name: httpserver
26+
type: capability
27+
properties:
28+
contract: wasmcloud:httpserver
29+
image: wasmcloud.azurecr.io/httpserver:0.17.0
30+
traits:
31+
- type: spreadscaler
32+
properties:
33+
replicas: 1

0 commit comments

Comments
 (0)