Skip to content

Commit

Permalink
feat: validate catalog app deletion (#306)
Browse files Browse the repository at this point in the history
* feat: validate catalog app deletion

* chore: rollback
  • Loading branch information
CristhianF7 authored Mar 5, 2024
1 parent c7cb8bf commit 4cfe32b
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 48 deletions.
94 changes: 94 additions & 0 deletions internal/router/api/v1/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,100 @@ func PostAddServiceToCluster(c *gin.Context) {
})
}

// PostValidateService godoc
// @Summary Validate gitops catalog application
// @Description Validate a gitops catalog application so it can be deleted
// @Tags services
// @Accept json
// @Produce json
// @Param cluster_name path string true "Cluster name"
// @Param service_name path string true "Service name to be validated"
// @Param definition body types.GitopsCatalogAppCreateRequest true "Service create request in JSON format"
// @Success 202 {object} types.GitopsCatalogAppValidateRequest
// @Failure 400 {object} types.JSONFailureResponse
// @Router /services/:cluster_name/:service_name/validate [post]
// @Param Authorization header string true "API key" default(Bearer <API key>)
// PostValidateService handles a request to add a service to a cluster based on a gitops catalog app
func PostValidateService(c *gin.Context) {
clusterName, param := c.Params.Get("cluster_name")
if !param {
c.JSON(http.StatusBadRequest, types.JSONFailureResponse{
Message: ":cluster_name not provided",
})
return
}

serviceName, param := c.Params.Get("service_name")
if !param {
c.JSON(http.StatusBadRequest, types.JSONFailureResponse{
Message: ":service_name not provided",
})
return
}

// Verify cluster exists
_, err := db.Client.GetCluster(clusterName)
if err != nil {
c.JSON(http.StatusBadRequest, types.JSONFailureResponse{
Message: "cluster not found",
})
return
}

// Verify service is a valid option and determine if it requires secrets
apps, err := db.Client.GetGitopsCatalogApps()
if err != nil {
c.JSON(http.StatusBadRequest, types.JSONFailureResponse{
Message: err.Error(),
})
return
}
valid := false
for _, app := range apps.Apps {
if app.Name == serviceName {
valid = true
}
}

if !valid {
c.JSON(http.StatusBadRequest, types.JSONFailureResponse{
Message: fmt.Sprintf("service %s is not valid", serviceName),
})
return
}

// Bind to variable as application/json, handle error
var serviceDefinition pkgtypes.GitopsCatalogAppCreateRequest
err = c.Bind(&serviceDefinition)
if err != nil {
c.JSON(http.StatusBadRequest, types.JSONFailureResponse{
Message: err.Error(),
})
return
}

// Generate and apply
cl, err := db.Client.GetCluster(clusterName)
if err != nil {
c.JSON(http.StatusBadRequest, types.JSONFailureResponse{
Message: err.Error(),
})
return
}

err, canDeleteService := services.ValidateService(&cl, serviceName, &serviceDefinition)
if err != nil {
c.JSON(http.StatusBadRequest, types.JSONFailureResponse{
Message: err.Error(),
})
return
}

c.JSON(http.StatusOK, pkgtypes.GitopsCatalogAppValidateRequest{
CanDeleteService: canDeleteService,
})
}

