Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: openchoreo.dev/v1alpha1
kind: ReleaseBinding
metadata:
name: collab-svc-development
namespace: default
spec:
environment: development
owner:
componentName: collab-svc
projectName: doclet
releaseName: collab-svc-e0458407
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
apiVersion: openchoreo.dev/v1alpha1
kind: ComponentRelease
metadata:
name: collab-svc-e0458407
namespace: default
spec:
componentProfile:
parameters:
exposed: true
port: 8090
Comment on lines +9 to +10
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The HTTPRoute selectors never match this endpoint.

Line 9 sets exposed: true, but the only route-generation branches at Lines 97-98 and 133-134 key off ep.visibility, and the endpoint declared at Lines 257-260 never sets that field. That leaves this release with, at best, a Service but no HTTPRoute for collab-svc (or a render failure if missing fields are not tolerated). Please either populate endpoint visibility explicitly or make the route logic honor exposed directly. Based on learnings, services in this sample repo are intentionally exposed by default, so losing that behavior here is unexpected.

Also applies to: 97-98, 133-134, 257-260

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@namespaces/default/projects/doclet/components/collab-svc/releases/collab-svc-e0458407.yaml`
around lines 9 - 10, The HTTPRoute generation never sees endpoint visibility
because the endpoint object for collab-svc sets exposed: true but does not set
ep.visibility; update the endpoint definition (the object that currently
includes "exposed: true") to also populate the visibility field (e.g., set
visibility: "External" or the value expected by the route branches) so the
route-generation branches that check ep.visibility will match, or alternatively
modify the route-generation logic that checks ep.visibility (the branches
referencing ep.visibility) to also accept exposed: true when deciding to create
HTTPRoute entries; ensure you update either the endpoint object (add visibility)
or the route-checking conditions to honor exposed to restore the intended
exposed-by-default behavior.

replicas: 1
componentType:
kind: ComponentType
name: deployment/service
spec:
environmentConfigs:
openAPIV3Schema:
$defs:
ResourceQuantity:
properties:
cpu:
default: 100m
type: string
memory:
default: 256Mi
type: string
type: object
ResourceRequirements:
properties:
limits:
$ref: '#/$defs/ResourceQuantity'
default: {}
requests:
$ref: '#/$defs/ResourceQuantity'
default: {}
type: object
properties:
imagePullPolicy:
default: IfNotPresent
type: string
replicas:
default: 1
type: integer
resources:
$ref: '#/$defs/ResourceRequirements'
default: {}
type: object
resources:
- id: deployment
template:
apiVersion: apps/v1
kind: Deployment
metadata:
labels: ${metadata.labels}
name: ${metadata.name}
namespace: ${metadata.namespace}
spec:
replicas: ${environmentConfigs.replicas}
selector:
matchLabels: ${metadata.podSelectors}
template:
metadata:
labels: ${metadata.podSelectors}
spec:
containers:
- args: |
${has(workload.container.args) ? workload.container.args : oc_omit()}
command: |
${has(workload.container.command) ? workload.container.command : oc_omit()}
env: ${connections.toContainerEnv()}
envFrom: ${configurations.toContainerEnvFrom()}
image: ${workload.container.image}
imagePullPolicy: ${environmentConfigs.imagePullPolicy}
name: main
resources:
limits:
cpu: ${environmentConfigs.resources.limits.cpu}
memory: ${environmentConfigs.resources.limits.memory}
requests:
cpu: ${environmentConfigs.resources.requests.cpu}
memory: ${environmentConfigs.resources.requests.memory}
volumeMounts: ${configurations.toContainerVolumeMounts()}
volumes: ${configurations.toVolumes()}
- id: service
includeWhen: ${size(workload.endpoints) > 0}
template:
apiVersion: v1
kind: Service
metadata:
labels: ${metadata.labels}
name: ${metadata.componentName}
namespace: ${metadata.namespace}
spec:
ports: ${workload.toServicePorts()}
selector: ${metadata.podSelectors}
type: ClusterIP
- forEach: '${workload.endpoints.transformList(name, ep, ("external" in ep.visibility
&& ep.type in ["HTTP", "REST", "GraphQL", "Websocket"]) ? [name] : []).flatten()}'
id: httproute-external
template:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
labels: '${oc_merge(metadata.labels, {"openchoreo.dev/endpoint-name":
endpoint, "openchoreo.dev/endpoint-visibility": "external"})}'
name: ${oc_generate_name(metadata.componentName, endpoint)}
namespace: ${metadata.namespace}
spec:
hostnames: |
${[gateway.ingress.external.?http, gateway.ingress.external.?https]
.filter(g, g.hasValue()).map(g, g.value().host).distinct()
.map(h, metadata.environmentName + "-" + metadata.componentNamespace + "." + h)}
parentRefs:
- name: ${gateway.ingress.external.name}
namespace: ${gateway.ingress.external.namespace}
rules:
- backendRefs:
- name: ${metadata.componentName}
port: ${workload.endpoints[endpoint].port}
filters:
- type: URLRewrite
urlRewrite:
path:
replacePrefixMatch: '${workload.endpoints[endpoint].?basePath.orValue("")
!= "" ? workload.endpoints[endpoint].?basePath.orValue("") :
"/"}'
type: ReplacePrefixMatch
matches:
- path:
type: PathPrefix
value: /${metadata.componentName}-${endpoint}
var: endpoint
- forEach: '${workload.endpoints.transformList(name, ep, ("internal" in ep.visibility
&& ep.type in ["HTTP", "REST", "GraphQL", "Websocket"]) ? [name] : []).flatten()}'
id: httproute-internal
template:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
labels: '${oc_merge(metadata.labels, {"openchoreo.dev/endpoint-name":
endpoint, "openchoreo.dev/endpoint-visibility": "internal"})}'
name: ${oc_generate_name(metadata.componentName, endpoint, "internal")}
namespace: ${metadata.namespace}
spec:
hostnames: |
${[gateway.ingress.internal.?http, gateway.ingress.internal.?https]
.filter(g, g.hasValue()).map(g, g.value().host).distinct()
.map(h, metadata.environmentName + "-" + metadata.componentNamespace + "." + h)}
parentRefs:
- name: ${gateway.ingress.internal.name}
namespace: ${gateway.ingress.internal.namespace}
rules:
- backendRefs:
- name: ${metadata.componentName}
port: ${workload.endpoints[endpoint].port}
filters:
- type: URLRewrite
urlRewrite:
path:
replacePrefixMatch: '${workload.endpoints[endpoint].?basePath.orValue("")
!= "" ? workload.endpoints[endpoint].?basePath.orValue("") :
"/"}'
type: ReplacePrefixMatch
matches:
- path:
type: PathPrefix
value: /${metadata.componentName}-${endpoint}
var: endpoint
- forEach: ${configurations.toConfigEnvsByContainer()}
id: env-config
template:
apiVersion: v1
data: |
${envConfig.envs.transformMapEntry(index, env, {env.name: env.value})}
kind: ConfigMap
metadata:
name: ${envConfig.resourceName}
namespace: ${metadata.namespace}
var: envConfig
- forEach: ${configurations.toConfigFileList()}
id: file-config
template:
apiVersion: v1
data:
${config.name}: |
${config.value}
kind: ConfigMap
metadata:
name: ${config.resourceName}
namespace: ${metadata.namespace}
var: config
- forEach: ${configurations.toSecretEnvsByContainer()}
id: secret-env-external
template:
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: ${secretEnv.resourceName}
namespace: ${metadata.namespace}
spec:
data: |
${secretEnv.envs.map(secret, {
"secretKey": secret.name,
"remoteRef": {
"key": secret.remoteRef.key,
"property": has(secret.remoteRef.property) ? secret.remoteRef.property : oc_omit()
}
})}
refreshInterval: 15s
secretStoreRef:
kind: ClusterSecretStore
name: ${dataplane.secretStore}
target:
creationPolicy: Owner
name: ${secretEnv.resourceName}
var: secretEnv
- forEach: ${configurations.toSecretFileList()}
id: secret-file-external
template:
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: ${file.resourceName}
namespace: ${metadata.namespace}
spec:
data:
- remoteRef:
key: ${file.remoteRef.key}
property: |
${has(file.remoteRef.property) ? file.remoteRef.property : oc_omit()}
secretKey: ${file.name}
refreshInterval: 15s
secretStoreRef:
kind: ClusterSecretStore
name: ${dataplane.secretStore}
target:
creationPolicy: Owner
name: ${file.resourceName}
var: file
workloadType: deployment
owner:
componentName: collab-svc
projectName: doclet
workload:
container:
env:
- key: DOCLET_COLLAB_ADDR
value: :8090
image: host.k3d.internal:10082/doclet-collab-svc-image:v1-e0458407
dependencies:
endpoints:
- component: nats
envBindings:
address: DOCLET_NATS_URL
name: tcp
visibility: project
endpoints:
http:
port: 8090
type: HTTP
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ spec:
env:
- key: DOCLET_COLLAB_ADDR
value: :8090
image: temp-image-placeholder
image: host.k3d.internal:10082/doclet-collab-svc-image:v1-e0458407
dependencies:
endpoints:
- component: nats
envBindings:
address: DOCLET_NATS_URL
name: tcp
visibility: project
endpoints:
http:
type: HTTP
port: 8090
dependencies:
endpoints:
- component: nats
name: tcp
visibility: project
envBindings:
address: DOCLET_NATS_URL
type: HTTP
owner:
componentName: collab-svc
projectName: doclet