From 702d90fd3b90397c293ab316af9843ee73e5ee42 Mon Sep 17 00:00:00 2001 From: Abdhesh Nayak Date: Thu, 18 Jan 2024 11:13:01 +0530 Subject: [PATCH 1/5] :art: In device, fixed iam, deletion of device --- .../consolevpndevice.graphqls | 1 + apps/console/internal/domain/domain.go | 30 ++- apps/console/internal/domain/vpn-device.go | 209 ++++++++++++++---- apps/console/internal/entities/vpn-device.go | 3 +- apps/console/internal/env/env.go | 2 +- 5 files changed, 194 insertions(+), 51 deletions(-) diff --git a/apps/console/internal/app/graph/struct-to-graphql/consolevpndevice.graphqls b/apps/console/internal/app/graph/struct-to-graphql/consolevpndevice.graphqls index 1ab978e51..738f41e5f 100644 --- a/apps/console/internal/app/graph/struct-to-graphql/consolevpndevice.graphqls +++ b/apps/console/internal/app/graph/struct-to-graphql/consolevpndevice.graphqls @@ -8,6 +8,7 @@ type ConsoleVPNDevice @shareable { id: String! kind: String lastUpdatedBy: Github__com___kloudlite___api___common__CreatedOrUpdatedBy! + linkedClusters: [String!] markedForDeletion: Boolean metadata: Metadata @goField(name: "objectMeta") projectName: String diff --git a/apps/console/internal/domain/domain.go b/apps/console/internal/domain/domain.go index 8a08f0911..b482f8069 100644 --- a/apps/console/internal/domain/domain.go +++ b/apps/console/internal/domain/domain.go @@ -134,6 +134,34 @@ func (d *domain) applyK8sResource(ctx K8sContext, projectName string, obj client return errors.NewE(err) } +func (d *domain) deleteK8sResourceOfCluster(ctx K8sContext, clusterName string, obj client.Object) error { + + if obj.GetObjectKind().GroupVersionKind().Empty() { + return errors.Newf("object GVK is not set, can not apply") + } + + m, err := fn.K8sObjToMap(obj) + if err != nil { + return errors.NewE(err) + } + b, err := json.Marshal(t.AgentMessage{ + AccountName: ctx.GetAccountName(), + ClusterName: clusterName, + Action: t.ActionDelete, + Object: m, + }) + if err != nil { + return errors.NewE(err) + } + + err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ + Subject: common.GetTenantClusterMessagingTopic(ctx.GetAccountName(), clusterName), + Payload: b, + }) + + return errors.NewE(err) +} + func (d *domain) deleteK8sResource(ctx K8sContext, projectName string, obj client.Object) error { clusterName, err := d.getClusterAttachedToProject(ctx, projectName) if err != nil { @@ -353,7 +381,7 @@ func (d *domain) canPerformActionInDevice(ctx ConsoleContext, action iamT.Action co, err := d.iamClient.Can(ctx, &iam.CanIn{ UserId: string(ctx.UserId), ResourceRefs: []string{ - iamT.NewResourceRef(ctx.AccountName, iamT.ResourceVPNDevice, devName), + iamT.NewResourceRef(ctx.AccountName, iamT.ResourceConsoleVPNDevice, devName), }, Action: string(action), }) diff --git a/apps/console/internal/domain/vpn-device.go b/apps/console/internal/domain/vpn-device.go index fe81734a0..2a26adcd2 100644 --- a/apps/console/internal/domain/vpn-device.go +++ b/apps/console/internal/domain/vpn-device.go @@ -1,11 +1,14 @@ package domain import ( + "time" + "github.com/kloudlite/api/apps/console/internal/entities" iamT "github.com/kloudlite/api/apps/iam/types" "github.com/kloudlite/api/common" "github.com/kloudlite/api/grpc-interfaces/kloudlite.io/rpc/iam" "github.com/kloudlite/api/pkg/errors" + fn "github.com/kloudlite/api/pkg/functions" "github.com/kloudlite/api/pkg/repos" t "github.com/kloudlite/api/pkg/types" wgv1 "github.com/kloudlite/operator/apis/wireguard/v1" @@ -28,6 +31,49 @@ func (d *domain) findVPNDevice(ctx ConsoleContext, name string) (*entities.Conso return device, nil } +func (d *domain) getClusterFromDevice(ctx ConsoleContext, device *entities.ConsoleVPNDevice) (string, error) { + if device == nil { + return "", errors.Newf("device is nil") + } + + if device.ProjectName == nil { + return "", errors.NewE(errors.Newf("project name is nil")) + } + + cluster, err := d.getClusterAttachedToProject(ctx, *device.ProjectName) + if err != nil { + return "", errors.NewE(err) + } + if cluster == nil { + return "", errors.NewE(errors.Newf("no cluster attached to project %s", *device.ProjectName)) + } + return *cluster, nil +} + +func (d *domain) updateVpnOnCluster(ctx ConsoleContext, ndev, xdev *entities.ConsoleVPNDevice) error { + + ndev.Namespace = d.envVars.DeviceNamespace + ndev.EnsureGVK() + if err := d.k8sClient.ValidateObject(ctx, &ndev.Device); err != nil { + return errors.NewE(err) + } + + if ndev.ProjectName != nil && ndev.EnvironmentName != nil { + if err := d.applyK8sResource(ctx, *ndev.ProjectName, &ndev.Device, ndev.RecordVersion); err != nil { + return errors.NewE(err) + } + } + + if (xdev.ProjectName != nil) && (*xdev.ProjectName != *ndev.ProjectName) { + xdev.Spec.Disabled = true + if err := d.applyK8sResource(ctx, *xdev.ProjectName, &xdev.Device, xdev.RecordVersion); err != nil { + return errors.NewE(err) + } + } + + return nil +} + func (d *domain) ListVPNDevices(ctx ConsoleContext, search map[string]repos.MatchFilter, pagination repos.CursorPagination) (*repos.PaginatedRecord[*entities.ConsoleVPNDevice], error) { if err := d.canPerformActionInAccount(ctx, iamT.ListVPNDevices); err != nil { return nil, errors.NewE(err) @@ -49,25 +95,6 @@ func (d *domain) ListVPNDevicesForUser(ctx ConsoleContext) ([]*entities.ConsoleV }) } -func (d *domain) getClusterFromDevice(ctx ConsoleContext, device *entities.ConsoleVPNDevice) (string, error) { - if device == nil { - return "", errors.Newf("device is nil") - } - - if device.ProjectName == nil { - return "", errors.NewE(errors.Newf("project name is nil")) - } - - cluster, err := d.getClusterAttachedToProject(ctx, *device.ProjectName) - if err != nil { - return "", errors.NewE(err) - } - if cluster == nil { - return "", errors.NewE(errors.Newf("no cluster attached to project %s", *device.ProjectName)) - } - return *cluster, nil -} - func (d *domain) GetVPNDevice(ctx ConsoleContext, name string) (*entities.ConsoleVPNDevice, error) { if err := d.canPerformActionInAccount(ctx, iamT.GetVPNDevice); err != nil { return nil, errors.NewE(err) @@ -97,6 +124,7 @@ func (d *domain) CreateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND device.LastUpdatedBy = device.CreatedBy device.AccountName = ctx.AccountName + device.LinkedClusters = []string{} device.SyncStatus = t.GenSyncStatus(t.SyncActionApply, device.RecordVersion) @@ -107,12 +135,19 @@ func (d *domain) CreateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND } device.Spec.ActiveNamespace = &s + + clusterName, err := d.getClusterFromDevice(ctx, &device) + if err != nil { + return nil, errors.NewE(err) + } + + device.LinkedClusters = append(device.LinkedClusters, clusterName) } if _, err := d.iamClient.AddMembership(ctx, &iam.AddMembershipIn{ UserId: string(ctx.UserId), - ResourceType: string(iamT.ResourceVPNDevice), - ResourceRef: iamT.NewResourceRef(ctx.AccountName, iamT.ResourceVPNDevice, device.Name), + ResourceType: string(iamT.ResourceConsoleVPNDevice), + ResourceRef: iamT.NewResourceRef(ctx.AccountName, iamT.ResourceConsoleVPNDevice, device.Name), Role: string(iamT.RoleResourceOwner), }); err != nil { return nil, errors.NewE(err) @@ -136,30 +171,6 @@ func (d *domain) CreateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND return nDevice, nil } -func (d *domain) updateVpnOnCluster(ctx ConsoleContext, ndev, xdev *entities.ConsoleVPNDevice) error { - - ndev.Namespace = d.envVars.DeviceNamespace - ndev.EnsureGVK() - if err := d.k8sClient.ValidateObject(ctx, &ndev.Device); err != nil { - return errors.NewE(err) - } - - if ndev.ProjectName != nil && ndev.EnvironmentName != nil { - if err := d.applyK8sResource(ctx, *ndev.ProjectName, &ndev.Device, ndev.RecordVersion); err != nil { - return errors.NewE(err) - } - } - - if (xdev.ProjectName != nil) && (*xdev.ProjectName != *ndev.ProjectName) { - xdev.Spec.Disabled = true - if err := d.applyK8sResource(ctx, *xdev.ProjectName, &xdev.Device, xdev.RecordVersion); err != nil { - return errors.NewE(err) - } - } - - return nil -} - func (d *domain) UpdateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPNDevice) (*entities.ConsoleVPNDevice, error) { if err := d.canPerformActionInDevice(ctx, iamT.UpdateVPNDevice, device.Name); err != nil { return nil, errors.NewE(err) @@ -178,6 +189,26 @@ func (d *domain) UpdateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND } device.Spec.ActiveNamespace = &s + + if xdevice.ProjectName != nil && *xdevice.ProjectName != *device.ProjectName { + clusterName, err := d.getClusterFromDevice(ctx, &device) + if err != nil { + return nil, errors.NewE(err) + } + + // is cluster already linked? + linked := false + for _, v := range xdevice.LinkedClusters { + if v == clusterName { + linked = true + break + } + } + + if !linked { + device.LinkedClusters = append(xdevice.LinkedClusters, clusterName) + } + } } patch := repos.Document{ @@ -190,6 +221,7 @@ func (d *domain) UpdateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND UserName: ctx.UserName, UserEmail: ctx.UserEmail, }, + "linkedClusters": device.LinkedClusters, } cv, err := d.vpnDeviceRepo.PatchById(ctx, xdevice.Id, patch) @@ -216,13 +248,32 @@ func (d *domain) DeleteVPNDevice(ctx ConsoleContext, name string) error { return errors.NewE(err) } - device.Namespace = d.envVars.DeviceNamespace - d.resourceEventPublisher.PublishVpnDeviceEvent(device, PublishDelete) + if device.IsMarkedForDeletion() { + return errors.Newf("vpnDevice %q is already marked for deletion", name) + } - if err := d.deleteK8sResource(ctx, *device.ProjectName, &device.Device); err != nil { + if _, err := d.vpnDeviceRepo.PatchById(ctx, device.Id, repos.Document{ + "markedForDeletion": fn.New(true), + "lastUpdatedBy": common.CreatedOrUpdatedBy{ + UserId: ctx.UserId, + UserName: ctx.UserName, + UserEmail: ctx.UserEmail, + }, + "syncStatus.lastSyncedAt": time.Now(), + "syncStatus.action": t.SyncActionDelete, + "syncStatus.state": t.SyncStateInQueue, + }); err != nil { return errors.NewE(err) } + d.resourceEventPublisher.PublishVpnDeviceEvent(device, PublishDelete) + + for _, v := range device.LinkedClusters { + if err := d.deleteK8sResourceOfCluster(ctx, v, &device.Device); err != nil { + return errors.NewE(err) + } + } + return nil } @@ -278,6 +329,28 @@ func (d *domain) UpdateVpnDeviceEnvironment(ctx ConsoleContext, devName string, return errors.NewE(err) } + linkedClusters := xdevice.LinkedClusters + + if xdevice.ProjectName != nil && *xdevice.ProjectName != projectName { + clusterName, err := d.getClusterAttachedToProject(ctx, projectName) + if err != nil { + return errors.NewE(err) + } + + // is cluster already linked? + linked := false + for _, v := range xdevice.LinkedClusters { + if v == *clusterName { + linked = true + break + } + } + + if !linked { + linkedClusters = append(xdevice.LinkedClusters, *clusterName) + } + } + patch := repos.Document{ "projectName": projectName, "environmentName": envName, @@ -287,12 +360,14 @@ func (d *domain) UpdateVpnDeviceEnvironment(ctx ConsoleContext, devName string, UserName: ctx.UserName, UserEmail: ctx.UserEmail, }, + "linkedClusters": linkedClusters, } ndevice, err := d.vpnDeviceRepo.PatchById(ctx, xdevice.Id, patch) if err != nil { return errors.NewE(err) } + d.resourceEventPublisher.PublishVpnDeviceEvent(ndevice, PublishUpdate) if err := d.updateVpnOnCluster(ctx, ndevice, xdevice); err != nil { @@ -347,6 +422,44 @@ func (d *domain) OnVPNDeviceDeleteMessage(ctx ConsoleContext, device entities.Co return errors.NewE(err) } + // ensure that the device is not linked to any cluster, if it is, unlink it + { + clusterName, err := d.getClusterFromDevice(ctx, &device) + if err != nil { + return errors.NewE(err) + } + + xdevice.LinkedClusters = func() []string { + var clusters []string + for _, c := range xdevice.LinkedClusters { + if c != clusterName { + clusters = append(clusters, c) + } + } + return clusters + }() + + if len(xdevice.LinkedClusters) >= 0 { + _, err := d.vpnDeviceRepo.PatchById(ctx, xdevice.Id, repos.Document{ + "linkedClusters": xdevice.LinkedClusters, + }) + + if err != nil { + return errors.NewE(err) + } + + d.resourceEventPublisher.PublishVpnDeviceEvent(xdevice, PublishUpdate) + return nil + } + } + + if _, err := d.iamClient.RemoveMembership(ctx, &iam.RemoveMembershipIn{ + UserId: string(ctx.UserId), + ResourceRef: iamT.NewResourceRef(ctx.AccountName, iamT.ResourceConsoleVPNDevice, device.Name), + }); err != nil { + return errors.NewE(err) + } + if err = d.vpnDeviceRepo.DeleteById(ctx, xdevice.Id); err != nil { return errors.NewE(err) } diff --git a/apps/console/internal/entities/vpn-device.go b/apps/console/internal/entities/vpn-device.go index b18434673..58bca2808 100644 --- a/apps/console/internal/entities/vpn-device.go +++ b/apps/console/internal/entities/vpn-device.go @@ -21,7 +21,8 @@ type ConsoleVPNDevice struct { WireguardConfig t.EncodedString `json:"wireguardConfig,omitempty" graphql:"noinput" struct-json-path:",ignore-nesting"` - SyncStatus t.SyncStatus `json:"syncStatus" graphql:"noinput"` + LinkedClusters []string `json:"linkedClusters,omitempty" graphql:"noinput"` + SyncStatus t.SyncStatus `json:"syncStatus" graphql:"noinput"` } var VPNDeviceIndexes = []repos.IndexField{ diff --git a/apps/console/internal/env/env.go b/apps/console/internal/env/env.go index cc49c7841..0841c924d 100644 --- a/apps/console/internal/env/env.go +++ b/apps/console/internal/env/env.go @@ -34,7 +34,7 @@ type Env struct { IsDev bool KubernetesApiProxy string `env:"KUBERNETES_API_PROXY"` - DeviceNamespace string `env:"DEVICE_NAMESPACE" default:"console-devices"` + DeviceNamespace string `env:"DEVICE_NAMESPACE" required:"true"` } func LoadEnv() (*Env, error) { From 783941632bca85412c8821d0a6530d12c039fab8 Mon Sep 17 00:00:00 2001 From: Abdhesh Nayak Date: Thu, 18 Jan 2024 11:13:25 +0530 Subject: [PATCH 2/5] :art: In device, fixed iam, deletion of device --- apps/infra/internal/domain/iam-checks.go | 2 +- apps/infra/internal/domain/vpn-device.go | 12 ++++++++++-- apps/infra/internal/env/env.go | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/infra/internal/domain/iam-checks.go b/apps/infra/internal/domain/iam-checks.go index 6112ff5a8..9eb39fae0 100644 --- a/apps/infra/internal/domain/iam-checks.go +++ b/apps/infra/internal/domain/iam-checks.go @@ -51,7 +51,7 @@ func (d *domain) canPerformActionInDevice(ctx InfraContext, action iamT.Action, co, err := d.iamClient.Can(ctx, &iam.CanIn{ UserId: string(ctx.UserId), ResourceRefs: []string{ - iamT.NewResourceRef(ctx.AccountName, iamT.ResourceVPNDevice, devName), + iamT.NewResourceRef(ctx.AccountName, iamT.ResourceInfraVPNDevice, devName), }, Action: string(action), }) diff --git a/apps/infra/internal/domain/vpn-device.go b/apps/infra/internal/domain/vpn-device.go index 687924d2b..3e9259b3b 100644 --- a/apps/infra/internal/domain/vpn-device.go +++ b/apps/infra/internal/domain/vpn-device.go @@ -173,6 +173,7 @@ func (d *domain) DeleteVPNDevice(ctx InfraContext, clusterName string, name stri if err != nil { return errors.NewE(err) } + if device.IsMarkedForDeletion() { return errors.Newf("vpnDevice %q (clusterName=%q) is already marked for deletion", name, clusterName) } @@ -236,8 +237,8 @@ func (d *domain) CreateVPNDevice(ctx InfraContext, clusterName string, device en if _, err := d.iamClient.AddMembership(ctx, &iam.AddMembershipIn{ UserId: string(ctx.UserId), - ResourceType: string(iamT.ResourceVPNDevice), - ResourceRef: iamT.NewResourceRef(ctx.AccountName, iamT.ResourceVPNDevice, device.Name), + ResourceType: string(iamT.ResourceInfraVPNDevice), + ResourceRef: iamT.NewResourceRef(ctx.AccountName, iamT.ResourceInfraVPNDevice, device.Name), Role: string(iamT.RoleResourceOwner), }); err != nil { return nil, errors.NewE(err) @@ -302,6 +303,13 @@ func (d *domain) OnVPNDeviceDeleteMessage(ctx InfraContext, clusterName string, return errors.NewE(err) } + if _, err = d.iamClient.RemoveMembership(ctx, &iam.RemoveMembershipIn{ + UserId: string(ctx.UserId), + ResourceRef: iamT.NewResourceRef(ctx.AccountName, iamT.ResourceInfraVPNDevice, currDevice.Name), + }); err != nil { + return errors.NewE(err) + } + if err = d.vpnDeviceRepo.DeleteById(ctx, currDevice.Id); err != nil { return errors.NewE(err) } diff --git a/apps/infra/internal/env/env.go b/apps/infra/internal/env/env.go index 81b686a44..3114c84fb 100644 --- a/apps/infra/internal/env/env.go +++ b/apps/infra/internal/env/env.go @@ -40,7 +40,7 @@ type Env struct { MsvcTemplateFilePath string `env:"MSVC_TEMPLATE_FILE_PATH" required:"true"` - DeviceNamespace string `env:"DEVICE_NAMESPACE" default:"infra-devices"` + DeviceNamespace string `env:"DEVICE_NAMESPACE" required:"true"` } func LoadEnv() (*Env, error) { From 7f48600914a8dc98c6ae85396b8ae7ba17af9e95 Mon Sep 17 00:00:00 2001 From: Abdhesh Nayak Date: Thu, 18 Jan 2024 11:13:44 +0530 Subject: [PATCH 3/5] :art: Added device resource type for both console and infra --- apps/iam/types/types.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/iam/types/types.go b/apps/iam/types/types.go index afbeef51a..1a15a4cea 100644 --- a/apps/iam/types/types.go +++ b/apps/iam/types/types.go @@ -8,8 +8,9 @@ const ( ResourceAccount ResourceType = "account" ResourceProject ResourceType = "project" - ResourceEnvironment ResourceType = "environment" - ResourceVPNDevice ResourceType = "vpn_device" + ResourceEnvironment ResourceType = "environment" + ResourceConsoleVPNDevice ResourceType = "console_vpn_device" + ResourceInfraVPNDevice ResourceType = "infra_vpn_device" ) type Role string From 39fb847f04d6c4669261a78eeae82b7112d8b6fd Mon Sep 17 00:00:00 2001 From: Abdhesh Nayak Date: Fri, 26 Jan 2024 15:52:04 +0530 Subject: [PATCH 4/5] :sparkles: Added support of cluster updated and namespace update in console device --- .../internal/app/graph/generated/generated.go | 337 +++++++++++++++++- .../internal/app/graph/schema.graphqls | 2 + .../internal/app/graph/schema.resolvers.go | 40 ++- .../consolevpndevice.graphqls | 2 + apps/console/internal/domain/api.go | 3 + apps/console/internal/domain/domain.go | 43 ++- apps/console/internal/domain/project.go | 2 + apps/console/internal/domain/vpn-device.go | 99 ++++- apps/console/internal/entities/vpn-device.go | 1 + 9 files changed, 506 insertions(+), 23 deletions(-) diff --git a/apps/console/internal/app/graph/generated/generated.go b/apps/console/internal/app/graph/generated/generated.go index 6ada0be78..0ad7d3474 100644 --- a/apps/console/internal/app/graph/generated/generated.go +++ b/apps/console/internal/app/graph/generated/generated.go @@ -165,6 +165,7 @@ type ComplexityRoot struct { ConsoleVPNDevice struct { APIVersion func(childComplexity int) int AccountName func(childComplexity int) int + ClusterName func(childComplexity int) int CreatedBy func(childComplexity int) int CreationTime func(childComplexity int) int DisplayName func(childComplexity int) int @@ -632,6 +633,8 @@ type ComplexityRoot struct { CoreUpdateVPNDevice func(childComplexity int, vpnDevice entities.ConsoleVPNDevice) int CoreUpdateVPNDeviceEnv func(childComplexity int, deviceName string, projectName string, envName string) int CoreUpdateVPNDevicePorts func(childComplexity int, deviceName string, ports []*v11.Port) int + CoreUpdateVpnClusterName func(childComplexity int, deviceName string, clusterName string) int + CoreUpdateVpnDeviceNs func(childComplexity int, deviceName string, ns string) int } PageInfo struct { @@ -938,6 +941,8 @@ type MutationResolver interface { CoreUpdateVPNDevice(ctx context.Context, vpnDevice entities.ConsoleVPNDevice) (*entities.ConsoleVPNDevice, error) CoreUpdateVPNDevicePorts(ctx context.Context, deviceName string, ports []*v11.Port) (bool, error) CoreUpdateVPNDeviceEnv(ctx context.Context, deviceName string, projectName string, envName string) (bool, error) + CoreUpdateVpnDeviceNs(ctx context.Context, deviceName string, ns string) (bool, error) + CoreUpdateVpnClusterName(ctx context.Context, deviceName string, clusterName string) (bool, error) CoreDeleteVPNDevice(ctx context.Context, deviceName string) (bool, error) } type ProjectResolver interface { @@ -1469,6 +1474,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ConsoleVPNDevice.AccountName(childComplexity), true + case "ConsoleVPNDevice.clusterName": + if e.complexity.ConsoleVPNDevice.ClusterName == nil { + break + } + + return e.complexity.ConsoleVPNDevice.ClusterName(childComplexity), true + case "ConsoleVPNDevice.createdBy": if e.complexity.ConsoleVPNDevice.CreatedBy == nil { break @@ -3706,6 +3718,30 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.CoreUpdateVPNDevicePorts(childComplexity, args["deviceName"].(string), args["ports"].([]*v11.Port)), true + case "Mutation.core_updateVpnClusterName": + if e.complexity.Mutation.CoreUpdateVpnClusterName == nil { + break + } + + args, err := ec.field_Mutation_core_updateVpnClusterName_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.CoreUpdateVpnClusterName(childComplexity, args["deviceName"].(string), args["clusterName"].(string)), true + + case "Mutation.core_updateVpnDeviceNs": + if e.complexity.Mutation.CoreUpdateVpnDeviceNs == nil { + break + } + + args, err := ec.field_Mutation_core_updateVpnDeviceNs_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.CoreUpdateVpnDeviceNs(childComplexity, args["deviceName"].(string), args["ns"].(string)), true + case "PageInfo.endCursor": if e.complexity.PageInfo.EndCursor == nil { break @@ -5170,6 +5206,8 @@ type Mutation { core_updateVPNDevicePorts(deviceName: String!,ports: [PortIn!]!): Boolean! @isLoggedInAndVerified @hasAccount core_updateVPNDeviceEnv(deviceName: String!,projectName: String!, envName: String!): Boolean! @isLoggedInAndVerified @hasAccount + core_updateVpnDeviceNs(deviceName: String!,ns: String!): Boolean! @isLoggedInAndVerified @hasAccount + core_updateVpnClusterName(deviceName: String!,clusterName: String!): Boolean! @isLoggedInAndVerified @hasAccount core_deleteVPNDevice(deviceName: String!): Boolean! @isLoggedInAndVerified @hasAccount } @@ -5857,6 +5895,7 @@ input ConfigKeyValueRefIn { {Name: "../struct-to-graphql/consolevpndevice.graphqls", Input: `type ConsoleVPNDevice @shareable { accountName: String! apiVersion: String + clusterName: String createdBy: Github__com___kloudlite___api___common__CreatedOrUpdatedBy! creationTime: Date! displayName: String! @@ -5889,6 +5928,7 @@ type ConsoleVPNDevicePaginatedRecords @shareable { input ConsoleVPNDeviceIn { apiVersion: String + clusterName: String displayName: String! environmentName: String kind: String @@ -7289,6 +7329,54 @@ func (ec *executionContext) field_Mutation_core_updateVPNDevice_args(ctx context return args, nil } +func (ec *executionContext) field_Mutation_core_updateVpnClusterName_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["deviceName"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deviceName")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["deviceName"] = arg0 + var arg1 string + if tmp, ok := rawArgs["clusterName"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clusterName")) + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["clusterName"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Mutation_core_updateVpnDeviceNs_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["deviceName"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deviceName")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["deviceName"] = arg0 + var arg1 string + if tmp, ok := rawArgs["ns"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ns")) + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["ns"] = arg1 + return args, nil +} + func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -11089,6 +11177,47 @@ func (ec *executionContext) fieldContext_ConsoleVPNDevice_apiVersion(ctx context return fc, nil } +func (ec *executionContext) _ConsoleVPNDevice_clusterName(ctx context.Context, field graphql.CollectedField, obj *entities.ConsoleVPNDevice) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ConsoleVPNDevice_clusterName(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) { + ctx = rctx // use context from middleware stack in children + return obj.ClusterName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2áš–string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ConsoleVPNDevice_clusterName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ConsoleVPNDevice", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _ConsoleVPNDevice_createdBy(ctx context.Context, field graphql.CollectedField, obj *entities.ConsoleVPNDevice) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ConsoleVPNDevice_createdBy(ctx, field) if err != nil { @@ -11977,6 +12106,8 @@ func (ec *executionContext) fieldContext_ConsoleVPNDeviceEdge_node(ctx context.C return ec.fieldContext_ConsoleVPNDevice_accountName(ctx, field) case "apiVersion": return ec.fieldContext_ConsoleVPNDevice_apiVersion(ctx, field) + case "clusterName": + return ec.fieldContext_ConsoleVPNDevice_clusterName(ctx, field) case "createdBy": return ec.fieldContext_ConsoleVPNDevice_createdBy(ctx, field) case "creationTime": @@ -25935,6 +26066,8 @@ func (ec *executionContext) fieldContext_Mutation_core_createVPNDevice(ctx conte return ec.fieldContext_ConsoleVPNDevice_accountName(ctx, field) case "apiVersion": return ec.fieldContext_ConsoleVPNDevice_apiVersion(ctx, field) + case "clusterName": + return ec.fieldContext_ConsoleVPNDevice_clusterName(ctx, field) case "createdBy": return ec.fieldContext_ConsoleVPNDevice_createdBy(ctx, field) case "creationTime": @@ -26053,6 +26186,8 @@ func (ec *executionContext) fieldContext_Mutation_core_updateVPNDevice(ctx conte return ec.fieldContext_ConsoleVPNDevice_accountName(ctx, field) case "apiVersion": return ec.fieldContext_ConsoleVPNDevice_apiVersion(ctx, field) + case "clusterName": + return ec.fieldContext_ConsoleVPNDevice_clusterName(ctx, field) case "createdBy": return ec.fieldContext_ConsoleVPNDevice_createdBy(ctx, field) case "creationTime": @@ -26267,6 +26402,168 @@ func (ec *executionContext) fieldContext_Mutation_core_updateVPNDeviceEnv(ctx co return fc, nil } +func (ec *executionContext) _Mutation_core_updateVpnDeviceNs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_core_updateVpnDeviceNs(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().CoreUpdateVpnDeviceNs(rctx, fc.Args["deviceName"].(string), fc.Args["ns"].(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_core_updateVpnDeviceNs(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_core_updateVpnDeviceNs_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return + } + return fc, nil +} + +func (ec *executionContext) _Mutation_core_updateVpnClusterName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_core_updateVpnClusterName(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().CoreUpdateVpnClusterName(rctx, fc.Args["deviceName"].(string), fc.Args["clusterName"].(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_core_updateVpnClusterName(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_core_updateVpnClusterName_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return + } + return fc, nil +} + func (ec *executionContext) _Mutation_core_deleteVPNDevice(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_core_deleteVPNDevice(ctx, field) if err != nil { @@ -31916,6 +32213,8 @@ func (ec *executionContext) fieldContext_Query_core_listVPNDevicesForUser(ctx co return ec.fieldContext_ConsoleVPNDevice_accountName(ctx, field) case "apiVersion": return ec.fieldContext_ConsoleVPNDevice_apiVersion(ctx, field) + case "clusterName": + return ec.fieldContext_ConsoleVPNDevice_clusterName(ctx, field) case "createdBy": return ec.fieldContext_ConsoleVPNDevice_createdBy(ctx, field) case "creationTime": @@ -32023,6 +32322,8 @@ func (ec *executionContext) fieldContext_Query_core_getVPNDevice(ctx context.Con return ec.fieldContext_ConsoleVPNDevice_accountName(ctx, field) case "apiVersion": return ec.fieldContext_ConsoleVPNDevice_apiVersion(ctx, field) + case "clusterName": + return ec.fieldContext_ConsoleVPNDevice_clusterName(ctx, field) case "createdBy": return ec.fieldContext_ConsoleVPNDevice_createdBy(ctx, field) case "creationTime": @@ -36794,7 +37095,7 @@ func (ec *executionContext) unmarshalInputConsoleVPNDeviceIn(ctx context.Context asMap[k] = v } - fieldsInOrder := [...]string{"apiVersion", "displayName", "environmentName", "kind", "metadata", "projectName", "spec"} + fieldsInOrder := [...]string{"apiVersion", "clusterName", "displayName", "environmentName", "kind", "metadata", "projectName", "spec"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -36809,6 +37110,14 @@ func (ec *executionContext) unmarshalInputConsoleVPNDeviceIn(ctx context.Context if err != nil { return it, err } + case "clusterName": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clusterName")) + it.ClusterName, err = ec.unmarshalOString2áš–string(ctx, v) + if err != nil { + return it, err + } case "displayName": var err error @@ -40546,6 +40855,10 @@ func (ec *executionContext) _ConsoleVPNDevice(ctx context.Context, sel ast.Selec out.Values[i] = ec._ConsoleVPNDevice_apiVersion(ctx, field, obj) + case "clusterName": + + out.Values[i] = ec._ConsoleVPNDevice_clusterName(ctx, field, obj) + case "createdBy": out.Values[i] = ec._ConsoleVPNDevice_createdBy(ctx, field, obj) @@ -43768,6 +44081,24 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) return ec._Mutation_core_updateVPNDeviceEnv(ctx, field) }) + if out.Values[i] == graphql.Null { + invalids++ + } + case "core_updateVpnDeviceNs": + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_core_updateVpnDeviceNs(ctx, field) + }) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "core_updateVpnClusterName": + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_core_updateVpnClusterName(ctx, field) + }) + if out.Values[i] == graphql.Null { invalids++ } @@ -47890,7 +48221,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 } @@ -47898,7 +48229,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/console/internal/app/graph/schema.graphqls b/apps/console/internal/app/graph/schema.graphqls index ec07daab6..e5551319d 100644 --- a/apps/console/internal/app/graph/schema.graphqls +++ b/apps/console/internal/app/graph/schema.graphqls @@ -178,6 +178,8 @@ type Mutation { core_updateVPNDevicePorts(deviceName: String!,ports: [PortIn!]!): Boolean! @isLoggedInAndVerified @hasAccount core_updateVPNDeviceEnv(deviceName: String!,projectName: String!, envName: String!): Boolean! @isLoggedInAndVerified @hasAccount + core_updateVpnDeviceNs(deviceName: String!,ns: String!): Boolean! @isLoggedInAndVerified @hasAccount + core_updateVpnClusterName(deviceName: String!,clusterName: String!): Boolean! @isLoggedInAndVerified @hasAccount core_deleteVPNDevice(deviceName: String!): Boolean! @isLoggedInAndVerified @hasAccount } diff --git a/apps/console/internal/app/graph/schema.resolvers.go b/apps/console/internal/app/graph/schema.resolvers.go index 53b7043ef..04b400326 100644 --- a/apps/console/internal/app/graph/schema.resolvers.go +++ b/apps/console/internal/app/graph/schema.resolvers.go @@ -352,6 +352,36 @@ func (r *mutationResolver) CoreUpdateVPNDeviceEnv(ctx context.Context, deviceNam return true, nil } +// CoreUpdateVpnDeviceNs is the resolver for the core_updateVpnDeviceNs field. +func (r *mutationResolver) CoreUpdateVpnDeviceNs(ctx context.Context, deviceName string, ns string) (bool, error) { + + cc, err := toConsoleContext(ctx) + if err != nil { + return false, errors.NewE(err) + } + + if err := r.Domain.UpdateVpnDeviceNs(cc, deviceName, ns); err != nil { + return false, errors.NewE(err) + } + + return true, nil +} + +// CoreUpdateVpnClusterName is the resolver for the core_updateVpnClusterName field. +func (r *mutationResolver) CoreUpdateVpnClusterName(ctx context.Context, deviceName string, clusterName string) (bool, error) { + + cc, err := toConsoleContext(ctx) + if err != nil { + return false, errors.NewE(err) + } + + if err := r.Domain.UpdateVpnDeviceCluster(cc, deviceName, clusterName); err != nil { + return false, errors.NewE(err) + } + + return true, nil +} + // CoreDeleteVPNDevice is the resolver for the core_deleteVPNDevice field. func (r *mutationResolver) CoreDeleteVPNDevice(ctx context.Context, deviceName string) (bool, error) { cc, err := toConsoleContext(ctx) @@ -960,13 +990,3 @@ func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } type mutationResolver struct{ *Resolver } type queryResolver struct{ *Resolver } - -// !!! WARNING !!! -// The code below was going to be deleted when updating resolvers. It has been copied here so you have -// one last chance to move it out of harms way if you want. There are two reasons this happens: -// - When renaming or deleting a resolver the old code will be put in here. You can safely delete -// it when you're done. -// - You have helper methods in this file. Move them out to keep these resolver files clean. -func (r *mutationResolver) CoreRestartApp(ctx context.Context, projectName string, envName string, appName string) (bool, error) { - panic(fmt.Errorf("not implemented: CoreRestartApp - core_restartApp")) -} diff --git a/apps/console/internal/app/graph/struct-to-graphql/consolevpndevice.graphqls b/apps/console/internal/app/graph/struct-to-graphql/consolevpndevice.graphqls index 738f41e5f..b60f4aabb 100644 --- a/apps/console/internal/app/graph/struct-to-graphql/consolevpndevice.graphqls +++ b/apps/console/internal/app/graph/struct-to-graphql/consolevpndevice.graphqls @@ -1,6 +1,7 @@ type ConsoleVPNDevice @shareable { accountName: String! apiVersion: String + clusterName: String createdBy: Github__com___kloudlite___api___common__CreatedOrUpdatedBy! creationTime: Date! displayName: String! @@ -33,6 +34,7 @@ type ConsoleVPNDevicePaginatedRecords @shareable { input ConsoleVPNDeviceIn { apiVersion: String + clusterName: String displayName: String! environmentName: String kind: String diff --git a/apps/console/internal/domain/api.go b/apps/console/internal/domain/api.go index ee94f677c..70c701eb0 100644 --- a/apps/console/internal/domain/api.go +++ b/apps/console/internal/domain/api.go @@ -256,6 +256,9 @@ type Domain interface { OnVPNDeviceApplyError(ctx ConsoleContext, errMsg string, name string, opts UpdateAndDeleteOpts) error OnVPNDeviceDeleteMessage(ctx ConsoleContext, device entities.ConsoleVPNDevice) error OnVPNDeviceUpdateMessage(ctx ConsoleContext, device entities.ConsoleVPNDevice, status types.ResourceStatus, opts UpdateAndDeleteOpts, clusterName string) error + + UpdateVpnDeviceCluster(ctx ConsoleContext, devName string, clusterName string) error + UpdateVpnDeviceNs(ctx ConsoleContext, devName string, namespace string) error } type PublishMsg string diff --git a/apps/console/internal/domain/domain.go b/apps/console/internal/domain/domain.go index f65647219..4aa0fa9d4 100644 --- a/apps/console/internal/domain/domain.go +++ b/apps/console/internal/domain/domain.go @@ -18,7 +18,6 @@ import ( msgTypes "github.com/kloudlite/api/pkg/messaging/types" "github.com/kloudlite/api/pkg/types" - // "github.com/kloudlite/operator/pkg/constants" "github.com/kloudlite/api/constants" t "github.com/kloudlite/api/apps/tenant-agent/types" @@ -91,6 +90,47 @@ type K8sContext interface { GetAccountName() string } +func (d *domain) applyK8sResourceOnCluster(ctx K8sContext, clusterName string, obj client.Object, recordVersion int) error { + + if clusterName == "" { + d.logger.Infof("skipping apply of k8s resource %s/%s, cluster name not provided", obj.GetNamespace(), obj.GetName()) + return nil + } + + if obj.GetObjectKind().GroupVersionKind().Empty() { + return errors.Newf("object GVK is not set, can not apply") + } + + ann := obj.GetAnnotations() + if ann == nil { + ann = make(map[string]string, 1) + } + ann[constants.RecordVersionKey] = fmt.Sprintf("%d", recordVersion) + obj.SetAnnotations(ann) + + m, err := fn.K8sObjToMap(obj) + if err != nil { + return errors.NewE(err) + } + b, err := json.Marshal(t.AgentMessage{ + AccountName: ctx.GetAccountName(), + ClusterName: clusterName, + Action: t.ActionApply, + Object: m, + }) + if err != nil { + return errors.NewE(err) + } + + subject := common.GetTenantClusterMessagingTopic(ctx.GetAccountName(), clusterName) + + err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ + Subject: subject, + Payload: b, + }) + return errors.NewE(err) +} + func (d *domain) applyK8sResource(ctx K8sContext, projectName string, obj client.Object, recordVersion int) error { clusterName, err := d.getClusterAttachedToProject(ctx, projectName) if err != nil { @@ -440,6 +480,7 @@ func cloneResource[T repos.Entity](ctx ResourceContext, d *domain, repoName repo return errors.NewE(err) } } + if err := d.applyK8sResource(ctx, ctx.ProjectName, obj, 0); err != nil { return errors.NewE(err) } diff --git a/apps/console/internal/domain/project.go b/apps/console/internal/domain/project.go index 4e3e3e45b..92a2dc1dc 100644 --- a/apps/console/internal/domain/project.go +++ b/apps/console/internal/domain/project.go @@ -152,6 +152,8 @@ func (d *domain) CreateProject(ctx ConsoleContext, project entities.Project) (*e project.IncrementRecordVersion() + // TODO: check if provided cluster is exists in account + project.CreatedBy = common.CreatedOrUpdatedBy{ UserId: ctx.UserId, UserName: ctx.UserName, diff --git a/apps/console/internal/domain/vpn-device.go b/apps/console/internal/domain/vpn-device.go index f333e8e67..1420fa2d0 100644 --- a/apps/console/internal/domain/vpn-device.go +++ b/apps/console/internal/domain/vpn-device.go @@ -41,6 +41,10 @@ func (d *domain) getClusterFromDevice(ctx ConsoleContext, device *entities.Conso return "", errors.Newf("device is nil") } + if device.ProjectName == nil && device.ClusterName != nil { + return *device.ClusterName, nil + } + if device.ProjectName == nil { return "", errors.NewE(errors.Newf("project name is nil")) } @@ -62,13 +66,14 @@ func (d *domain) updateVpnOnCluster(ctx ConsoleContext, ndev, xdev *entities.Con return errors.NewE(err) } - if ndev.ProjectName != nil && ndev.EnvironmentName != nil { + if (ndev.ProjectName != nil && ndev.EnvironmentName != nil) || ndev.ClusterName != nil { if err := d.applyVPNDevice(ctx, ndev); err != nil { return errors.NewE(err) } } - if (xdev.ProjectName != nil) && (*xdev.ProjectName != *ndev.ProjectName) { + if (xdev.ProjectName != nil && (ndev.ProjectName == nil || *xdev.ProjectName != *ndev.ProjectName)) || + (xdev.ClusterName != nil && (ndev.ClusterName == nil || *xdev.ClusterName != *ndev.ClusterName)) { xdev.Spec.Disabled = true if err := d.applyVPNDevice(ctx, xdev); err != nil { return errors.NewE(err) @@ -143,6 +148,14 @@ func (d *domain) applyVPNDevice(ctx ConsoleContext, device *entities.ConsoleVPND if err := d.applyK8sResource(ctx, *device.ProjectName, &device.Device, device.RecordVersion); err != nil { return errors.NewE(err) } + + return nil + } + + if device.ClusterName != nil { + if err := d.applyK8sResourceOnCluster(ctx, *device.ClusterName, &device.Device, device.RecordVersion); err != nil { + return errors.NewE(err) + } } return nil @@ -219,7 +232,39 @@ func (d *domain) CreateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND return nDevice, nil } -func (d *domain) UpdateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPNDevice) (*entities.ConsoleVPNDevice, error) { +func (d *domain) UpdateVpnDeviceNs(ctx ConsoleContext, devName string, namespace string) (device error) { + if err := d.canPerformActionInDevice(ctx, iamT.UpdateVPNDevice, devName); err != nil { + return errors.NewE(err) + } + + xDevice, err := d.findVPNDevice(ctx, devName) + if err != nil { + return errors.NewE(err) + } + + patchForUpdate := common.PatchForUpdate( + ctx, + xDevice, + common.PatchOpts{ + XPatch: repos.Document{ + fc.ConsoleVPNDeviceSpecActiveNamespace: namespace, + }, + }) + + upDevice, err := d.vpnDeviceRepo.PatchById(ctx, xDevice.Id, patchForUpdate) + if err != nil { + return errors.NewE(err) + } + d.resourceEventPublisher.PublishConsoleEvent(ctx, entities.ResourceTypeVPNDevice, devName, PublishUpdate) + + if err := d.applyVPNDevice(ctx, upDevice); err != nil { + return errors.NewE(err) + } + + return nil +} + +func (d *domain) updateVpnDevice(ctx ConsoleContext, device entities.ConsoleVPNDevice, projectName, envName, clusterName *string) (*entities.ConsoleVPNDevice, error) { if err := d.canPerformActionInDevice(ctx, iamT.UpdateVPNDevice, device.Name); err != nil { return nil, errors.NewE(err) } @@ -233,23 +278,35 @@ func (d *domain) UpdateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND device.Spec.ActiveNamespace = nil - if device.ProjectName != nil && device.EnvironmentName != nil { - activeNamespace, err := d.envTargetNamespace(ctx, *device.ProjectName, *device.EnvironmentName) + if clusterName != nil && !slices.Contains(linkedClusters, *clusterName) { + linkedClusters = append(linkedClusters, *clusterName) + } + + if projectName != nil && envName != nil { + activeNamespace, err := d.envTargetNamespace(ctx, *projectName, *envName) if err != nil { return nil, errors.NewE(err) } device.Spec.ActiveNamespace = &activeNamespace - clusterName, err := d.getClusterAttachedToProject(ctx, *device.ProjectName) + cName, err := d.getClusterAttachedToProject(ctx, *projectName) if err != nil { return nil, errors.NewE(err) } - if clusterName != nil && !slices.Contains(linkedClusters, *clusterName) { - linkedClusters = append(linkedClusters, *clusterName) + if cName != nil && !slices.Contains(linkedClusters, *cName) { + linkedClusters = append(linkedClusters, *cName) } } + device.ClusterName = nil + if clusterName != nil { + device.ClusterName = clusterName + + device.ProjectName = nil + device.EnvironmentName = nil + } + patchForUpdate := common.PatchForUpdate( ctx, &device, @@ -258,6 +315,7 @@ func (d *domain) UpdateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND fc.ConsoleVPNDeviceSpec: device.Spec, fields.ProjectName: device.ProjectName, fields.EnvironmentName: device.EnvironmentName, + fields.ClusterName: device.ClusterName, fc.ConsoleVPNDeviceLinkedClusters: linkedClusters, }, }) @@ -279,6 +337,10 @@ func (d *domain) UpdateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPND return upDevice, nil } +func (d *domain) UpdateVPNDevice(ctx ConsoleContext, device entities.ConsoleVPNDevice) (*entities.ConsoleVPNDevice, error) { + return d.updateVpnDevice(ctx, device, device.ProjectName, device.EnvironmentName, nil) +} + func (d *domain) DeleteVPNDevice(ctx ConsoleContext, name string) error { if err := d.canPerformActionInDevice(ctx, iamT.DeleteVPNDevice, name); err != nil { return errors.NewE(err) @@ -356,13 +418,32 @@ func (d *domain) UpdateVpnDeviceEnvironment(ctx ConsoleContext, devName string, xdevice.ProjectName = &projectName xdevice.EnvironmentName = &envName - _, err = d.UpdateVPNDevice(ctx, *xdevice) + _, err = d.updateVpnDevice(ctx, *xdevice, xdevice.ProjectName, xdevice.EnvironmentName, nil) if err != nil { return errors.NewE(err) } return nil } +func (d *domain) UpdateVpnDeviceCluster(ctx ConsoleContext, devName string, clusterName string) error { + d.canPerformActionInAccount(ctx, iamT.GetCluster) + + xdevice, err := d.findVPNDevice(ctx, devName) + if err != nil { + return errors.NewE(err) + } + + // TODO: check if cluster exists in account + + xdevice.ClusterName = &clusterName + _, err = d.updateVpnDevice(ctx, *xdevice, nil, nil, &clusterName) + if err != nil { + return errors.NewE(err) + } + + return nil +} + func (d *domain) OnVPNDeviceUpdateMessage(ctx ConsoleContext, device entities.ConsoleVPNDevice, status types.ResourceStatus, opts UpdateAndDeleteOpts, clusterName string) error { xdevice, err := d.findVPNDevice(ctx, device.Name) if err != nil { diff --git a/apps/console/internal/entities/vpn-device.go b/apps/console/internal/entities/vpn-device.go index e745ba583..3ffe27b91 100644 --- a/apps/console/internal/entities/vpn-device.go +++ b/apps/console/internal/entities/vpn-device.go @@ -20,6 +20,7 @@ type ConsoleVPNDevice struct { AccountName string `json:"accountName" graphql:"noinput"` ProjectName *string `json:"projectName,omitempty"` EnvironmentName *string `json:"environmentName,omitempty"` + ClusterName *string `json:"clusterName,omitempty"` WireguardConfig t.EncodedString `json:"wireguardConfig,omitempty" graphql:"noinput" struct-json-path:",ignore-nesting"` From dcc9328c8e4af565395d7b5d348addb7d1d554a2 Mon Sep 17 00:00:00 2001 From: Abdhesh Nayak Date: Fri, 26 Jan 2024 15:53:26 +0530 Subject: [PATCH 5/5] :lock: Added iam check while getting kubeconfig --- apps/infra/internal/domain/clusters.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/infra/internal/domain/clusters.go b/apps/infra/internal/domain/clusters.go index 34e58f730..68762d3ab 100644 --- a/apps/infra/internal/domain/clusters.go +++ b/apps/infra/internal/domain/clusters.go @@ -64,6 +64,10 @@ func (d *domain) createTokenSecret(ctx InfraContext, ps *entities.CloudProviderS } func (d *domain) GetClusterAdminKubeconfig(ctx InfraContext, clusterName string) (*string, error) { + if err := d.canPerformActionInAccount(ctx, iamT.UpdateCluster); err != nil { + return nil, errors.NewE(err) + } + cluster, err := d.findCluster(ctx, clusterName) if err != nil { return nil, errors.NewE(err)