Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
dynamo
Commits
1e8b2866
Unverified
Commit
1e8b2866
authored
May 07, 2025
by
hhzhang16
Committed by
GitHub
May 07, 2025
Browse files
feat: add ingress to graph deployments (#960)
parent
a590d103
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
372 additions
and
24 deletions
+372
-24
deploy/cloud/helm/deploy.sh
deploy/cloud/helm/deploy.sh
+3
-1
deploy/cloud/helm/dynamo-platform-values.yaml
deploy/cloud/helm/dynamo-platform-values.yaml
+1
-0
deploy/cloud/helm/network-config-wizard.sh
deploy/cloud/helm/network-config-wizard.sh
+9
-1
deploy/cloud/helm/platform/components/operator/templates/deployment.yaml
...lm/platform/components/operator/templates/deployment.yaml
+3
-0
deploy/cloud/operator/cmd/main.go
deploy/cloud/operator/cmd/main.go
+5
-1
deploy/cloud/operator/internal/consts/consts.go
deploy/cloud/operator/internal/consts/consts.go
+1
-1
deploy/cloud/operator/internal/controller/dynamocomponentdeployment_controller.go
...ternal/controller/dynamocomponentdeployment_controller.go
+3
-3
deploy/cloud/operator/internal/controller/dynamographdeployment_controller.go
...r/internal/controller/dynamographdeployment_controller.go
+4
-1
deploy/cloud/operator/internal/controller_common/predicate.go
...oy/cloud/operator/internal/controller_common/predicate.go
+2
-0
deploy/cloud/operator/internal/dynamo/graph.go
deploy/cloud/operator/internal/dynamo/graph.go
+12
-10
deploy/cloud/operator/internal/dynamo/graph_test.go
deploy/cloud/operator/internal/dynamo/graph_test.go
+290
-1
deploy/helm/chart/templates/deployment.yaml
deploy/helm/chart/templates/deployment.yaml
+1
-1
deploy/sdk/src/dynamo/sdk/cli/serve_dynamo.py
deploy/sdk/src/dynamo/sdk/cli/serve_dynamo.py
+4
-4
deploy/sdk/src/dynamo/sdk/lib/service.py
deploy/sdk/src/dynamo/sdk/lib/service.py
+11
-0
deploy/sdk/src/dynamo/sdk/lib/utils.py
deploy/sdk/src/dynamo/sdk/lib/utils.py
+23
-0
No files found.
deploy/cloud/helm/deploy.sh
View file @
1e8b2866
...
...
@@ -36,6 +36,7 @@ export INGRESS_ENABLED="${INGRESS_ENABLED:=false}"
export
ISTIO_ENABLED
=
"
${
ISTIO_ENABLED
:
=false
}
"
export
ISTIO_GATEWAY
=
"
${
ISTIO_GATEWAY
:
=istio-system/istio-ingressgateway
}
"
export
INGRESS_CLASS
=
"
${
INGRESS_CLASS
:
=nginx
}
"
export
VIRTUAL_SERVICE_SUPPORTS_HTTPS
=
"
${
VIRTUAL_SERVICE_SUPPORTS_HTTPS
:
=false
}
"
# Add command line options
INTERACTIVE
=
false
...
...
@@ -140,8 +141,9 @@ echo "ISTIO_ENABLED: $ISTIO_ENABLED"
echo
"INGRESS_CLASS:
$INGRESS_CLASS
"
echo
"ISTIO_GATEWAY:
$ISTIO_GATEWAY
"
echo
"DYNAMO_INGRESS_SUFFIX:
$DYNAMO_INGRESS_SUFFIX
"
echo
"VIRTUAL_SERVICE_SUPPORTS_HTTPS:
$VIRTUAL_SERVICE_SUPPORTS_HTTPS
"
envsubst
'${NAMESPACE} ${RELEASE_NAME} ${DOCKER_USERNAME} ${DOCKER_PASSWORD} ${DOCKER_SERVER} ${IMAGE_TAG} ${DYNAMO_INGRESS_SUFFIX} ${PIPELINES_DOCKER_SERVER} ${PIPELINES_DOCKER_USERNAME} ${PIPELINES_DOCKER_PASSWORD} ${DOCKER_SECRET_NAME} ${INGRESS_ENABLED} ${ISTIO_ENABLED} ${INGRESS_CLASS} ${ISTIO_GATEWAY}'
< dynamo-platform-values.yaml
>
generated-values.yaml
envsubst
'${NAMESPACE} ${RELEASE_NAME} ${DOCKER_USERNAME} ${DOCKER_PASSWORD} ${DOCKER_SERVER} ${IMAGE_TAG} ${DYNAMO_INGRESS_SUFFIX} ${PIPELINES_DOCKER_SERVER} ${PIPELINES_DOCKER_USERNAME} ${PIPELINES_DOCKER_PASSWORD} ${DOCKER_SECRET_NAME} ${INGRESS_ENABLED} ${ISTIO_ENABLED} ${INGRESS_CLASS} ${ISTIO_GATEWAY}
${VIRTUAL_SERVICE_SUPPORTS_HTTPS}
'
< dynamo-platform-values.yaml
>
generated-values.yaml
echo
"generated file contents:"
cat
generated-values.yaml
...
...
deploy/cloud/helm/dynamo-platform-values.yaml
View file @
1e8b2866
...
...
@@ -40,6 +40,7 @@ dynamo-operator:
username
:
${PIPELINES_DOCKER_USERNAME}
password
:
${PIPELINES_DOCKER_PASSWORD}
imageBuildEngine
:
buildkit
virtualServiceSupportsHTTPS
:
${VIRTUAL_SERVICE_SUPPORTS_HTTPS}
dynamo-api-store
:
namespaceRestriction
:
...
...
deploy/cloud/helm/network-config-wizard.sh
View file @
1e8b2866
...
...
@@ -253,6 +253,14 @@ if [ "$CONFIG_TYPE" = "istio" ]; then
fi
fi
# Ask if the Istio gateway supports HTTPS
read
-p
"Does your Istio gateway support HTTPS? (y/n): "
SUPPORTS_HTTPS_REPLY
if
[[
"
$SUPPORTS_HTTPS_REPLY
"
=
~ ^[Yy]
$
]]
;
then
export
VIRTUAL_SERVICE_SUPPORTS_HTTPS
=
true
else
export
VIRTUAL_SERVICE_SUPPORTS_HTTPS
=
false
fi
elif
[
"
$CONFIG_TYPE
"
=
"ingress"
]
;
then
echo
-e
"
${
CYAN
}
Configuring Ingress settings...
${
NC
}
"
...
...
@@ -332,4 +340,4 @@ elif [ "$CONFIG_TYPE" = "ingress" ]; then
fi
print_header
"Wizard Complete"
echo
-e
"
${
GREEN
}
Network configuration complete!
${
NC
}
"
\ No newline at end of file
echo
-e
"
${
GREEN
}
Network configuration complete!
${
NC
}
"
deploy/cloud/helm/platform/components/operator/templates/deployment.yaml
View file @
1e8b2866
...
...
@@ -86,6 +86,9 @@ spec:
{{
- if .Values.dynamo.ingressHostSuffix
}}
-
--ingress-host-suffix={{ .Values.dynamo.ingressHostSuffix }}
{{
- end
}}
{{
- if .Values.dynamo.virtualServiceSupportsHTTPS
}}
-
--virtual-service-supports-https={{ .Values.dynamo.virtualServiceSupportsHTTPS }}
{{
- end
}}
command
:
-
/manager
...
...
deploy/cloud/operator/cmd/main.go
View file @
1e8b2866
...
...
@@ -71,6 +71,7 @@ func main() {
var
natsAddr
string
var
etcdAddr
string
var
istioVirtualServiceGateway
string
var
virtualServiceSupportsHTTPS
bool
var
ingressControllerClassName
string
var
ingressControllerTLSSecretName
string
var
ingressHostSuffix
string
...
...
@@ -91,6 +92,8 @@ func main() {
flag
.
StringVar
(
&
etcdAddr
,
"etcdAddr"
,
""
,
"address of the etcd server"
)
flag
.
StringVar
(
&
istioVirtualServiceGateway
,
"istio-virtual-service-gateway"
,
""
,
"The name of the istio virtual service gateway to use"
)
flag
.
BoolVar
(
&
virtualServiceSupportsHTTPS
,
"virtual-service-supports-https"
,
false
,
"If set, assume VirtualService endpoints are HTTPS"
)
flag
.
StringVar
(
&
ingressControllerClassName
,
"ingress-controller-class-name"
,
""
,
"The name of the ingress controller class to use"
)
flag
.
StringVar
(
&
ingressControllerTLSSecretName
,
"ingress-controller-tls-secret-name"
,
""
,
...
...
@@ -106,7 +109,8 @@ func main() {
utilruntime
.
Must
(
istioclientsetscheme
.
AddToScheme
(
scheme
))
ctrlConfig
:=
commonController
.
Config
{
RestrictedNamespace
:
restrictedNamespace
,
RestrictedNamespace
:
restrictedNamespace
,
VirtualServiceSupportsHTTPS
:
virtualServiceSupportsHTTPS
,
}
ctrl
.
SetLogger
(
zap
.
New
(
zap
.
UseFlagOptions
(
&
opts
)))
...
...
deploy/cloud/operator/internal/consts/consts.go
View file @
1e8b2866
...
...
@@ -24,7 +24,7 @@ const (
// nolint: gosec
EnvApiStoreApiToken
=
"API_STORE_API_TOKEN"
EnvDynamoServicePort
=
"PORT"
EnvDynamoServicePort
=
"
DYNAMO_
PORT"
EnvDockerRegistryServer
=
"DOCKER_REGISTRY_SERVER"
EnvDockerRegistrySecret
=
"DOCKER_REGISTRY_SECRET_NAME"
...
...
deploy/cloud/operator/internal/controller/dynamocomponentdeployment_controller.go
View file @
1e8b2866
...
...
@@ -740,7 +740,7 @@ func (r *DynamoComponentDeploymentReconciler) generateIngress(ctx context.Contex
Service
:
&
networkingv1
.
IngressServiceBackend
{
Name
:
opt
.
dynamoComponentDeployment
.
Name
,
Port
:
networkingv1
.
ServiceBackendPort
{
Number
:
3000
,
Number
:
commonconsts
.
DynamoServicePort
,
},
},
},
...
...
@@ -800,7 +800,7 @@ func (r *DynamoComponentDeploymentReconciler) generateVirtualService(ctx context
Destination
:
&
istioNetworking
.
Destination
{
Host
:
opt
.
dynamoComponentDeployment
.
Name
,
Port
:
&
istioNetworking
.
PortSelector
{
Number
:
3000
,
Number
:
commonconsts
.
DynamoServicePort
,
},
},
},
...
...
@@ -1121,7 +1121,7 @@ func (r *DynamoComponentDeploymentReconciler) generatePodTemplateSpec(ctx contex
// todo : remove this line when https://github.com/ai-dynamo/dynamo/issues/345 is fixed
enableDependsOption
:=
false
if
len
(
opt
.
dynamoComponentDeployment
.
Spec
.
ExternalServices
)
>
0
&&
enableDependsOption
{
serviceSuffix
:=
fmt
.
Sprintf
(
"%s.svc.cluster.local:
3000
"
,
opt
.
dynamoComponentDeployment
.
Namespace
)
serviceSuffix
:=
fmt
.
Sprintf
(
"%s.svc.cluster.local:
%d
"
,
opt
.
dynamoComponentDeployment
.
Namespace
,
containerPort
)
keys
:=
make
([]
string
,
0
,
len
(
opt
.
dynamoComponentDeployment
.
Spec
.
ExternalServices
))
for
key
:=
range
opt
.
dynamoComponentDeployment
.
Spec
.
ExternalServices
{
...
...
deploy/cloud/operator/internal/controller/dynamographdeployment_controller.go
View file @
1e8b2866
...
...
@@ -143,7 +143,7 @@ func (r *DynamoGraphDeploymentReconciler) Reconcile(ctx context.Context, req ctr
}
}
if
deployment
.
Spec
.
Ingress
.
Enabled
{
dynamoDeployment
.
SetEndpointStatus
(
(
r
.
isEndpointSecured
()
)
,
getIngressHost
(
deployment
.
Spec
.
Ingress
))
dynamoDeployment
.
SetEndpointStatus
(
r
.
isEndpointSecured
(),
getIngressHost
(
deployment
.
Spec
.
Ingress
))
}
}
...
...
@@ -238,6 +238,9 @@ func (r *DynamoGraphDeploymentReconciler) generateDefaultIngressSpec(dynamoDeplo
}
func
(
r
*
DynamoGraphDeploymentReconciler
)
isEndpointSecured
()
bool
{
if
r
.
VirtualServiceGateway
!=
""
&&
r
.
Config
.
VirtualServiceSupportsHTTPS
{
return
true
}
return
r
.
IngressControllerTLSSecret
!=
""
}
...
...
deploy/cloud/operator/internal/controller_common/predicate.go
View file @
1e8b2866
...
...
@@ -30,6 +30,8 @@ import (
type
Config
struct
{
// Enable resources filtering, only the resources belonging to the given namespace will be handled.
RestrictedNamespace
string
// If true, assume VirtualService endpoints are HTTPS
VirtualServiceSupportsHTTPS
bool
}
func
EphemeralDeploymentEventFilter
(
config
Config
)
predicate
.
Predicate
{
...
...
deploy/cloud/operator/internal/dynamo/graph.go
View file @
1e8b2866
...
...
@@ -66,10 +66,12 @@ type Autoscaling struct {
}
type
Config
struct
{
Dynamo
*
DynamoConfig
`yaml:"dynamo,omitempty"`
Resources
*
Resources
`yaml:"resources,omitempty"`
Traffic
*
Traffic
`yaml:"traffic,omitempty"`
Autoscaling
*
Autoscaling
`yaml:"autoscaling,omitempty"`
Dynamo
*
DynamoConfig
`yaml:"dynamo,omitempty"`
Resources
*
Resources
`yaml:"resources,omitempty"`
Traffic
*
Traffic
`yaml:"traffic,omitempty"`
Autoscaling
*
Autoscaling
`yaml:"autoscaling,omitempty"`
HttpExposed
bool
`yaml:"http_exposed,omitempty"`
ApiEndpoints
[]
string
`yaml:"api_endpoints,omitempty"`
}
type
ServiceConfig
struct
{
...
...
@@ -250,13 +252,13 @@ func GenerateDynamoComponentsDeployments(ctx context.Context, parentDynamoGraphD
deployment
.
Spec
.
DynamoNamespace
=
&
dynamoNamespace
dynamoServices
[
service
.
Name
]
=
fmt
.
Sprintf
(
"%s/%s"
,
service
.
Config
.
Dynamo
.
Name
,
dynamoNamespace
)
labels
[
commonconsts
.
KubeLabelDynamoNamespace
]
=
dynamoNamespace
}
else
{
// dynamo is not enabled
if
config
.
EntryService
==
service
.
Name
{
// enable virtual service for the entry service
deployment
.
Spec
.
Ingress
=
*
ingressSpec
}
}
// Check http_exposed independently
if
config
.
EntryService
==
service
.
Name
&&
service
.
Config
.
HttpExposed
{
deployment
.
Spec
.
Ingress
=
*
ingressSpec
// TODO (maybe): add paths to IngressSpec
}
if
service
.
Config
.
Resources
!=
nil
{
deployment
.
Spec
.
Resources
=
&
compounaiCommon
.
Resources
{
Requests
:
&
compounaiCommon
.
ResourceItem
{
...
...
deploy/cloud/operator/internal/dynamo/graph_test.go
View file @
1e8b2866
...
...
@@ -182,6 +182,7 @@ func TestGenerateDynamoComponentsDeployments(t *testing.T) {
Name
:
"service1"
,
Dependencies
:
[]
map
[
string
]
string
{{
"service"
:
"service2"
}},
Config
:
Config
{
HttpExposed
:
true
,
Resources
:
&
Resources
{
CPU
:
"1"
,
Memory
:
"1Gi"
,
...
...
@@ -260,6 +261,10 @@ func TestGenerateDynamoComponentsDeployments(t *testing.T) {
},
},
},
Status
:
v1alpha1
.
DynamoComponentDeploymentStatus
{
Conditions
:
nil
,
PodSelector
:
nil
,
},
},
"service2"
:
{
ObjectMeta
:
metav1
.
ObjectMeta
{
...
...
@@ -283,6 +288,18 @@ func TestGenerateDynamoComponentsDeployments(t *testing.T) {
commonconsts
.
KubeLabelDynamoComponent
:
"service2"
,
commonconsts
.
KubeLabelDynamoNamespace
:
"default"
,
},
Ingress
:
v1alpha1
.
IngressSpec
{
Enabled
:
false
,
Host
:
""
,
UseVirtualService
:
false
,
VirtualServiceGateway
:
nil
,
HostPrefix
:
nil
,
Annotations
:
nil
,
Labels
:
nil
,
TLS
:
nil
,
HostSuffix
:
nil
,
IngressControllerClassName
:
nil
,
},
},
},
},
...
...
@@ -309,6 +326,7 @@ func TestGenerateDynamoComponentsDeployments(t *testing.T) {
Name
:
"service1"
,
Dependencies
:
[]
map
[
string
]
string
{{
"service"
:
"service2"
}},
Config
:
Config
{
HttpExposed
:
true
,
Resources
:
&
Resources
{
CPU
:
"1"
,
Memory
:
"1Gi"
,
...
...
@@ -374,12 +392,27 @@ func TestGenerateDynamoComponentsDeployments(t *testing.T) {
DeploymentSelectorValue
:
"service2/dynamo-test-dynamographdeployment"
,
},
},
Ingress
:
v1alpha1
.
IngressSpec
{},
Ingress
:
v1alpha1
.
IngressSpec
{
Enabled
:
false
,
Host
:
""
,
UseVirtualService
:
false
,
VirtualServiceGateway
:
nil
,
HostPrefix
:
nil
,
Annotations
:
nil
,
Labels
:
nil
,
TLS
:
nil
,
HostSuffix
:
nil
,
IngressControllerClassName
:
nil
,
},
Labels
:
map
[
string
]
string
{
commonconsts
.
KubeLabelDynamoComponent
:
"service1"
,
},
},
},
Status
:
v1alpha1
.
DynamoComponentDeploymentStatus
{
Conditions
:
nil
,
PodSelector
:
nil
,
},
},
"service2"
:
{
ObjectMeta
:
metav1
.
ObjectMeta
{
...
...
@@ -403,6 +436,18 @@ func TestGenerateDynamoComponentsDeployments(t *testing.T) {
commonconsts
.
KubeLabelDynamoComponent
:
"service2"
,
commonconsts
.
KubeLabelDynamoNamespace
:
"dynamo-test-dynamographdeployment"
,
},
Ingress
:
v1alpha1
.
IngressSpec
{
Enabled
:
false
,
Host
:
""
,
UseVirtualService
:
false
,
VirtualServiceGateway
:
nil
,
HostPrefix
:
nil
,
Annotations
:
nil
,
Labels
:
nil
,
TLS
:
nil
,
HostSuffix
:
nil
,
IngressControllerClassName
:
nil
,
},
},
},
},
...
...
@@ -462,6 +507,250 @@ func TestGenerateDynamoComponentsDeployments(t *testing.T) {
},
wantErr
:
true
,
},
{
name
:
"Test GenerateDynamoComponentsDeployments ingress enabled by default"
,
args
:
args
{
parentDynamoGraphDeployment
:
&
v1alpha1
.
DynamoGraphDeployment
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"test-dynamographdeployment"
,
Namespace
:
"default"
,
},
Spec
:
v1alpha1
.
DynamoGraphDeploymentSpec
{
DynamoGraph
:
"dynamocomponent:ac4e234"
,
},
},
config
:
&
DynamoGraphConfig
{
DynamoTag
:
"dynamocomponent:MyServiceIngressEnabled"
,
EntryService
:
"service1"
,
Services
:
[]
ServiceConfig
{
{
Name
:
"service1"
,
Config
:
Config
{
HttpExposed
:
true
,
},
},
},
},
ingressSpec
:
&
v1alpha1
.
IngressSpec
{
Enabled
:
true
,
Host
:
"test-dynamographdeployment"
,
},
},
want
:
map
[
string
]
*
v1alpha1
.
DynamoComponentDeployment
{
"service1"
:
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"test-dynamographdeployment-service1"
,
Namespace
:
"default"
,
Labels
:
map
[
string
]
string
{
commonconsts
.
KubeLabelDynamoComponent
:
"service1"
,
},
},
Spec
:
v1alpha1
.
DynamoComponentDeploymentSpec
{
DynamoComponent
:
"dynamocomponent:ac4e234"
,
DynamoTag
:
"dynamocomponent:MyServiceIngressEnabled"
,
DynamoComponentDeploymentSharedSpec
:
v1alpha1
.
DynamoComponentDeploymentSharedSpec
{
Annotations
:
nil
,
Labels
:
map
[
string
]
string
{
commonconsts
.
KubeLabelDynamoComponent
:
"service1"
,
},
ServiceName
:
"service1"
,
DynamoNamespace
:
nil
,
Resources
:
nil
,
Autoscaling
:
&
v1alpha1
.
Autoscaling
{
Enabled
:
false
,
MinReplicas
:
0
,
MaxReplicas
:
0
,
Behavior
:
nil
,
Metrics
:
nil
,
},
Envs
:
nil
,
EnvFromSecret
:
nil
,
PVC
:
nil
,
RunMode
:
nil
,
ExternalServices
:
nil
,
Ingress
:
v1alpha1
.
IngressSpec
{
Enabled
:
true
,
Host
:
"test-dynamographdeployment"
,
},
ExtraPodMetadata
:
nil
,
ExtraPodSpec
:
nil
,
LivenessProbe
:
nil
,
ReadinessProbe
:
nil
,
Replicas
:
nil
,
},
},
Status
:
v1alpha1
.
DynamoComponentDeploymentStatus
{
Conditions
:
nil
,
PodSelector
:
nil
,
},
},
},
wantErr
:
false
,
},
{
name
:
"Test GenerateDynamoComponentsDeployments ingress explicitly disabled"
,
args
:
args
{
parentDynamoGraphDeployment
:
&
v1alpha1
.
DynamoGraphDeployment
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"test-dynamographdeployment"
,
Namespace
:
"default"
,
},
Spec
:
v1alpha1
.
DynamoGraphDeploymentSpec
{
DynamoGraph
:
"dynamocomponent:ac4e234"
,
},
},
config
:
&
DynamoGraphConfig
{
DynamoTag
:
"dynamocomponent:MyServiceIngressDisabled"
,
Services
:
[]
ServiceConfig
{
{
Name
:
"service1"
,
Config
:
Config
{},
},
},
},
ingressSpec
:
&
v1alpha1
.
IngressSpec
{
Enabled
:
false
,
},
},
want
:
map
[
string
]
*
v1alpha1
.
DynamoComponentDeployment
{
"service1"
:
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"test-dynamographdeployment-service1"
,
Namespace
:
"default"
,
Labels
:
map
[
string
]
string
{
commonconsts
.
KubeLabelDynamoComponent
:
"service1"
,
},
},
Spec
:
v1alpha1
.
DynamoComponentDeploymentSpec
{
DynamoComponent
:
"dynamocomponent:ac4e234"
,
DynamoTag
:
"dynamocomponent:MyServiceIngressDisabled"
,
DynamoComponentDeploymentSharedSpec
:
v1alpha1
.
DynamoComponentDeploymentSharedSpec
{
Annotations
:
nil
,
Labels
:
map
[
string
]
string
{
commonconsts
.
KubeLabelDynamoComponent
:
"service1"
,
},
ServiceName
:
"service1"
,
DynamoNamespace
:
nil
,
Resources
:
nil
,
Autoscaling
:
&
v1alpha1
.
Autoscaling
{
Enabled
:
false
,
MinReplicas
:
0
,
MaxReplicas
:
0
,
Behavior
:
nil
,
Metrics
:
nil
,
},
Envs
:
nil
,
EnvFromSecret
:
nil
,
PVC
:
nil
,
RunMode
:
nil
,
ExternalServices
:
nil
,
Ingress
:
v1alpha1
.
IngressSpec
{
Enabled
:
false
,
Host
:
""
,
UseVirtualService
:
false
,
VirtualServiceGateway
:
nil
,
HostPrefix
:
nil
,
Annotations
:
nil
,
Labels
:
nil
,
TLS
:
nil
,
HostSuffix
:
nil
,
IngressControllerClassName
:
nil
,
},
ExtraPodMetadata
:
nil
,
ExtraPodSpec
:
nil
,
LivenessProbe
:
nil
,
ReadinessProbe
:
nil
,
Replicas
:
nil
,
},
},
Status
:
v1alpha1
.
DynamoComponentDeploymentStatus
{
Conditions
:
nil
,
PodSelector
:
nil
,
},
},
},
wantErr
:
false
,
},
{
name
:
"Test GenerateDynamoComponentsDeployments ingress custom host"
,
args
:
args
{
parentDynamoGraphDeployment
:
&
v1alpha1
.
DynamoGraphDeployment
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"test-dynamographdeployment"
,
Namespace
:
"default"
,
},
Spec
:
v1alpha1
.
DynamoGraphDeploymentSpec
{
DynamoGraph
:
"dynamocomponent:ac4e234"
,
},
},
config
:
&
DynamoGraphConfig
{
DynamoTag
:
"dynamocomponent:MyServiceIngressCustomHost"
,
EntryService
:
"service1"
,
Services
:
[]
ServiceConfig
{
{
Name
:
"service1"
,
Config
:
Config
{
HttpExposed
:
true
,
},
},
},
},
ingressSpec
:
&
v1alpha1
.
IngressSpec
{
Enabled
:
true
,
Host
:
"custom-host"
,
},
},
want
:
map
[
string
]
*
v1alpha1
.
DynamoComponentDeployment
{
"service1"
:
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"test-dynamographdeployment-service1"
,
Namespace
:
"default"
,
Labels
:
map
[
string
]
string
{
commonconsts
.
KubeLabelDynamoComponent
:
"service1"
,
},
},
Spec
:
v1alpha1
.
DynamoComponentDeploymentSpec
{
DynamoComponent
:
"dynamocomponent:ac4e234"
,
DynamoTag
:
"dynamocomponent:MyServiceIngressCustomHost"
,
DynamoComponentDeploymentSharedSpec
:
v1alpha1
.
DynamoComponentDeploymentSharedSpec
{
Annotations
:
nil
,
Labels
:
map
[
string
]
string
{
commonconsts
.
KubeLabelDynamoComponent
:
"service1"
,
},
ServiceName
:
"service1"
,
DynamoNamespace
:
nil
,
Resources
:
nil
,
Autoscaling
:
&
v1alpha1
.
Autoscaling
{
Enabled
:
false
,
MinReplicas
:
0
,
MaxReplicas
:
0
,
Behavior
:
nil
,
Metrics
:
nil
,
},
Envs
:
nil
,
EnvFromSecret
:
nil
,
PVC
:
nil
,
RunMode
:
nil
,
ExternalServices
:
nil
,
Ingress
:
v1alpha1
.
IngressSpec
{
Enabled
:
true
,
Host
:
"custom-host"
,
},
ExtraPodMetadata
:
nil
,
ExtraPodSpec
:
nil
,
LivenessProbe
:
nil
,
ReadinessProbe
:
nil
,
Replicas
:
nil
,
},
},
Status
:
v1alpha1
.
DynamoComponentDeploymentStatus
{
Conditions
:
nil
,
PodSelector
:
nil
,
},
},
},
wantErr
:
false
,
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
...
...
deploy/helm/chart/templates/deployment.yaml
View file @
1e8b2866
...
...
@@ -86,7 +86,7 @@ spec:
-
name
:
WORKERS
value
:
"
{{
.config.workers
}}"
{{
- end
}}
-
name
:
PORT
-
name
:
DYNAMO_
PORT
value
:
"
3000"
{{
- if $.Values.natsAddr
}}
-
name
:
NATS_SERVER
...
...
deploy/sdk/src/dynamo/sdk/cli/serve_dynamo.py
View file @
1e8b2866
...
...
@@ -37,6 +37,7 @@ from dynamo.runtime import DistributedRuntime, dynamo_endpoint, dynamo_worker
from
dynamo.sdk
import
dynamo_context
from
dynamo.sdk.cli.utils
import
append_dynamo_state
from
dynamo.sdk.lib.service
import
LinkedServices
from
dynamo.sdk.lib.utils
import
get_host_port
logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -313,16 +314,15 @@ def main(
if
added_routes
:
# Configure uvicorn with graceful shutdown
# get the port from PORT env var or use 8000 as default
port
=
int
(
os
.
environ
.
get
(
"PORT"
,
8000
))
host
,
port
=
get_host_port
()
config
=
uvicorn
.
Config
(
service
.
app
,
host
=
"0.0.0.0"
,
port
=
port
,
log_level
=
"info"
service
.
app
,
host
=
host
,
port
=
port
,
log_level
=
"info"
)
server
=
uvicorn
.
Server
(
config
)
# Start the server with graceful shutdown handling
logger
.
info
(
f
"Starting FastAPI server on
0.0.0.0:
{
port
}
with routes:
{
added_routes
}
"
f
"Starting FastAPI server on
{
config
.
host
}
:
{
config
.
port
}
with routes:
{
added_routes
}
"
)
server
.
run
()
else
:
...
...
deploy/sdk/src/dynamo/sdk/lib/service.py
View file @
1e8b2866
...
...
@@ -133,10 +133,21 @@ class DynamoService(Service[T]):
# Register Dynamo endpoints
self
.
_dynamo_endpoints
:
Dict
[
str
,
DynamoEndpoint
]
=
{}
self
.
_api_endpoints
:
list
[
str
]
=
[]
for
field
in
dir
(
inner
):
value
=
getattr
(
inner
,
field
)
if
isinstance
(
value
,
DynamoEndpoint
):
self
.
_dynamo_endpoints
[
value
.
name
]
=
value
if
getattr
(
value
,
"is_api"
,
False
):
# Ensure endpoint path starts with '/'
path
=
(
value
.
name
if
value
.
name
.
startswith
(
"/"
)
else
f
"/
{
value
.
name
}
"
)
self
.
_api_endpoints
.
append
(
path
)
# If any API endpoints exist, mark service as HTTP-exposed and list endpoints
if
self
.
_api_endpoints
:
self
.
config
[
"http_exposed"
]
=
True
self
.
config
[
"api_endpoints"
]
=
self
.
_api_endpoints
.
copy
()
self
.
_linked_services
:
List
[
DynamoService
]
=
[]
# Track linked services
...
...
deploy/sdk/src/dynamo/sdk/lib/utils.py
0 → 100644
View file @
1e8b2866
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import
os
def
get_host_port
():
"""Gets host and port from environment variables. Defaults to 0.0.0.0:8000."""
port
=
int
(
os
.
environ
.
get
(
"DYNAMO_PORT"
,
8000
))
host
=
os
.
environ
.
get
(
"DYNAMO_HOST"
,
"0.0.0.0"
)
return
host
,
port
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment