From 7b277ba04c2688622cd1609ff26d2c2c239d62c3 Mon Sep 17 00:00:00 2001 From: Piyush Kumar Date: Tue, 6 Feb 2024 17:08:58 +0530 Subject: [PATCH 1/3] feature(infra): added delete pv api --- apps/console/internal/domain/environment.go | 4 +- .../internal/app/graph/generated/generated.go | 134 +++++++++++++++++- apps/infra/internal/app/graph/schema.graphqls | 2 + .../internal/app/graph/schema.resolvers.go | 14 +- apps/infra/internal/domain/api.go | 1 + apps/infra/internal/domain/clusters.go | 13 ++ apps/infra/internal/domain/pv.go | 24 ++++ 7 files changed, 187 insertions(+), 5 deletions(-) diff --git a/apps/console/internal/domain/environment.go b/apps/console/internal/domain/environment.go index 669b8d098..f9abf7d67 100644 --- a/apps/console/internal/domain/environment.go +++ b/apps/console/internal/domain/environment.go @@ -187,7 +187,7 @@ func (d *domain) CloneEnvironment(ctx ConsoleContext, projectName string, source }, Spec: crdsv1.EnvironmentSpec{ ProjectName: projectName, - TargetNamespace: fmt.Sprintf("env-%s", destinationEnvName), + TargetNamespace: d.getEnvironmentTargetNamespace(projectName, destinationEnvName), Routing: &crdsv1.EnvironmentRouting{ Mode: envRoutingMode, }, @@ -279,7 +279,7 @@ func (d *domain) CloneEnvironment(ctx ConsoleContext, projectName string, source resourceMetadata := func(dn string) common.ResourceMetadata { return common.ResourceMetadata{ - DisplayName: fmt.Sprintf("clone of %s", dn), + DisplayName: dn, CreatedBy: common.CreatedOrUpdatedBy{ UserId: ctx.UserId, UserName: ctx.UserName, diff --git a/apps/infra/internal/app/graph/generated/generated.go b/apps/infra/internal/app/graph/generated/generated.go index fa3596a7e..ad27988a4 100644 --- a/apps/infra/internal/app/graph/generated/generated.go +++ b/apps/infra/internal/app/graph/generated/generated.go @@ -969,6 +969,7 @@ type ComplexityRoot struct { InfraDeleteHelmRelease func(childComplexity int, clusterName string, releaseName string) int InfraDeleteNodePool func(childComplexity int, clusterName string, poolName string) int InfraDeleteProviderSecret func(childComplexity int, secretName string) int + InfraDeletePv func(childComplexity int, clusterName string, pvName string) int InfraUpdateCluster func(childComplexity int, cluster entities.Cluster) int InfraUpdateClusterManagedService func(childComplexity int, clusterName string, service entities.ClusterManagedService) int InfraUpdateDomainEntry func(childComplexity int, domainEntry entities.DomainEntry) int @@ -1286,6 +1287,7 @@ type MutationResolver interface { InfraCreateHelmRelease(ctx context.Context, clusterName string, release entities.HelmRelease) (*entities.HelmRelease, error) InfraUpdateHelmRelease(ctx context.Context, clusterName string, release entities.HelmRelease) (*entities.HelmRelease, error) InfraDeleteHelmRelease(ctx context.Context, clusterName string, releaseName string) (bool, error) + InfraDeletePv(ctx context.Context, clusterName string, pvName string) (bool, error) } type NamespaceResolver interface { CreationTime(ctx context.Context, obj *entities.Namespace) (string, error) @@ -5331,6 +5333,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.InfraDeleteProviderSecret(childComplexity, args["secretName"].(string)), true + case "Mutation.infra_deletePV": + if e.complexity.Mutation.InfraDeletePv == nil { + break + } + + args, err := ec.field_Mutation_infra_deletePV_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.InfraDeletePv(childComplexity, args["clusterName"].(string), args["pvName"].(string)), true + case "Mutation.infra_updateCluster": if e.complexity.Mutation.InfraUpdateCluster == nil { break @@ -6894,6 +6908,8 @@ type Mutation { infra_createHelmRelease(clusterName: String!, release: HelmReleaseIn!): HelmRelease @isLoggedInAndVerified @hasAccount infra_updateHelmRelease(clusterName: String!, release: HelmReleaseIn!): HelmRelease @isLoggedInAndVerified @hasAccount infra_deleteHelmRelease(clusterName: String!, releaseName: String!): Boolean! @isLoggedInAndVerified @hasAccount + + infra_deletePV(clusterName: String!, pvName: String!): Boolean! @isLoggedInAndVerified @hasAccount } type EncodedValue { @@ -8968,6 +8984,30 @@ func (ec *executionContext) field_Mutation_infra_deleteNodePool_args(ctx context return args, nil } +func (ec *executionContext) field_Mutation_infra_deletePV_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["clusterName"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clusterName")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["clusterName"] = arg0 + var arg1 string + if tmp, ok := rawArgs["pvName"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("pvName")) + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["pvName"] = arg1 + return args, nil +} + func (ec *executionContext) field_Mutation_infra_deleteProviderSecret_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -35802,6 +35842,87 @@ func (ec *executionContext) fieldContext_Mutation_infra_deleteHelmRelease(ctx co return fc, nil } +func (ec *executionContext) _Mutation_infra_deletePV(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_infra_deletePV(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().InfraDeletePv(rctx, fc.Args["clusterName"].(string), fc.Args["pvName"].(string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsLoggedInAndVerified == nil { + return nil, errors.New("directive isLoggedInAndVerified is not implemented") + } + return ec.directives.IsLoggedInAndVerified(ctx, nil, directive0) + } + directive2 := func(ctx context.Context) (interface{}, error) { + if ec.directives.HasAccount == nil { + return nil, errors.New("directive hasAccount is not implemented") + } + return ec.directives.HasAccount(ctx, nil, directive1) + } + + tmp, err := directive2(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(bool); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be bool`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_infra_deletePV(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_infra_deletePV_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return + } + return fc, nil +} + func (ec *executionContext) _Namespace_accountName(ctx context.Context, field graphql.CollectedField, obj *entities.Namespace) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Namespace_accountName(ctx, field) if err != nil { @@ -57154,6 +57275,15 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) return ec._Mutation_infra_deleteHelmRelease(ctx, field) }) + if out.Values[i] == graphql.Null { + invalids++ + } + case "infra_deletePV": + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_infra_deletePV(ctx, field) + }) + if out.Values[i] == graphql.Null { invalids++ } @@ -61628,7 +61758,7 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a return res } -func (ec *executionContext) unmarshalOAny2interface(ctx context.Context, v interface{}) (interface{}, error) { +func (ec *executionContext) unmarshalOAny2interface(ctx context.Context, v interface{}) (any, error) { if v == nil { return nil, nil } @@ -61636,7 +61766,7 @@ func (ec *executionContext) unmarshalOAny2interface(ctx context.Context, v inter return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalOAny2interface(ctx context.Context, sel ast.SelectionSet, v interface{}) graphql.Marshaler { +func (ec *executionContext) marshalOAny2interface(ctx context.Context, sel ast.SelectionSet, v any) graphql.Marshaler { if v == nil { return graphql.Null } diff --git a/apps/infra/internal/app/graph/schema.graphqls b/apps/infra/internal/app/graph/schema.graphqls index d6ad9a83c..ac2ab170d 100644 --- a/apps/infra/internal/app/graph/schema.graphqls +++ b/apps/infra/internal/app/graph/schema.graphqls @@ -137,6 +137,8 @@ type Mutation { infra_createHelmRelease(clusterName: String!, release: HelmReleaseIn!): HelmRelease @isLoggedInAndVerified @hasAccount infra_updateHelmRelease(clusterName: String!, release: HelmReleaseIn!): HelmRelease @isLoggedInAndVerified @hasAccount infra_deleteHelmRelease(clusterName: String!, releaseName: String!): Boolean! @isLoggedInAndVerified @hasAccount + + infra_deletePV(clusterName: String!, pvName: String!): Boolean! @isLoggedInAndVerified @hasAccount } type EncodedValue { diff --git a/apps/infra/internal/app/graph/schema.resolvers.go b/apps/infra/internal/app/graph/schema.resolvers.go index 13b9059cd..482cb1712 100644 --- a/apps/infra/internal/app/graph/schema.resolvers.go +++ b/apps/infra/internal/app/graph/schema.resolvers.go @@ -7,7 +7,6 @@ package graph import ( "context" "encoding/base64" - "github.com/kloudlite/api/apps/infra/internal/app/graph/generated" "github.com/kloudlite/api/apps/infra/internal/app/graph/model" "github.com/kloudlite/api/apps/infra/internal/domain" @@ -226,6 +225,19 @@ func (r *mutationResolver) InfraDeleteHelmRelease(ctx context.Context, clusterNa return true, nil } +// InfraDeletePv is the resolver for the infra_deletePV field. +func (r *mutationResolver) InfraDeletePv(ctx context.Context, clusterName string, pvName string) (bool, error) { + ictx, err := toInfraContext(ctx) + if err != nil { + return false, errors.NewE(err) + } + + if err := r.Domain.DeletePV(ictx, clusterName, pvName); err != nil { + return false, errors.NewE(err) + } + return true, nil +} + // InfraCheckNameAvailability is the resolver for the infra_checkNameAvailability field. func (r *queryResolver) InfraCheckNameAvailability(ctx context.Context, resType domain.ResType, clusterName *string, name string) (*domain.CheckNameAvailabilityOutput, error) { ictx, err := toInfraContext(ctx) diff --git a/apps/infra/internal/domain/api.go b/apps/infra/internal/domain/api.go index 7a8295220..71b513a7d 100644 --- a/apps/infra/internal/domain/api.go +++ b/apps/infra/internal/domain/api.go @@ -133,6 +133,7 @@ type Domain interface { GetPV(ctx InfraContext, clusterName string, pvName string) (*entities.PersistentVolume, error) OnPVUpdateMessage(ctx InfraContext, clusterName string, pv entities.PersistentVolume, status types.ResourceStatus, opts UpdateAndDeleteOpts) error OnPVDeleteMessage(ctx InfraContext, clusterName string, pv entities.PersistentVolume) error + DeletePV(ctx InfraContext, clusterName string, pvName string) error OnIngressUpdateMessage(ctx InfraContext, clusterName string, ingress networkingv1.Ingress, status types.ResourceStatus, opts UpdateAndDeleteOpts) error OnIngressDeleteMessage(ctx InfraContext, clusterName string, ingress networkingv1.Ingress) error diff --git a/apps/infra/internal/domain/clusters.go b/apps/infra/internal/domain/clusters.go index a6e1cfe92..0f07054ba 100644 --- a/apps/infra/internal/domain/clusters.go +++ b/apps/infra/internal/domain/clusters.go @@ -405,6 +405,19 @@ func (d *domain) DeleteCluster(ctx InfraContext, name string) error { return errors.NewE(err) } + filter := map[string]repos.MatchFilter{} + pagination := &repos.DefaultCursorPagination + + npList, err := d.ListNodePools(ctx, name, filter, *pagination) + if npList.TotalCount != 0 { + return errors.Newf("delete nodepool first, aborting cluster deletion") + } + + pvList, err := d.ListPVs(ctx, name, filter, *pagination) + if pvList.TotalCount != 0 { + return errors.Newf("delete pvs first, aborting cluster deletion") + } + ucluster, err := d.clusterRepo.Patch( ctx, repos.Filter{ diff --git a/apps/infra/internal/domain/pv.go b/apps/infra/internal/domain/pv.go index 2531435dd..ebbea698f 100644 --- a/apps/infra/internal/domain/pv.go +++ b/apps/infra/internal/domain/pv.go @@ -1,7 +1,9 @@ package domain import ( + iamT "github.com/kloudlite/api/apps/iam/types" "github.com/kloudlite/api/apps/infra/internal/entities" + "github.com/kloudlite/api/common" "github.com/kloudlite/api/common/fields" "github.com/kloudlite/api/pkg/errors" "github.com/kloudlite/api/pkg/repos" @@ -35,6 +37,28 @@ func (d *domain) ListPVs(ctx InfraContext, clusterName string, search map[string return d.pvRepo.FindPaginated(ctx, d.nodePoolRepo.MergeMatchFilters(filter, search), pagination) } +func (d *domain) DeletePV(ctx InfraContext, clusterName string, pvName string) error { + if err := d.canPerformActionInAccount(ctx, iamT.DeleteNodepool); err != nil { + return errors.NewE(err) + } + + upv, err := d.pvRepo.Patch( + ctx, + repos.Filter{ + fields.ClusterName: clusterName, + fields.AccountName: ctx.AccountName, + fields.MetadataName: pvName, + }, + common.PatchForMarkDeletion(), + ) + if err != nil { + return errors.NewE(err) + } + + d.resourceEventPublisher.PublishResourceEvent(ctx, clusterName, ResourceTypeNodePool, upv.Name, PublishUpdate) + return d.resDispatcher.DeleteFromTargetCluster(ctx, clusterName, &upv.PersistentVolume) +} + // OnPVDeleteMessage implements Domain. func (d *domain) OnPVDeleteMessage(ctx InfraContext, clusterName string, pv entities.PersistentVolume) error { if err := d.pvRepo.DeleteOne(ctx, repos.Filter{ From a9d8f9216fbb9bcf87c98cac7506305f989a023f Mon Sep 17 00:00:00 2001 From: Piyush Kumar Date: Tue, 6 Feb 2024 17:27:17 +0530 Subject: [PATCH 2/3] added repo count method for nodepool and pv count --- apps/infra/internal/domain/clusters.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/infra/internal/domain/clusters.go b/apps/infra/internal/domain/clusters.go index 0f07054ba..b66ddf655 100644 --- a/apps/infra/internal/domain/clusters.go +++ b/apps/infra/internal/domain/clusters.go @@ -405,17 +405,25 @@ func (d *domain) DeleteCluster(ctx InfraContext, name string) error { return errors.NewE(err) } - filter := map[string]repos.MatchFilter{} - pagination := &repos.DefaultCursorPagination + filter := repos.Filter{ + fields.AccountName: ctx.AccountName, + fields.ClusterName: name, + } - npList, err := d.ListNodePools(ctx, name, filter, *pagination) - if npList.TotalCount != 0 { + npCount, err := d.nodePoolRepo.Count(ctx, filter) + if err != nil { + return errors.NewE(err) + } + if npCount != 0 { return errors.Newf("delete nodepool first, aborting cluster deletion") } - pvList, err := d.ListPVs(ctx, name, filter, *pagination) - if pvList.TotalCount != 0 { - return errors.Newf("delete pvs first, aborting cluster deletion") + pvCount, err := d.nodePoolRepo.Count(ctx, filter) + if err != nil { + return errors.NewE(err) + } + if pvCount != 0 { + return errors.Newf("delete nodepool first, aborting cluster deletion") } ucluster, err := d.clusterRepo.Patch( From 985a24e5ba680b42391339ed04bbc7ba15426f7f Mon Sep 17 00:00:00 2001 From: Piyush Kumar Date: Tue, 6 Feb 2024 17:33:58 +0530 Subject: [PATCH 3/3] added repo count method for nodepool and pv count --- apps/infra/internal/domain/clusters.go | 4 ++-- apps/infra/internal/domain/pv.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/infra/internal/domain/clusters.go b/apps/infra/internal/domain/clusters.go index b66ddf655..325688c4a 100644 --- a/apps/infra/internal/domain/clusters.go +++ b/apps/infra/internal/domain/clusters.go @@ -418,12 +418,12 @@ func (d *domain) DeleteCluster(ctx InfraContext, name string) error { return errors.Newf("delete nodepool first, aborting cluster deletion") } - pvCount, err := d.nodePoolRepo.Count(ctx, filter) + pvCount, err := d.pvRepo.Count(ctx, filter) if err != nil { return errors.NewE(err) } if pvCount != 0 { - return errors.Newf("delete nodepool first, aborting cluster deletion") + return errors.Newf("delete pvs first, aborting cluster deletion") } ucluster, err := d.clusterRepo.Patch( diff --git a/apps/infra/internal/domain/pv.go b/apps/infra/internal/domain/pv.go index ebbea698f..b01e438bf 100644 --- a/apps/infra/internal/domain/pv.go +++ b/apps/infra/internal/domain/pv.go @@ -38,6 +38,7 @@ func (d *domain) ListPVs(ctx InfraContext, clusterName string, search map[string } func (d *domain) DeletePV(ctx InfraContext, clusterName string, pvName string) error { + // FIXME: (IAM role binding for DeletePV) if err := d.canPerformActionInAccount(ctx, iamT.DeleteNodepool); err != nil { return errors.NewE(err) }