Skip to content

Commit

Permalink
Fix: validate non empty projects for delete (#154)
Browse files Browse the repository at this point in the history
fix: validate non empty projects for delete

Signed-off-by: mabhi <abhijit.mukherjee@infracloud.io>
  • Loading branch information
mabhi committed Feb 20, 2023
1 parent 0971def commit a211287
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 13 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ All notable changes to this project will be documented in this file.
### Added
- Configure the SA account lifetime from [mabhi](https://github.com/mabhi)

### Fixed
- namespace limitation [mabhi](https://github.com/mabhi)
## Fixed
- Able to Deleted Project With Clusters In It from [mabhi](https://github.com/mabhi)

## [0.2.0] - 2023-01-27

Expand Down
5 changes: 3 additions & 2 deletions pkg/reconcile/cluster_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,15 @@ func (h *clusterEventHandler) handleClusterEvent(ev event.Resource) {

if ev.ID != "" {
cluster, err = h.cs.Select(ctx, &infrav3.Cluster{
Metadata: &commonv3.Metadata{Id: ev.ID},
Metadata: &commonv3.Metadata{Id: ev.ID, Project: ev.ProjectID},
}, true)
} else {

cluster, err = h.cs.Get(ctx,
query.WithName(ev.Name),
query.WithPartnerID(ev.PartnerID),
query.WithOrganizationID(ev.OrganizationID),
query.WithProjectID(ev.ProjectID),
)
}

Expand Down Expand Up @@ -196,7 +197,7 @@ func (h *clusterEventHandler) handleClusterWorkloadEvent(ev event.Resource) {

if ev.ID != "" {
cluster, err = h.cs.Select(ctx, &infrav3.Cluster{
Metadata: &commonv3.Metadata{Id: ev.ID},
Metadata: &commonv3.Metadata{Id: ev.ID, Project: ev.ProjectID},
}, true)
} else {
cluster, err = h.cs.Get(ctx,
Expand Down
1 change: 1 addition & 0 deletions pkg/service/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ func prepareAgentResponse(agent *models.BootstrapAgent) *sentry.BootstrapAgent {
ModifiedAt: timestamppb.New(agent.ModifiedAt),
Labels: lbls,
Annotations: ann,
Project: agent.ProjectId.String(),
},
Spec: &sentry.BootstrapAgentSpec{
Token: agent.Token,
Expand Down
46 changes: 40 additions & 6 deletions pkg/service/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,16 @@ func (s *clusterService) Select(ctx context.Context, cluster *infrav3.Cluster, i
if err != nil {
id = uuid.Nil
}
c, err := cdao.GetCluster(ctx, s.db, &models.Cluster{ID: id, Name: cluster.Metadata.Name})

reqProjectId, err := uuid.Parse(cluster.Metadata.Project)
if err != nil {
reqProjectId, err = dao.GetProjectId(ctx, s.db, cluster.Metadata.Project)
if err != nil {
return nil, err
}
}

c, err := cdao.GetCluster(ctx, s.db, &models.Cluster{ID: id, Name: cluster.Metadata.Name, ProjectId: reqProjectId})
if err != nil {
return &infrav3.Cluster{}, err
}
Expand All @@ -324,6 +333,9 @@ func (s *clusterService) Select(ctx context.Context, cluster *infrav3.Cluster, i
if err != nil {
return &infrav3.Cluster{}, err
}
if len(projects) <= 0 {
return &infrav3.Cluster{}, fmt.Errorf("no projects associated with the cluster")
}
}

var metro *models.Metro
Expand Down Expand Up @@ -356,7 +368,15 @@ func (s *clusterService) Get(ctx context.Context, opts ...query.Option) (*infrav
if err != nil {
id = uuid.Nil
}
c, err := cdao.GetCluster(ctx, s.db, &models.Cluster{ID: id, Name: queryOptions.Name})
reqProjectId, err := uuid.Parse(queryOptions.Project)
if err != nil {
reqProjectId, err = dao.GetProjectId(ctx, s.db, queryOptions.Project)
if err != nil {
return nil, err
}
}

c, err := cdao.GetCluster(ctx, s.db, &models.Cluster{ID: id, Name: queryOptions.Name, ProjectId: reqProjectId})
if err != nil {
return &infrav3.Cluster{}, err
}
Expand All @@ -366,6 +386,10 @@ func (s *clusterService) Get(ctx context.Context, opts ...query.Option) (*infrav
if err != nil {
return &infrav3.Cluster{}, err
}

if len(projects) <= 0 {
return &infrav3.Cluster{}, fmt.Errorf("no projects associated with the cluster")
}
}

s.prepareClusterResponse(ctx, clstr, c, nil, projects, queryOptions.Extended)
Expand Down Expand Up @@ -479,12 +503,22 @@ func (s *clusterService) Update(ctx context.Context, cluster *infrav3.Cluster) (
}
return cluster, fmt.Errorf("invalid cluster data, name is missing")
}

edb, err := dao.GetByName(ctx, s.db, cluster.Metadata.Name, &models.Cluster{})
// look for projectId and validate it during cluster fetch
reqProjectId, err := uuid.Parse(projectName)
if err != nil {
return &infrav3.Cluster{}, fmt.Errorf(errormsg)
reqProjectId, err = dao.GetProjectId(ctx, s.db, projectName)
if err != nil {
return nil, err
}
}
id, err := uuid.Parse(cluster.Metadata.Id)
if err != nil {
return nil, err
}
cdb, err := cdao.GetCluster(ctx, s.db, &models.Cluster{ID: id, Name: cluster.Metadata.Name, ProjectId: reqProjectId})
if err != nil {
return &infrav3.Cluster{}, err
}
cdb := edb.(*models.Cluster)

pid := cdb.PartnerId
if cluster.Spec.ClusterType == "" {
Expand Down
6 changes: 6 additions & 0 deletions pkg/service/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ func TestUpdateCluster(t *testing.T) {
puuid := uuid.New().String()
cuuid := uuid.New().String()

mock.ExpectQuery(`SELECT "project"."id"`).WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(puuid))

mock.ExpectQuery(`SELECT "cluster"."id", "cluster"."organization_id"`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(cuuid))

Expand Down Expand Up @@ -113,6 +115,8 @@ func TestSelectCluster(t *testing.T) {
puuid := uuid.New().String()
cuuid := uuid.New().String()

mock.ExpectQuery(`SELECT "project"."id"`).WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(puuid))

mock.ExpectQuery(`SELECT "cluster"."id", "cluster"."organization_id"`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(cuuid))

Expand Down Expand Up @@ -147,6 +151,8 @@ func TestGetCluster(t *testing.T) {
puuid := uuid.New().String()
cuuid := uuid.New().String()

// mock.ExpectQuery(`SELECT "project"."id"`).WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(puuid))

mock.ExpectQuery(`SELECT "cluster"."id", "cluster"."organization_id"`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(cuuid))

Expand Down
16 changes: 16 additions & 0 deletions pkg/service/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"time"

"github.com/google/uuid"
cdao "github.com/paralus/paralus/internal/cluster/dao"
"github.com/paralus/paralus/internal/dao"
"github.com/paralus/paralus/internal/models"
authzv1 "github.com/paralus/paralus/proto/types/authz"
commonv3 "github.com/paralus/paralus/proto/types/commonpb/v3"
v3 "github.com/paralus/paralus/proto/types/commonpb/v3"
systemv3 "github.com/paralus/paralus/proto/types/systempb/v3"
bun "github.com/uptrace/bun"
Expand Down Expand Up @@ -310,6 +312,20 @@ func (s *projectService) Delete(ctx context.Context, project *systemv3.Project)
return &systemv3.Project{}, err
}

clusters, err := cdao.ListClusters(ctx, s.db, commonv3.QueryOptions{
Project: proj.ID.String(),
Organization: proj.OrganizationId.String(),
Partner: proj.PartnerId.String(),
})
if err != nil {
tx.Rollback()
return &systemv3.Project{}, err
}
if len(clusters) > 0 {
tx.Rollback()
return &systemv3.Project{}, fmt.Errorf("there is(are) active cluster(s) %d in the project %s", len(clusters), proj.Name)
}

project, err = s.deleteGroupRoleRelations(ctx, tx, proj.ID, project)
if err != nil {
tx.Rollback()
Expand Down
35 changes: 35 additions & 0 deletions pkg/service/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ func TestProjectDelete(t *testing.T) {
mock.ExpectQuery(`SELECT "project"."id", "project"."name", .* FROM "authsrv_project" AS "project" WHERE`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(puuid, "project-"+puuid))
mock.ExpectBegin()
// return empty rows
mock.ExpectQuery(`SELECT "cluster"."id"`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}))

mock.ExpectExec(`UPDATE "authsrv_projectgrouprole" AS "projectgrouprole" SET trash = TRUE WHERE`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectQuery(`UPDATE "authsrv_projectgroupnamespacerole" AS "projectgroupnamespacerole" SET trash = TRUE WHERE ."project_id" = '` + puuid + `'. AND .trash = false. RETURNING *`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(puuid))
Expand All @@ -146,6 +150,37 @@ func TestProjectDelete(t *testing.T) {
}
}

func TestNonEmptyProjectDelete(t *testing.T) {
db, mock := getDB(t)
defer db.Close()

mazc := mockAuthzClient{}
ps := NewProjectService(db, &mazc, getLogger(), true)

puuid := uuid.New().String()
cuuid := uuid.New().String()

mock.ExpectQuery(`SELECT "project"."id", "project"."name", .* FROM "authsrv_project" AS "project" WHERE`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(puuid, "project-"+puuid))

mock.ExpectBegin()

mock.ExpectQuery(`SELECT "cluster"."id", "cluster"."organization_id"`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(cuuid))

mock.ExpectRollback()
mock.ExpectQuery(`SELECT "projectcluster"."cluster_id", "projectcluster"."project_id"`).
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(cuuid))

project := &systemv3.Project{
Metadata: &v3.Metadata{Id: puuid, Name: "project-" + puuid},
}
_, err := ps.Delete(context.Background(), project)
if err == nil {
t.Fatal("non empty project deleted:", err)
}
}

func TestProjectDeleteNonExist(t *testing.T) {
db, mock := getDB(t)
defer db.Close()
Expand Down
7 changes: 4 additions & 3 deletions server/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,16 +249,17 @@ func (s *bootstrapServer) RegisterBootstrapAgent(ctx context.Context, in *sentry

if template.Metadata.Name == "paralus-core-relay-agent" {
_log.Info("updating cluster status for :: ", agent.Metadata.Name)
err = s.updateClusterStatus(ctx, agent.Metadata.Name)
err = s.updateClusterStatus(ctx, agent.Metadata.Name, agent.Metadata.Project)
}

return
}

func (s *bootstrapServer) updateClusterStatus(ctx context.Context, clusterID string) error {
func (s *bootstrapServer) updateClusterStatus(ctx context.Context, clusterID, projectID string) error {
cluster := &infrav3.Cluster{
Metadata: &commonv3.Metadata{
Id: clusterID,
Id: clusterID,
Project: projectID,
},
Spec: &infrav3.ClusterSpec{
ClusterData: &infrav3.ClusterData{
Expand Down

0 comments on commit a211287

Please sign in to comment.