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
5ddc7f7d
Commit
5ddc7f7d
authored
Mar 04, 2025
by
Maksim Khadkevich
Committed by
GitHub
Mar 04, 2025
Browse files
feat: moved compoundAI operator, APIserver, and examples (#10)
parent
14ce7e03
Changes
239
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
2196 additions
and
0 deletions
+2196
-0
Earthfile
Earthfile
+50
-0
deploy/compoundai/api-server/.air.toml
deploy/compoundai/api-server/.air.toml
+66
-0
deploy/compoundai/api-server/.env
deploy/compoundai/api-server/.env
+14
-0
deploy/compoundai/api-server/.gitignore
deploy/compoundai/api-server/.gitignore
+14
-0
deploy/compoundai/api-server/Dockerfile
deploy/compoundai/api-server/Dockerfile
+49
-0
deploy/compoundai/api-server/Earthfile
deploy/compoundai/api-server/Earthfile
+35
-0
deploy/compoundai/api-server/api/common/client/client.go
deploy/compoundai/api-server/api/common/client/client.go
+67
-0
deploy/compoundai/api-server/api/common/consts/consts.go
deploy/compoundai/api-server/api/common/consts/consts.go
+38
-0
deploy/compoundai/api-server/api/common/consts/k8s.go
deploy/compoundai/api-server/api/common/consts/k8s.go
+26
-0
deploy/compoundai/api-server/api/common/env/env.go
deploy/compoundai/api-server/api/common/env/env.go
+40
-0
deploy/compoundai/api-server/api/common/env/nds.go
deploy/compoundai/api-server/api/common/env/nds.go
+64
-0
deploy/compoundai/api-server/api/common/env/scope.go
deploy/compoundai/api-server/api/common/env/scope.go
+60
-0
deploy/compoundai/api-server/api/common/utils/utils.go
deploy/compoundai/api-server/api/common/utils/utils.go
+31
-0
deploy/compoundai/api-server/api/controllers/cluster.go
deploy/compoundai/api-server/api/controllers/cluster.go
+157
-0
deploy/compoundai/api-server/api/controllers/common.go
deploy/compoundai/api-server/api/controllers/common.go
+42
-0
deploy/compoundai/api-server/api/controllers/compound_component.go
...mpoundai/api-server/api/controllers/compound_component.go
+194
-0
deploy/compoundai/api-server/api/controllers/deployment.go
deploy/compoundai/api-server/api/controllers/deployment.go
+1051
-0
deploy/compoundai/api-server/api/controllers/deployment_revision.go
...poundai/api-server/api/controllers/deployment_revision.go
+126
-0
deploy/compoundai/api-server/api/controllers/health.go
deploy/compoundai/api-server/api/controllers/health.go
+32
-0
deploy/compoundai/api-server/api/controllers/info.go
deploy/compoundai/api-server/api/controllers/info.go
+40
-0
No files found.
Earthfile
0 → 100644
View file @
5ddc7f7d
# SPDX-FileCopyrightText: Copyright (c) 2024-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.
VERSION 0.8
############### ARTIFACTS TARGETS ##############################
# These targets are invoked in child Earthfiles to pass top-level files that are out of their build context
# https://docs.earthly.dev/earthly-0.6/best-practices#copying-files-from-outside-the-build-context
############### SHARED LIBRARY TARGETS ##############################
golang-base:
FROM golang:1.23
RUN apt-get update && apt-get install -y git && apt-get clean && rm -rf /var/lib/apt/lists/* && curl -sSfL https://github.com/golangci/golangci-lint/releases/download/v1.61.0/golangci-lint-1.61.0-linux-amd64.tar.gz | tar -xzv && mv golangci-lint-1.61.0-linux-amd64/golangci-lint /usr/local/bin/
############### ALL TARGETS ##############################
all-test:
BUILD ./deploy/compoundai/operator+test
# BUILD ./deploy/compoundai/api-server+test #TODO: mkhadkevich earthly tests fail https://gitlab-master.nvidia.com/aire/microservices/compoundai/-/jobs/144475821
all-docker:
ARG CI_REGISTRY_IMAGE=my-registry
ARG CI_COMMIT_SHA=latest
BUILD ./deploy/compoundai/operator+docker --CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE --CI_COMMIT_SHA=$CI_COMMIT_SHA
BUILD ./deploy/compoundai/api-server+docker --CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE --CI_COMMIT_SHA=$CI_COMMIT_SHA
all-lint:
BUILD ./deploy/compoundai/operator+lint
all:
BUILD +all-test
BUILD +all-docker
BUILD +all-lint
# For testing
custom:
ARG CI_REGISTRY_IMAGE=my-registry
ARG CI_COMMIT_SHA=latest
BUILD +all-test
deploy/compoundai/api-server/.air.toml
0 → 100644
View file @
5ddc7f7d
# SPDX-FileCopyrightText: Copyright (c) 2024-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.
root
=
"."
testdata_dir
=
"testdata"
tmp_dir
=
"tmp"
[build]
args_bin
=
[]
bin
=
"./tmp/main"
cmd
=
"go build -o ./tmp/main ./api"
delay
=
1000
exclude_dir
=
[
"assets"
,
"tmp"
,
"vendor"
,
"testdata"
]
exclude_file
=
[]
exclude_regex
=
["_test.go"]
exclude_unchanged
=
false
follow_symlink
=
false
full_bin
=
""
include_dir
=
[]
include_ext
=
[
"go"
,
"tpl"
,
"tmpl"
,
"html"
]
include_file
=
[]
kill_delay
=
"0s"
log
=
"build-errors.log"
poll
=
false
poll_interval
=
0
post_cmd
=
[]
pre_cmd
=
[]
rerun
=
false
rerun_delay
=
500
send_interrupt
=
false
stop_on_error
=
false
[color]
app
=
""
build
=
"yellow"
main
=
"magenta"
runner
=
"green"
watcher
=
"cyan"
[log]
main_only
=
false
time
=
false
[misc]
clean_on_exit
=
false
[proxy]
app_port
=
0
enabled
=
false
proxy_port
=
0
[screen]
clear_on_rebuild
=
false
keep_scroll
=
true
deploy/compoundai/api-server/.env
0 → 100644
View file @
5ddc7f7d
# Local development env
DB_USER="postgres"
DB_PASSWORD="pgadmin"
DB_HOST="localhost"
DB_PORT=5432
DB_NAME="postgres"
DMS_HOST="localhost"
DMS_PORT=8080
NDS_HOST="localhost"
NDS_PORT=8001
DEFAULT_KUBE_NAMESPACE="compoundai"
deploy/compoundai/api-server/.gitignore
0 → 100644
View file @
5ddc7f7d
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin/*
Dockerfile.cross
# Test binary, built with `go test -c`
*.test
# Temporary folder used by Air
tmp
\ No newline at end of file
deploy/compoundai/api-server/Dockerfile
0 → 100644
View file @
5ddc7f7d
# SPDX-FileCopyrightText: Copyright (c) 2024-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.
# Build the manager binary
FROM
golang:1.23 AS builder
ARG
TARGETOS
ARG
TARGETARCH
WORKDIR
/workspace
# Copy the Go Modules manifests
COPY
go.mod go.mod
COPY
go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN
go mod download
# Copy the go source
COPY
api/ api/
COPY
.env .env
# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN
CGO_ENABLED
=
0
GOOS
=
${
TARGETOS
:-
linux
}
GOARCH
=
${
TARGETARCH
}
go build
-a
-o
server api/main.go
# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM
gcr.io/distroless/static:nonroot
WORKDIR
/
COPY
--from=builder /workspace/server .
COPY
--from=builder /workspace/.env .
USER
65532:65532
ENTRYPOINT
["/server"]
deploy/compoundai/api-server/Earthfile
0 → 100644
View file @
5ddc7f7d
VERSION 0.8
build:
FROM golang:1.23
ARG TARGETOS
ARG TARGETARCH
WORKDIR /workspace
COPY go.mod go.mod
COPY go.sum go.sum
RUN go mod download
COPY api/ api/
COPY .env .env
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o server api/main.go
SAVE ARTIFACT /workspace/server
SAVE ARTIFACT /workspace/.env
#TODO: mkhadkevich earthly tests fail https://gitlab-master.nvidia.com/aire/microservices/compoundai/-/jobs/144475821
#test:
# FROM +build
# # copy test files
# COPY tests/ tests/
# RUN go test ./...
docker:
ARG CI_REGISTRY_IMAGE=my-registry
ARG CI_COMMIT_SHA=latest
ARG IMAGE=compound-api-server
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY +build/server .
COPY +build/.env .
USER 65532:65532
ENTRYPOINT ["/server"]
SAVE IMAGE --push $CI_REGISTRY_IMAGE/$IMAGE:$CI_COMMIT_SHA
\ No newline at end of file
deploy/compoundai/api-server/api/common/client/client.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
client
import
(
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func
SendRequestJSON
(
url
string
,
method
string
,
body
*
any
)
(
*
http
.
Response
,
[]
byte
,
error
)
{
var
req
*
http
.
Request
var
err
error
if
body
!=
nil
{
jsonData
,
err
:=
json
.
Marshal
(
body
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"failed to marshal request: %v"
,
err
)
}
req
,
err
=
http
.
NewRequest
(
method
,
url
,
bytes
.
NewBuffer
(
jsonData
))
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"failed to create request: %v"
,
err
)
}
}
else
{
req
,
err
=
http
.
NewRequest
(
method
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"failed to create request: %v"
,
err
)
}
}
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
client
:=
&
http
.
Client
{}
resp
,
err
:=
client
.
Do
(
req
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"failed to send request: %v"
,
err
)
}
defer
resp
.
Body
.
Close
()
respBody
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
nil
,
nil
,
fmt
.
Errorf
(
"received non-OK response: %v, %s"
,
resp
.
Status
,
respBody
)
}
return
resp
,
respBody
,
nil
}
deploy/compoundai/api-server/api/common/consts/consts.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
consts
import
(
"errors"
"gorm.io/gorm"
)
var
(
ErrNotFound
=
gorm
.
ErrRecordNotFound
ErrNoPermission
=
errors
.
New
(
"no permission"
)
ErrEmptyData
=
errors
.
New
(
"data is nil"
)
ErrNoImplemented
=
errors
.
New
(
"no implemented"
)
ErrTimeout
=
errors
.
New
(
"timeout"
)
YataiOrganizationHeaderName
=
"X-Yatai-Organization"
NgcOrganizationHeaderName
=
"Nv-Ngc-Org"
NgcUserHeaderName
=
"Nv-Actor-Id"
CompoundNimContainerPortName
=
"http"
)
deploy/compoundai/api-server/api/common/consts/k8s.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
consts
const
(
KubeLabelCompoundNim
=
"yatai.ai/bento-repository"
KubeLabelCompoundNimVersion
=
"yatai.ai/bento"
KubeLabelCompoundNimVersionDeployment
=
"yatai.ai/bento-deployment"
KubeImageBuilderMainContainer
=
"builder"
)
deploy/compoundai/api-server/api/common/env/env.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
env
import
(
"github.com/joho/godotenv"
"github.com/rs/zerolog/log"
)
func
SetupEnv
()
{
err
:=
godotenv
.
Load
()
if
err
!=
nil
{
log
.
Fatal
()
.
Msgf
(
"Failed to load env during setup %s"
,
err
.
Error
())
}
_
,
err
=
SetResourceScope
()
if
err
!=
nil
{
log
.
Fatal
()
.
Msgf
(
"Failed to set resource scope during env setup %s"
,
err
.
Error
())
}
_
,
err
=
SetNdsHost
()
if
err
!=
nil
{
log
.
Fatal
()
.
Msgf
(
"Failed to set nds urls during env setup %s"
,
err
.
Error
())
}
}
deploy/compoundai/api-server/api/common/env/nds.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
env
import
(
"fmt"
"sync"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/common/utils"
)
var
(
NdsHostBase
string
once
sync
.
Once
)
func
GetNdsUrl
()
string
{
baseUrl
:=
GetNdsHost
()
return
fmt
.
Sprintf
(
"http://%s"
,
baseUrl
)
}
func
GetNdsHost
()
string
{
return
NdsHostBase
}
func
SetNdsHost
()
(
string
,
error
)
{
var
err
error
once
.
Do
(
func
()
{
// We cache and reuse the same NDS host
NDS_HOST
,
syncErr
:=
utils
.
MustGetEnv
(
"NDS_HOST"
)
if
syncErr
!=
nil
{
err
=
syncErr
return
}
NDS_PORT
,
syncErr
:=
utils
.
MustGetEnv
(
"NDS_PORT"
)
if
syncErr
!=
nil
{
err
=
syncErr
return
}
NdsHostBase
=
fmt
.
Sprintf
(
"%s:%s"
,
NDS_HOST
,
NDS_PORT
)
})
if
err
!=
nil
{
return
""
,
err
}
return
NdsHostBase
,
nil
}
deploy/compoundai/api-server/api/common/env/scope.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
env
import
(
"fmt"
"os"
"sync"
)
type
ResourceScope
string
const
(
OrganizationScope
ResourceScope
=
"organization"
UserScope
ResourceScope
=
"user"
)
var
(
ApplicationScope
ResourceScope
getScopeOnce
sync
.
Once
)
func
SetResourceScope
()
(
ResourceScope
,
error
)
{
var
err
error
getScopeOnce
.
Do
(
func
()
{
scope
:=
os
.
Getenv
(
"RESOURCE_SCOPE"
)
if
scope
==
""
{
scope
=
string
(
UserScope
)
}
switch
ResourceScope
(
scope
)
{
case
OrganizationScope
,
UserScope
:
ApplicationScope
=
ResourceScope
(
scope
)
default
:
err
=
fmt
.
Errorf
(
"invalid scope value: %s"
,
scope
)
return
}
})
if
err
!=
nil
{
return
""
,
err
}
return
ApplicationScope
,
nil
}
deploy/compoundai/api-server/api/common/utils/utils.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
utils
import
(
"fmt"
"os"
)
func
MustGetEnv
(
key
string
)
(
string
,
error
)
{
value
:=
os
.
Getenv
(
key
)
if
value
==
""
{
return
""
,
fmt
.
Errorf
(
"environment variable %s is not set"
,
key
)
}
return
value
,
nil
}
deploy/compoundai/api-server/api/controllers/cluster.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
controllers
import
(
"fmt"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/converters"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/models"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/schemas"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/services"
)
type
clusterController
struct
{}
var
ClusterController
=
clusterController
{}
func
(
s
*
clusterController
)
GetCluster
(
ctx
*
gin
.
Context
,
clusterName
string
)
(
*
models
.
Cluster
,
error
)
{
ownership
,
err
:=
GetOwnershipInfo
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
}
cluster
,
err
:=
services
.
ClusterService
.
GetByName
(
ctx
,
ownership
.
OrganizationId
,
clusterName
)
if
err
!=
nil
{
return
nil
,
err
}
return
cluster
,
nil
}
func
(
c
*
clusterController
)
Create
(
ctx
*
gin
.
Context
)
{
var
schema
schemas
.
CreateClusterSchema
if
err
:=
ctx
.
ShouldBindJSON
(
&
schema
);
err
!=
nil
{
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
ownership
,
err
:=
GetOwnershipInfo
(
ctx
)
if
err
!=
nil
{
ctx
.
JSON
(
400
,
err
)
}
cluster
,
err
:=
services
.
ClusterService
.
Create
(
ctx
,
services
.
CreateClusterOption
{
Name
:
schema
.
Name
,
OrganizationId
:
ownership
.
OrganizationId
,
CreatorId
:
ownership
.
UserId
,
Description
:
schema
.
Description
,
KubeConfig
:
schema
.
KubeConfig
,
})
if
err
!=
nil
{
log
.
Info
()
.
Msgf
(
"Failed to create cluster: %s"
,
err
.
Error
())
ctx
.
JSON
(
500
,
gin
.
Error
{
Err
:
err
})
return
}
ctx
.
JSON
(
200
,
converters
.
ToClusterFullSchema
(
cluster
))
}
func
(
c
*
clusterController
)
Update
(
ctx
*
gin
.
Context
)
{
var
schema
schemas
.
UpdateClusterSchema
clusterName
:=
ctx
.
Param
(
"clusterName"
)
if
err
:=
ctx
.
ShouldBindJSON
(
&
schema
);
err
!=
nil
{
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
cluster
,
err
:=
c
.
GetCluster
(
ctx
,
clusterName
)
if
err
!=
nil
{
ctx
.
JSON
(
404
,
gin
.
H
{
"error"
:
fmt
.
Sprintf
(
"Could not find cluster with the name %s"
,
clusterName
)})
return
}
cluster
,
err
=
services
.
ClusterService
.
Update
(
ctx
,
cluster
,
services
.
UpdateClusterOption
{
Description
:
schema
.
Description
,
KubeConfig
:
schema
.
KubeConfig
,
})
if
err
!=
nil
{
log
.
Info
()
.
Msgf
(
"Failed to update cluster: %s"
,
err
.
Error
())
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
fmt
.
Sprintf
(
"Error updating cluster %s"
,
err
.
Error
())})
return
}
ctx
.
JSON
(
200
,
converters
.
ToClusterFullSchema
(
cluster
))
}
func
(
c
*
clusterController
)
Get
(
ctx
*
gin
.
Context
)
{
clusterName
:=
ctx
.
Param
(
"clusterName"
)
cluster
,
err
:=
c
.
GetCluster
(
ctx
,
clusterName
)
if
err
!=
nil
{
ctx
.
JSON
(
404
,
gin
.
H
{
"error"
:
fmt
.
Sprintf
(
"Could not find cluster with the name %s"
,
clusterName
)})
return
}
ctx
.
JSON
(
200
,
converters
.
ToClusterFullSchema
(
cluster
))
}
func
(
c
*
clusterController
)
List
(
ctx
*
gin
.
Context
)
{
var
schema
schemas
.
ListQuerySchema
if
err
:=
ctx
.
ShouldBindQuery
(
&
schema
);
err
!=
nil
{
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
ownership
,
err
:=
GetOwnershipInfo
(
ctx
)
if
err
!=
nil
{
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
clusters
,
total
,
err
:=
services
.
ClusterService
.
List
(
ctx
,
services
.
ListClusterOption
{
BaseListOption
:
services
.
BaseListOption
{
Start
:
&
schema
.
Start
,
Count
:
&
schema
.
Count
,
Search
:
schema
.
Search
,
},
OrganizationId
:
&
ownership
.
OrganizationId
,
})
if
err
!=
nil
{
log
.
Info
()
.
Msgf
(
"Failed to list clusters: %s"
,
err
.
Error
())
ctx
.
JSON
(
400
,
gin
.
H
{
"Error"
:
fmt
.
Sprintf
(
"List clusters %s"
,
err
.
Error
())})
return
}
clusterList
:=
schemas
.
ClusterListSchema
{
BaseListSchema
:
schemas
.
BaseListSchema
{
Start
:
schema
.
Start
,
Count
:
schema
.
Count
,
Total
:
total
,
},
Items
:
converters
.
ToClusterSchemaList
(
clusters
),
}
ctx
.
JSON
(
200
,
clusterList
)
}
deploy/compoundai/api-server/api/controllers/common.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
controllers
import
(
"errors"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/common/consts"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/schemas"
"github.com/gin-gonic/gin"
)
const
OwnershipInfoKey
=
"_ownershipInfoKey"
func
GetOwnershipInfo
(
ctx
*
gin
.
Context
)
(
*
schemas
.
OwnershipSchema
,
error
)
{
ownership_
:=
ctx
.
Value
(
OwnershipInfoKey
)
if
ownership_
==
nil
{
return
nil
,
consts
.
ErrNotFound
}
ownership
,
ok
:=
ownership_
.
(
*
schemas
.
OwnershipSchema
)
if
!
ok
{
return
nil
,
errors
.
New
(
"current ownership is not an ownership struct"
)
}
return
ownership
,
nil
}
deploy/compoundai/api-server/api/controllers/compound_component.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
controllers
import
(
"errors"
"fmt"
"strings"
"time"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/common/consts"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/converters"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/database"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/models"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/schemas"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/services"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
)
type
compoundComponentController
struct
{}
var
CompoundComponentController
=
compoundComponentController
{}
func
(
c
*
compoundComponentController
)
Register
(
ctx
*
gin
.
Context
)
{
var
getCluster
schemas
.
GetClusterSchema
var
registerCompoundComponentSchema
schemas
.
RegisterCompoundComponentSchema
if
err
:=
ctx
.
ShouldBindUri
(
&
getCluster
);
err
!=
nil
{
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
if
err
:=
ctx
.
ShouldBindJSON
(
&
registerCompoundComponentSchema
);
err
!=
nil
{
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
names
:=
[]
string
{
getCluster
.
ClusterName
}
clusters
,
_
,
err
:=
services
.
ClusterService
.
List
(
ctx
,
services
.
ListClusterOption
{
Names
:
&
names
,
})
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to get clusters %s when registering Compound Component: %s"
,
getCluster
.
ClusterName
,
err
.
Error
())
log
.
Error
()
.
Msg
(
errMsg
)
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
errMsg
})
return
}
kubeNamespace
:=
strings
.
TrimSpace
(
registerCompoundComponentSchema
.
KubeNamespace
)
// nolint: ineffassign, staticcheck
tx
,
ctx_
,
df
,
err
:=
database
.
DatabaseUtil
.
StartTransaction
(
ctx
)
defer
func
()
{
df
(
err
)
}()
log
.
Info
()
.
Msgf
(
"Registering compound component for %d clusters"
,
len
(
clusters
))
var
compoundComponent
*
models
.
CompoundComponent
for
_
,
cluster
:=
range
clusters
{
compoundComponent
,
err
=
services
.
CompoundComponentService
.
GetByName
(
ctx_
,
cluster
.
ID
,
string
(
registerCompoundComponentSchema
.
Name
))
isNotFound
:=
errors
.
Is
(
err
,
consts
.
ErrNotFound
)
if
err
!=
nil
&&
!
isNotFound
{
log
.
Error
()
.
Msgf
(
"Failed to get compoundComponent: %s"
,
err
.
Error
())
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
"failed to get compoundComponent"
})
return
}
manifest
:=
&
schemas
.
CompoundComponentManifestSchema
{
SelectorLabels
:
registerCompoundComponentSchema
.
SelectorLabels
,
}
if
registerCompoundComponentSchema
.
Manifest
!=
nil
{
manifest
=
registerCompoundComponentSchema
.
Manifest
}
if
isNotFound
{
compoundComponent
,
err
=
services
.
CompoundComponentService
.
Create
(
ctx_
,
services
.
CreateCompoundComponentOption
{
ClusterId
:
cluster
.
ID
,
Name
:
string
(
registerCompoundComponentSchema
.
Name
),
KubeNamespace
:
kubeNamespace
,
Version
:
registerCompoundComponentSchema
.
Version
,
Manifest
:
manifest
,
})
}
else
{
now
:=
time
.
Now
()
now_
:=
&
now
opt
:=
services
.
UpdateCompoundComponentOption
{
LatestHeartbeatAt
:
&
now_
,
Version
:
&
registerCompoundComponentSchema
.
Version
,
Manifest
:
&
manifest
,
}
if
compoundComponent
.
Version
!=
registerCompoundComponentSchema
.
Version
{
opt
.
LatestInstalledAt
=
&
now_
}
compoundComponent
,
err
=
services
.
CompoundComponentService
.
Update
(
ctx_
,
compoundComponent
,
opt
)
}
if
err
!=
nil
{
log
.
Error
()
.
Msgf
(
"Failed to register compoundComponent: %s"
,
err
.
Error
())
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
"failed to register compoundComponent"
})
return
}
}
tx
.
Commit
()
compoundComponentSchema
,
err
:=
converters
.
ToCompoundComponentSchema
(
ctx
,
compoundComponent
)
if
err
!=
nil
{
log
.
Error
()
.
Msgf
(
"Failed to convert compound component model to schema: %s"
,
err
.
Error
())
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
ctx
.
JSON
(
200
,
compoundComponentSchema
)
}
func
(
c
*
compoundComponentController
)
ListAll
(
ctx
*
gin
.
Context
)
{
compoundComponents
,
err
:=
services
.
CompoundComponentService
.
List
(
ctx
,
services
.
ListCompoundComponentOption
{})
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to get all compoundComponents: %s"
,
err
.
Error
())
log
.
Error
()
.
Msg
(
errMsg
)
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
errMsg
})
return
}
compoundComponentSchema
,
err
:=
converters
.
ToCompoundComponentSchemas
(
ctx
,
compoundComponents
)
if
err
!=
nil
{
log
.
Error
()
.
Msgf
(
"Failed to convert compound component model to schema: %s"
,
err
.
Error
())
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
ctx
.
JSON
(
200
,
compoundComponentSchema
)
}
func
(
c
*
compoundComponentController
)
List
(
ctx
*
gin
.
Context
)
{
var
getCluster
schemas
.
GetClusterSchema
if
err
:=
ctx
.
ShouldBindUri
(
&
getCluster
);
err
!=
nil
{
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
names
:=
[]
string
{
getCluster
.
ClusterName
}
clusters
,
_
,
err
:=
services
.
ClusterService
.
List
(
ctx
,
services
.
ListClusterOption
{
Names
:
&
names
,
})
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to get clusters %s when registering Compound Component: %s"
,
getCluster
.
ClusterName
,
err
.
Error
())
log
.
Error
()
.
Msg
(
errMsg
)
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
errMsg
})
return
}
clusterIds
:=
[]
uint
{}
for
_
,
cluster
:=
range
clusters
{
clusterIds
=
append
(
clusterIds
,
cluster
.
ID
)
}
compoundComponents
,
err
:=
services
.
CompoundComponentService
.
List
(
ctx
,
services
.
ListCompoundComponentOption
{
ClusterIds
:
&
clusterIds
,
})
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to get compoundComponents for the cluster %s: %s"
,
getCluster
.
ClusterName
,
err
.
Error
())
log
.
Error
()
.
Msg
(
errMsg
)
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
errMsg
})
return
}
compoundComponentSchema
,
err
:=
converters
.
ToCompoundComponentSchemas
(
ctx
,
compoundComponents
)
if
err
!=
nil
{
log
.
Error
()
.
Msgf
(
"Failed to convert compound component model to schema: %s"
,
err
.
Error
())
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
ctx
.
JSON
(
200
,
compoundComponentSchema
)
}
deploy/compoundai/api-server/api/controllers/deployment.go
0 → 100644
View file @
5ddc7f7d
This diff is collapsed.
Click to expand it.
deploy/compoundai/api-server/api/controllers/deployment_revision.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
controllers
import
(
"fmt"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/converters"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/schemas"
"github.com/dynemo-ai/dynemo/deploy/compoundai/api-server/api/services"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
)
type
deploymentRevisionController
struct
{}
var
DeploymentRevisionController
=
deploymentRevisionController
{}
func
(
c
*
deploymentRevisionController
)
List
(
ctx
*
gin
.
Context
)
{
var
schema
schemas
.
ListQuerySchema
var
getSchema
schemas
.
GetDeploymentSchema
if
err
:=
ctx
.
ShouldBindUri
(
&
getSchema
);
err
!=
nil
{
log
.
Error
()
.
Msgf
(
"Error binding: %s"
,
err
.
Error
())
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
if
err
:=
ctx
.
ShouldBindQuery
(
&
schema
);
err
!=
nil
{
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
deployment
,
err
:=
getDeployment
(
ctx
,
&
getSchema
)
if
err
!=
nil
{
log
.
Error
()
.
Msgf
(
"Could not find deployment with the name %s: %s"
,
getSchema
.
DeploymentName
,
err
.
Error
())
ctx
.
JSON
(
404
,
gin
.
H
{
"error"
:
fmt
.
Sprintf
(
"Could not find deployment with the name %s"
,
getSchema
.
DeploymentName
)})
return
}
deploymentRevisions
,
total
,
err
:=
services
.
DeploymentRevisionService
.
List
(
ctx
,
services
.
ListDeploymentRevisionOption
{
BaseListOption
:
services
.
BaseListOption
{
Start
:
&
schema
.
Start
,
Count
:
&
schema
.
Count
,
Search
:
schema
.
Search
,
},
DeploymentId
:
&
deployment
.
ID
,
})
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to get deployment revisions %s"
,
err
.
Error
())
log
.
Error
()
.
Msgf
(
errMsg
)
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
errMsg
})
return
}
deploymentRevisionSchemas
,
err
:=
converters
.
ToDeploymentRevisionSchemas
(
ctx
,
deploymentRevisions
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to convert models to deployment revision schemas %s"
,
err
.
Error
())
log
.
Error
()
.
Msgf
(
errMsg
)
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
errMsg
})
return
}
log
.
Info
()
.
Msgf
(
"Got %d deployment revisions"
,
len
(
deploymentRevisionSchemas
))
deploymentRevisionListSchema
:=
schemas
.
DeploymentRevisionListSchema
{
BaseListSchema
:
schemas
.
BaseListSchema
{
Total
:
total
,
Start
:
schema
.
Start
,
Count
:
schema
.
Count
,
},
Items
:
deploymentRevisionSchemas
,
}
ctx
.
JSON
(
200
,
deploymentRevisionListSchema
)
}
func
(
c
*
deploymentRevisionController
)
Get
(
ctx
*
gin
.
Context
)
{
var
schema
schemas
.
GetDeploymentRevisionSchema
if
err
:=
ctx
.
ShouldBindUri
(
&
schema
);
err
!=
nil
{
log
.
Error
()
.
Msgf
(
"Error binding: %s"
,
err
.
Error
())
ctx
.
JSON
(
400
,
gin
.
H
{
"error"
:
err
.
Error
()})
return
}
_
,
err
:=
getDeployment
(
ctx
,
&
schema
.
GetDeploymentSchema
)
if
err
!=
nil
{
log
.
Error
()
.
Msgf
(
"Could not find deployment with the name %s: %s"
,
schema
.
DeploymentName
,
err
.
Error
())
ctx
.
JSON
(
404
,
gin
.
H
{
"error"
:
fmt
.
Sprintf
(
"Could not find deployment with the name %s"
,
schema
.
DeploymentName
)})
return
}
deploymentRevision
,
err
:=
services
.
DeploymentRevisionService
.
GetByUid
(
ctx
,
schema
.
RevisionUid
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to get deployment revisions %s for %s"
,
schema
.
DeploymentName
,
err
.
Error
())
log
.
Error
()
.
Msgf
(
errMsg
)
ctx
.
JSON
(
404
,
gin
.
H
{
"error"
:
errMsg
})
return
}
deploymentRevisionSchema
,
err
:=
converters
.
ToDeploymentRevisionSchema
(
ctx
,
deploymentRevision
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to convert model to deployment revision schema %s"
,
err
.
Error
())
log
.
Error
()
.
Msgf
(
errMsg
)
ctx
.
JSON
(
500
,
gin
.
H
{
"error"
:
errMsg
})
return
}
ctx
.
JSON
(
200
,
deploymentRevisionSchema
)
}
deploy/compoundai/api-server/api/controllers/health.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
controllers
import
(
"net/http"
"github.com/gin-gonic/gin"
)
type
healthController
struct
{}
var
HealthController
=
healthController
{}
func
(
h
*
healthController
)
Get
(
gin
*
gin
.
Context
)
{
gin
.
JSON
(
http
.
StatusOK
,
"ok"
)
}
deploy/compoundai/api-server/api/controllers/info.go
0 → 100644
View file @
5ddc7f7d
/*
* 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.
*/
package
controllers
import
(
"github.com/gin-gonic/gin"
)
type
infoController
struct
{}
var
InfoController
=
infoController
{}
type
InfoSchema
struct
{
IsSaas
bool
`json:"is_saas"`
SaasDomainSuffix
string
`json:"saas_domain_suffix"`
}
func
(
c
*
infoController
)
GetInfo
(
ctx
*
gin
.
Context
)
{
schema
:=
InfoSchema
{
IsSaas
:
true
,
SaasDomainSuffix
:
""
,
}
ctx
.
JSON
(
200
,
schema
)
}
Prev
1
2
3
4
5
…
12
Next
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