// DeleteServiceFromCluster godoc
// @Summary Remove a gitops catalog application from a cluster
// @Description Remove a gitops catalog application from a cluster
Expand Down
1 change: 1 addition & 0 deletions internal/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func SetupRouter() *gin.Engine {
// Services
v1.GET("/services/:cluster_name", middleware.ValidateAPIKey(), router.GetServices)
v1.POST("/services/:cluster_name/:service_name", middleware.ValidateAPIKey(), router.PostAddServiceToCluster)
v1.POST("/services/:cluster_name/:service_name/validate", middleware.ValidateAPIKey(), router.PostValidateService)
v1.DELETE("/services/:cluster_name/:service_name", middleware.ValidateAPIKey(), router.DeleteServiceFromCluster)

// Domains
Expand Down
154 changes: 106 additions & 48 deletions internal/services/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ func CreateService(cl *pkgtypes.Cluster, serviceName string, appDef *pkgtypes.Gi
return fmt.Errorf("cluster %s - unable to deploy service %s to cluster: cannot deploy services to a cluster in %s state", cl.ClusterName, serviceName, cl.Status)
}

homeDir, err := os.UserHomeDir()
homeDir, _ := os.UserHomeDir()
tmpGitopsDir := fmt.Sprintf("%s/.k1/%s/%s/gitops", homeDir, cl.ClusterName, serviceName)
tmpGitopsCatalogDir := fmt.Sprintf("%s/.k1/%s/%s/gitops-catalog", homeDir, cl.ClusterName, serviceName)

// Remove gitops dir
err = os.RemoveAll(tmpGitopsDir)
err := os.RemoveAll(tmpGitopsDir)
if err != nil {
log.Fatal().Msgf("error removing gitops dir %s: %s", tmpGitopsDir, err)
return err
Expand Down Expand Up @@ -209,7 +209,7 @@ func CreateService(cl *pkgtypes.Cluster, serviceName string, appDef *pkgtypes.Gi
return fmt.Errorf("cluster %s - error pushing commit for service file: %s", clusterName, err)
}

existingService, err := db.Client.GetServices(clusterName)
existingService, _ := db.Client.GetServices(clusterName)

if existingService.ClusterName == "" {
// Add to list
Expand Down Expand Up @@ -311,14 +311,112 @@ func DeleteService(cl *pkgtypes.Cluster, serviceName string, def pkgtypes.Gitops
return fmt.Errorf("cluster %s - error finding service: %s", clusterName, err)
}

homeDir, err := os.UserHomeDir()
if !def.SkipFiles {
homeDir, _ := os.UserHomeDir()
tmpGitopsDir := fmt.Sprintf("%s/.k1/%s/%s/gitops", homeDir, cl.ClusterName, serviceName)

// Remove gitops dir
err = os.RemoveAll(tmpGitopsDir)
if err != nil {
log.Fatal().Msgf("error removing gitops dir %s: %s", tmpGitopsDir, err)
return err
}

err = gitShim.PrepareGitEnvironment(cl, tmpGitopsDir)
if err != nil {
log.Fatal().Msgf("an error ocurred preparing git environment %s %s", tmpGitopsDir, err)
}

gitopsRepo, _ = git.PlainOpen(tmpGitopsDir)

registryPath := getRegistryPath(clusterName, cl.CloudProvider, def.IsTemplate)

serviceFile := fmt.Sprintf("%s/%s/%s.yaml", tmpGitopsDir, registryPath, serviceName)
componentsServiceFolder := fmt.Sprintf("%s/%s/components/%s", tmpGitopsDir, registryPath, serviceName)

err = gitShim.PullWithAuth(
gitopsRepo,
cl.GitProvider,
"main",
&githttps.BasicAuth{
Username: cl.GitAuth.User,
Password: cl.GitAuth.Token,
},
)

if err != nil {
log.Warn().Msgf("cluster %s - error pulling gitops repo: %s", clusterName, err)
}

// removing registry service file
_, err = os.Stat(serviceFile)
if err != nil {
return fmt.Errorf("file %s does not exist in repository", serviceFile)
} else {
err := os.Remove(serviceFile)
if err != nil {
return fmt.Errorf("cluster %s - error deleting file: %s", clusterName, err)
}
}

// removing componentes service folder
_, err = os.Stat(componentsServiceFolder)
if err != nil {
return fmt.Errorf("folder %s does not exist in repository", componentsServiceFolder)
} else {
err := os.RemoveAll(componentsServiceFolder)
if err != nil {
return fmt.Errorf("cluster %s - error deleting components folder: %s", clusterName, err)
}
}

// Commit to gitops repository
err = gitClient.Commit(gitopsRepo, fmt.Sprintf("removing %s from the cluster %s on behalf of %s", serviceName, clusterName, def.User))
if err != nil {
return fmt.Errorf("cluster %s - error deleting service file: %s", clusterName, err)
}

err = gitopsRepo.Push(&git.PushOptions{
RemoteName: "origin",
Auth: &githttps.BasicAuth{
Username: cl.GitAuth.User,
Password: cl.GitAuth.Token,
},
})

if err != nil {
return fmt.Errorf("cluster %s - error pushing commit for service file: %s", clusterName, err)
}
}

err = db.Client.DeleteClusterServiceListEntry(clusterName, &svc)
if err != nil {
return err
}

return nil
}

// ValidateService
func ValidateService(cl *pkgtypes.Cluster, serviceName string, def *pkgtypes.GitopsCatalogAppCreateRequest) (error, bool) {
canDeleleteService := true

var gitopsRepo *git.Repository

clusterName := cl.ClusterName

if def.WorkloadClusterName != "" {
clusterName = def.WorkloadClusterName
}

homeDir, _ := os.UserHomeDir()
tmpGitopsDir := fmt.Sprintf("%s/.k1/%s/%s/gitops", homeDir, cl.ClusterName, serviceName)

// Remove gitops dir
err = os.RemoveAll(tmpGitopsDir)
err := os.RemoveAll(tmpGitopsDir)
if err != nil {
log.Fatal().Msgf("error removing gitops dir %s: %s", tmpGitopsDir, err)
return err
return err, false
}

err = gitShim.PrepareGitEnvironment(cl, tmpGitopsDir)
Expand All @@ -331,7 +429,6 @@ func DeleteService(cl *pkgtypes.Cluster, serviceName string, def pkgtypes.Gitops
registryPath := getRegistryPath(clusterName, cl.CloudProvider, def.IsTemplate)

serviceFile := fmt.Sprintf("%s/%s/%s.yaml", tmpGitopsDir, registryPath, serviceName)
componentsServiceFolder := fmt.Sprintf("%s/%s/components/%s", tmpGitopsDir, registryPath, serviceName)

err = gitShim.PullWithAuth(
gitopsRepo,
Expand All @@ -350,49 +447,10 @@ func DeleteService(cl *pkgtypes.Cluster, serviceName string, def pkgtypes.Gitops
// removing registry service file
_, err = os.Stat(serviceFile)
if err != nil {
return fmt.Errorf("file %s does not exist in repository", serviceFile)
} else {
err := os.Remove(serviceFile)
if err != nil {
return fmt.Errorf("cluster %s - error deleting file: %s", clusterName, err)
}
}

// removing componentes service folder
_, err = os.Stat(componentsServiceFolder)
if err != nil {
return fmt.Errorf("folder %s does not exist in repository", componentsServiceFolder)
} else {
err := os.RemoveAll(componentsServiceFolder)
if err != nil {
return fmt.Errorf("cluster %s - error deleting components folder: %s", clusterName, err)
}
}

// Commit to gitops repository
err = gitClient.Commit(gitopsRepo, fmt.Sprintf("removing %s from the cluster %s on behalf of %s", serviceName, clusterName, def.User))
if err != nil {
return fmt.Errorf("cluster %s - error deleting service file: %s", clusterName, err)
canDeleleteService = false
}

err = gitopsRepo.Push(&git.PushOptions{
RemoteName: "origin",
Auth: &githttps.BasicAuth{
Username: cl.GitAuth.User,
Password: cl.GitAuth.Token,
},
})

if err != nil {
return fmt.Errorf("cluster %s - error pushing commit for service file: %s", clusterName, err)
}

err = db.Client.DeleteClusterServiceListEntry(clusterName, &svc)
if err != nil {
return err
}

return nil
return nil, canDeleleteService
}

// AddDefaultServices
Expand Down
6 changes: 6 additions & 0 deletions pkg/types/gitopsCatalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,14 @@ type GitopsCatalogAppCreateRequest struct {
Environment string `bson:"environment" json:"environment"`
}

// GitopsCatalogAppValidateRequest
type GitopsCatalogAppValidateRequest struct {
CanDeleteService bool `bson:"can_delete_service" json:"can_delete_service"`
}

type GitopsCatalogAppDeleteRequest struct {
User string `bson:"user" json:"user"`
IsTemplate bool `bson:"is_template" json:"is_template"`
WorkloadClusterName string `bson:"workload_cluster_name" json:"workload_cluster_name"`
SkipFiles bool `bson:"skip_files" json:"skip_files"`
}

0 comments on commit 4cfe32b

Please sign in to comment.