/* * 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(®isterCompoundComponentSchema); 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: ®isterCompoundComponentSchema.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) }