From 04be35414a032ba1a3ba8d749c2e7eae876f310a Mon Sep 17 00:00:00 2001 From: donggyu Date: Thu, 25 Jan 2024 14:17:02 +0900 Subject: [PATCH 1/8] add keycloak setting --- internal/keycloak/keycloak.go | 180 +++++++++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 1 deletion(-) diff --git a/internal/keycloak/keycloak.go b/internal/keycloak/keycloak.go index 7c3040a6..34a26a8b 100644 --- a/internal/keycloak/keycloak.go +++ b/internal/keycloak/keycloak.go @@ -36,6 +36,12 @@ type IKeycloak interface { JoinGroup(organizationId string, userId string, groupName string) error LeaveGroup(organizationId string, userId string, groupName string) error + CreateClientRoleWithClientName(organizationId string, clientName string, roleName string) error + DeleteClientRoleWithClientName(organizationId string, clientName string, roleName string) error + + AssignClientRoleToUser(organizationId string, userId string, clientName string, roleName string) error + UnassignClientRoleToUser(organizationId string, userId string, clientName string, roleName string) error + VerifyAccessToken(token string, organizationId string) (bool, error) GetSessions(userId string, organizationId string) (*[]string, error) } @@ -115,6 +121,7 @@ func (k *Keycloak) InitializeKeycloak() error { return err } + // for _, defaultMapper := range defaultProtocolTksMapper { if err := k.ensureClientProtocolMappers(ctx, token, DefaultMasterRealm, *tksClient.ClientID, "openid", defaultMapper); err != nil { log.Fatal(err) @@ -446,6 +453,151 @@ func (k *Keycloak) LeaveGroup(organizationId string, userId string, groupName st return nil } + +func (k *Keycloak) CreateClientRoleWithClientName(organizationId string, clientName string, roleName string) error { + ctx := context.Background() + token := k.adminCliToken + + clients, err := k.client.GetClients(ctx, token.AccessToken, organizationId, gocloak.GetClientsParams{ + ClientID: &clientName, + }) + if err != nil { + log.Error("Getting Client is failed", err) + return err + } + + targetClient := clients[0] + + role := gocloak.Role{ + Name: gocloak.StringP(roleName), + } + + _, err = k.client.CreateClientRole(ctx, token.AccessToken, organizationId, *targetClient.ID, role) + if err != nil { + log.Error("Creating Client Role is failed", err) + return err + } + + return nil +} + +func (k *Keycloak) DeleteClientRoleWithClientName(organizationId string, clientName string, roleName string) error { + ctx := context.Background() + token := k.adminCliToken + + clients, err := k.client.GetClients(ctx, token.AccessToken, organizationId, gocloak.GetClientsParams{ + ClientID: &clientName, + }) + if err != nil { + log.Error("Getting Client is failed", err) + return err + } + + targetClient := clients[0] + + roles, err := k.client.GetClientRoles(ctx, token.AccessToken, organizationId, *targetClient.ID, gocloak.GetRoleParams{ + Search: &roleName, + }) + if err != nil { + log.Error("Getting Client Role is failed", err) + return err + } + + if len(roles) == 0 { + log.Warn("Client Role not found", roleName) + return nil + } + + err = k.client.DeleteClientRole(ctx, token.AccessToken, organizationId, *targetClient.ID, *roles[0].ID) + if err != nil { + log.Error("Deleting Client Role is failed", err) + return err + } + + return nil +} + +func (k *Keycloak) AssignClientRoleToUser(organizationId string, userId string, clientName string, roleName string) error { + ctx := context.Background() + token := k.adminCliToken + + clients, err := k.client.GetClients(ctx, token.AccessToken, organizationId, gocloak.GetClientsParams{ + ClientID: &clientName, + }) + if err != nil { + log.Error("Getting Client is failed", err) + return err + } + if len(clients) == 0 { + log.Warn("Client not found", clientName) + return nil + } + + targetClient := clients[0] + + roles, err := k.client.GetClientRoles(ctx, token.AccessToken, organizationId, *targetClient.ID, gocloak.GetRoleParams{ + Search: &roleName, + }) + if err != nil { + log.Error("Getting Client Role is failed", err) + return err + } + + if len(roles) == 0 { + log.Warn("Client Role not found", roleName) + return nil + } + + err = k.client.AddClientRolesToUser(ctx, token.AccessToken, organizationId, userId, *targetClient.ID, []gocloak.Role{*roles[0]}) + + if err != nil { + log.Error("Assigning Client Role to User is failed", err) + return err + } + + return nil +} + +func (k *Keycloak) UnassignClientRoleToUser(organizationId string, userId string, clientName string, roleName string) error { + ctx := context.Background() + token := k.adminCliToken + + clients, err := k.client.GetClients(ctx, token.AccessToken, organizationId, gocloak.GetClientsParams{ + ClientID: &clientName, + }) + if err != nil { + log.Error("Getting Client is failed", err) + return err + } + if len(clients) == 0 { + log.Warn("Client not found", clientName) + return nil + } + + targetClient := clients[0] + + roles, err := k.client.GetClientRoles(ctx, token.AccessToken, organizationId, *targetClient.ID, gocloak.GetRoleParams{ + Search: &roleName, + }) + if err != nil { + log.Error("Getting Client Role is failed", err) + return err + } + + if len(roles) == 0 { + log.Warn("Client Role not found", roleName) + return nil + } + + err = k.client.DeleteClientRolesFromUser(ctx, token.AccessToken, organizationId, userId, *targetClient.ID, []gocloak.Role{*roles[0]}) + if err != nil { + log.Error("Unassigning Client Role to User is failed", err) + return err + } + + return nil +} + func (k *Keycloak) ensureClientProtocolMappers(ctx context.Context, token *gocloak.JWT, realm string, clientId string, scope string, mapper gocloak.ProtocolMapperRepresentation) error { //TODO: Check current logic(if exist, do nothing) is fine @@ -624,6 +776,16 @@ func (k *Keycloak) getClientByClientId(ctx context.Context, accessToken string, return *clients[0].ID, nil } +func (k *Keycloak) createClientRole(ctx context.Context, accessToken string, realm string, clientUuid string, + roleName string) (string, error) { + id, err := k.client.CreateClientRole(ctx, accessToken, realm, clientUuid, gocloak.Role{Name: gocloak.StringP(roleName)}) + if err != nil { + log.Error("Creating Client Role is failed", err) + return "", err + } + return id, nil +} + func (k *Keycloak) getClientRole(ctx context.Context, accessToken string, realm string, clientUuid string, roleName string) (*gocloak.Role, error) { role, err := k.client.GetClientRole(ctx, accessToken, realm, clientUuid, roleName) @@ -695,7 +857,6 @@ func (k *Keycloak) reflectRealmRepresentation(org domain.Organization) *gocloak. } } -// var defaultProtocolTksMapper = make([]gocloak.ProtocolMapperRepresentation, 3) var defaultProtocolTksMapper = []gocloak.ProtocolMapperRepresentation{ { Name: gocloak.StringP("org"), @@ -734,6 +895,23 @@ var defaultProtocolTksMapper = []gocloak.ProtocolMapperRepresentation{ "userinfo.token.claim": "false", }, }, + { + Name: gocloak.StringP("project-role"), + Protocol: gocloak.StringP("openid-connect"), + ProtocolMapper: gocloak.StringP("oidc-usermodel-client-role-mapper"), + Config: &map[string]string{ + "access.token.claim": "true", + "id.token.claim": "false", + "userinfo.token.claim": "false", + + "claim.name": "project-role", + "jsonType.label": "String", + "multivalued": "true", + + "usermodel.clientRoleMapping.clientId": "tks", + "usermodel.clientRoleMapping.role_prefix": "", + }, + }, } func defaultRealmSetting(realmId string) gocloak.RealmRepresentation { From ef5f29c5bfebc53585a3a456612389e100045354 Mon Sep 17 00:00:00 2001 From: donggyu Date: Mon, 29 Jan 2024 12:47:52 +0900 Subject: [PATCH 2/8] add kubernetes setting --- internal/kubernetes/kubernetes.go | 356 ++++++++++++++++++++++++- internal/kubernetes/kubernetes_test.go | 119 ++++++++- 2 files changed, 473 insertions(+), 2 deletions(-) diff --git a/internal/kubernetes/kubernetes.go b/internal/kubernetes/kubernetes.go index 8addc0b1..15ba1411 100644 --- a/internal/kubernetes/kubernetes.go +++ b/internal/kubernetes/kubernetes.go @@ -4,13 +4,14 @@ import ( "bytes" "context" "fmt" - "gopkg.in/yaml.v3" "os" "strings" "github.com/spf13/viper" + rbacV1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/discovery" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" @@ -189,6 +190,359 @@ func GetKubernetesVserion() (string, error) { return information.GitVersion, nil } +func GetKubeconfigById(clusterId string) ([]byte, error) { + clientset, err := GetClientAdminCluster() + if err != nil { + return nil, err + } + + secrets, err := clientset.CoreV1().Secrets(clusterId).Get(context.TODO(), clusterId+"-tks-kubeconfig", metav1.GetOptions{}) + if err != nil { + log.Error(err) + return nil, err + } + + return secrets.Data["value"], nil +} + +func GetResourceApiVersion(kubeconfig []byte, kind string) (string, error) { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return "", err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + apiResourceList, err := clientset.Discovery().ServerPreferredResources() + if err != nil { + log.Error(err) + return "", err + } + + for _, apiResource := range apiResourceList { + for _, resource := range apiResource.APIResources { + if resource.Kind == kind { + return resource.Version, nil + } + } + } + + return "", nil +} + +func EnsureClusterRole(kubeconfig []byte, projectName string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + // generate clusterrole object + for _, role := range []string{leaderRole, memberRole, viewerRole} { + obj := getClusterRole(role, projectName+"-"+role) + + if _, err := clientset.RbacV1().ClusterRoles().Get(context.Background(), projectName+"-"+role, metav1.GetOptions{}); err != nil { + _, err = clientset.RbacV1().ClusterRoles().Create(context.Background(), obj, metav1.CreateOptions{}) + if err != nil { + log.Error(err) + return err + } + } else { + _, err = clientset.RbacV1().ClusterRoles().Update(context.Background(), obj, metav1.UpdateOptions{}) + if err != nil { + log.Error(err) + return err + } + } + } + + return nil +} + +func EnsureClusterRoleBinding(kubeconfig []byte, projectName string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + for _, role := range []string{leaderRole, memberRole, viewerRole} { + obj := generateClusterRoleToClusterRoleBinding(role+"@"+projectName, projectName+"-"+role, projectName+"-"+role) + if _, err = clientset.RbacV1().ClusterRoleBindings().Get(context.Background(), projectName+"-"+role, metav1.GetOptions{}); err != nil { + _, err = clientset.RbacV1().ClusterRoleBindings().Create(context.Background(), obj, metav1.CreateOptions{}) + if err != nil { + log.Error(err) + return err + } + } else { + _, err = clientset.RbacV1().ClusterRoleBindings().Update(context.Background(), obj, metav1.UpdateOptions{}) + if err != nil { + log.Error(err) + return err + } + } + } + + return nil +} + +func RemoveClusterRoleBinding(kubeconfig []byte, projectName string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + for _, role := range []string{leaderRole, memberRole, viewerRole} { + if err := clientset.RbacV1().ClusterRoleBindings().Delete(context.Background(), projectName+"-"+role, metav1.DeleteOptions{}); err != nil { + log.Error(err) + } + } + + return nil +} + +func EnsureRoleBinding(kubeconfig []byte, projectName string, namespace string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + for _, role := range []string{leaderRole, memberRole, viewerRole} { + obj := generateClusterRoleToRoleBinding(role+"@"+projectName, projectName+"-"+role, namespace, projectName+"-"+role) + if _, err = clientset.RbacV1().RoleBindings(namespace).Get(context.Background(), projectName+"-"+role, metav1.GetOptions{}); err != nil { + _, err = clientset.RbacV1().RoleBindings(namespace).Create(context.Background(), obj, metav1.CreateOptions{}) + if err != nil { + log.Error(err) + return err + } + } else { + _, err = clientset.RbacV1().RoleBindings(namespace).Update(context.Background(), obj, metav1.UpdateOptions{}) + if err != nil { + log.Error(err) + return err + } + } + } + + return nil +} + +func RemoveRoleBinding(kubeconfig []byte, projectName string, namespace string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + for _, role := range []string{leaderRole, memberRole, viewerRole} { + if err := clientset.RbacV1().RoleBindings(namespace).Delete(context.Background(), projectName+"-"+role, metav1.DeleteOptions{}); err != nil { + log.Error(err) + } + } + + return nil +} + +const ( + leaderRole = "leader" + memberRole = "member" + viewerRole = "viewer" +) + +func getClusterRole(role, objName string) *rbacV1.ClusterRole { + + clusterRole := rbacV1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: objName, + }, + Rules: []rbacV1.PolicyRule{ + { + Verbs: []string{"*"}, + APIGroups: []string{"*"}, + Resources: []string{"*"}, + }, + }, + } + + switch role { + case leaderRole: + clusterRole.Rules[0].Verbs = []string{"*"} + case memberRole: + clusterRole.Rules[0].Verbs = []string{"*"} + case viewerRole: + clusterRole.Rules[0].Verbs = []string{"get", "list", "watch"} + default: + return nil + } + + return &clusterRole +} + +func EnsureCommonClusterRole(kubeconfig []byte, projectName string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + obj := generateCommonClusterRole(projectName + "-common") + if _, err = clientset.RbacV1().ClusterRoles().Get(context.Background(), projectName+"-common", metav1.GetOptions{}); err != nil { + _, err = clientset.RbacV1().ClusterRoles().Create(context.Background(), obj, metav1.CreateOptions{}) + if err != nil { + log.Error(err) + return err + } + } else { + _, err = clientset.RbacV1().ClusterRoles().Update(context.Background(), obj, metav1.UpdateOptions{}) + if err != nil { + log.Error(err) + return err + } + } + + return nil +} + +func EnsureCommonClusterRoleBinding(kubeconfig []byte, projectName string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + for _, role := range []string{leaderRole, memberRole, viewerRole} { + obj := generateClusterRoleToClusterRoleBinding(role+"@"+projectName, projectName+"-common-"+role, projectName+"-common") + if _, err = clientset.RbacV1().ClusterRoleBindings().Get(context.Background(), projectName+"-common"+"-"+role, metav1.GetOptions{}); err != nil { + _, err = clientset.RbacV1().ClusterRoleBindings().Create(context.Background(), obj, metav1.CreateOptions{}) + if err != nil { + log.Error(err) + return err + } + } else { + _, err = clientset.RbacV1().ClusterRoleBindings().Update(context.Background(), obj, metav1.UpdateOptions{}) + if err != nil { + log.Error(err) + return err + } + } + } + + return nil +} + +func RemoveCommonClusterRoleBinding(kubeconfig []byte, projectName string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + for _, role := range []string{leaderRole, memberRole, viewerRole} { + if err := clientset.RbacV1().ClusterRoles().Delete(context.Background(), projectName+"-common-"+role, metav1.DeleteOptions{}); err != nil { + log.Error(err) + return err + } + } + + return nil +} +func generateCommonClusterRole(objName string) *rbacV1.ClusterRole { + clusterRole := rbacV1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: objName, + }, + Rules: []rbacV1.PolicyRule{ + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{""}, + Resources: []string{"namespaces", "nodes", "storageclasses", "persistentvolumes"}, + }, + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{"storage.k8s.io"}, + Resources: []string{"storageclasses"}, + }, + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{"apiextensions.k8s.io"}, + Resources: []string{"customresourcedefinitions"}, + }, + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{"certificates.k8s.io"}, + Resources: []string{"certificatesigningrequests"}, + }, + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{"rbac.authorization.k8s.io"}, + Resources: []string{"clusterroles", "clusterrolebindings"}, + }, + }, + } + + return &clusterRole +} + +func generateClusterRoleToClusterRoleBinding(groupName, objName, roleName string) *rbacV1.ClusterRoleBinding { + clusterRoleBinding := rbacV1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: objName, + }, + Subjects: []rbacV1.Subject{ + { + Kind: "Group", + Name: groupName, + }, + }, + RoleRef: rbacV1.RoleRef{ + Kind: "ClusterRole", + Name: roleName, + }, + } + + return &clusterRoleBinding +} + +func generateClusterRoleToRoleBinding(groupName, objName, roleName, namespace string) *rbacV1.RoleBinding { + roleBinding := rbacV1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: objName, + Namespace: namespace, + }, + Subjects: []rbacV1.Subject{ + { + Kind: "Group", + Name: groupName, + }, + }, + RoleRef: rbacV1.RoleRef{ + Kind: "ClusterRole", + Name: roleName, + }, + } + + return &roleBinding +} + func MergeKubeconfigsWithSingleUser(kubeconfigs []string) (string, error) { type kubeConfigType struct { APIVersion string `yaml:"apiVersion"` diff --git a/internal/kubernetes/kubernetes_test.go b/internal/kubernetes/kubernetes_test.go index 3f8a578a..6e25b0bb 100644 --- a/internal/kubernetes/kubernetes_test.go +++ b/internal/kubernetes/kubernetes_test.go @@ -2,11 +2,128 @@ package kubernetes_test import ( "github.com/openinfradev/tks-api/internal/kubernetes" - "gopkg.in/yaml.v3" + "os" "reflect" "testing" ) +const path = "/Users/1113433/local_vm_kube/kubeconfig" + +func TestGetResourceApiVersionByClusterId(t *testing.T) { + dat, err := os.ReadFile(path) + if err != nil { + t.Errorf("ReadFile() error = %v", err) + return + } + + res, err := kubernetes.GetResourceApiVersion(dat, "ClusterRole") + if err != nil { + t.Errorf("GetResourceApiVersion() error = %v", err) + return + } + + t.Logf("GetResourceApiVersion() result = %v", res) + +} + +func TestEnsureClusterRole(t *testing.T) { + dat, err := os.ReadFile(path) + if err != nil { + t.Errorf("ReadFile() error = %v", err) + return + } + + err = kubernetes.EnsureClusterRole(dat, "p123") + if err != nil { + t.Errorf("EnsureClusterRole() error = %v", err) + return + } +} + +func TestEnsureCommonClusterRole(t *testing.T) { + dat, err := os.ReadFile(path) + if err != nil { + t.Errorf("ReadFile() error = %v", err) + return + } + + err = kubernetes.EnsureCommonClusterRole(dat, "p123") + if err != nil { + t.Errorf("EnsureClusterRole() error = %v", err) + return + } +} + +func TestEnsureCommonClusterRoleBinding(t *testing.T) { + dat, err := os.ReadFile(path) + if err != nil { + t.Errorf("ReadFile() error = %v", err) + return + } + + err = kubernetes.EnsureCommonClusterRoleBinding(dat, "p123") + if err != nil { + t.Errorf("EnsureClusterRole() error = %v", err) + return + } +} + +func TestEnsureClusterRoleBinding(t *testing.T) { + dat, err := os.ReadFile(path) + if err != nil { + t.Errorf("ReadFile() error = %v", err) + return + } + + err = kubernetes.EnsureClusterRoleBinding(dat, "p123") + if err != nil { + t.Errorf("EnsureClusterRole() error = %v", err) + return + } +} + +func TestEnsureRoleBinding(t *testing.T) { + dat, err := os.ReadFile(path) + if err != nil { + t.Errorf("ReadFile() error = %v", err) + return + } + + err = kubernetes.EnsureRoleBinding(dat, "p123", "test") + if err != nil { + t.Errorf("EnsureClusterRole() error = %v", err) + return + } +} + +func TestRemoveClusterRoleBinding(t *testing.T) { + dat, err := os.ReadFile(path) + if err != nil { + t.Errorf("ReadFile() error = %v", err) + return + } + + err = kubernetes.RemoveClusterRoleBinding(dat, "p123") + if err != nil { + t.Errorf("EnsureClusterRole() error = %v", err) + return + } +} + +func TestRemoveRoleBinding(t *testing.T) { + dat, err := os.ReadFile(path) + if err != nil { + t.Errorf("ReadFile() error = %v", err) + return + } + + err = kubernetes.RemoveRoleBinding(dat, "p123", "test") + if err != nil { + t.Errorf("EnsureClusterRole() error = %v", err) + return + } +} + func TestMergeKubeconfigsWithSingleUser(t *testing.T) { type kubeConfigType struct { APIVersion string `yaml:"apiVersion"` From 6ed4c7704b9a65f67d6b1402eab7e97609fe9921 Mon Sep 17 00:00:00 2001 From: donggyu Date: Mon, 29 Jan 2024 12:51:58 +0900 Subject: [PATCH 3/8] mark not to build auto-gen code --- hack/endpoint-codegen.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hack/endpoint-codegen.go b/hack/endpoint-codegen.go index eff018a0..eba0b574 100644 --- a/hack/endpoint-codegen.go +++ b/hack/endpoint-codegen.go @@ -1,3 +1,5 @@ +//go:build ignore + package main import ( From b5017fdb293a4155d563cf3568afc392700ca640 Mon Sep 17 00:00:00 2001 From: donggyu Date: Fri, 16 Feb 2024 15:25:45 +0900 Subject: [PATCH 4/8] implement keycloak & k8s logic --- internal/delivery/http/project.go | 139 ++++++++++++++++ internal/keycloak/keycloak.go | 4 +- internal/kubernetes/kubernetes.go | 36 +++++ internal/usecase/project.go | 258 +++++++++++++++++++++++++++++- 4 files changed, 434 insertions(+), 3 deletions(-) diff --git a/internal/delivery/http/project.go b/internal/delivery/http/project.go index cc864945..df18232c 100644 --- a/internal/delivery/http/project.go +++ b/internal/delivery/http/project.go @@ -374,6 +374,8 @@ func (p ProjectHandler) UpdateProject(w http.ResponseWriter, r *http.Request) { } func (p ProjectHandler) DeleteProject(w http.ResponseWriter, r *http.Request) { + //ToDo: to donggyu. implement cleanup logic for k8s & keycloak + //TODO implement me } @@ -497,6 +499,17 @@ func (p ProjectHandler) AddProjectMember(w http.ResponseWriter, r *http.Request) return } + pns, err := p.usecase.GetProjectNamespaces(organizationId, projectId) + if err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + var stackIds map[string]struct{} + for _, pn := range pns { + stackIds[pn.StackId] = struct{}{} + } + now := time.Now() for _, pmr := range projectMemberReq.ProjectMemberRequests { pu, err := p.usecase.GetProjectUser(pmr.ProjectUserId) @@ -533,6 +546,15 @@ func (p ProjectHandler) AddProjectMember(w http.ResponseWriter, r *http.Request) ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return } + + // tasks for keycloak & k8s + for stackId := range stackIds { + if err := p.usecase.AssignKeycloakClientRoleToMember(organizationId, projectId, stackId, pmId); err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + } } out := domain.CommonProjectResponse{Result: "OK"} @@ -768,6 +790,26 @@ func (p ProjectHandler) RemoveProjectMember(w http.ResponseWriter, r *http.Reque "C_INVALID_PROJECT_MEMBER_ID", "")) return } + + // tasks for keycloak & k8s + pns, err := p.usecase.GetProjectNamespaces(organizationId, projectId) + if err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + var stackIds map[string]struct{} + for _, pn := range pns { + stackIds[pn.StackId] = struct{}{} + } + for stackId := range stackIds { + if err := p.usecase.UnassignKeycloakClientRoleToMember(organizationId, projectId, stackId, projectMemberId); err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + } + if err := p.usecase.RemoveProjectMember(projectMemberId); err != nil { ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return @@ -812,8 +854,29 @@ func (p ProjectHandler) RemoveProjectMembers(w http.ResponseWriter, r *http.Requ return } + // tasks for keycloak & k8s + pns, err := p.usecase.GetProjectNamespaces(organizationId, projectId) + if err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + var stackIds map[string]struct{} + for _, pn := range pns { + stackIds[pn.StackId] = struct{}{} + } + // TODO: change multi row delete for _, pm := range projectMemberReq.ProjectMember { + // tasks for keycloak & k8s + for stackId := range stackIds { + if err := p.usecase.UnassignKeycloakClientRoleToMember(organizationId, projectId, stackId, pm.ProjectMemberId); err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + } + if err := p.usecase.RemoveProjectMember(pm.ProjectMemberId); err != nil { ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return @@ -879,6 +942,25 @@ func (p ProjectHandler) UpdateProjectMemberRole(w http.ResponseWriter, r *http.R return } + pns, err := p.usecase.GetProjectNamespaces(organizationId, projectId) + if err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + var stackIds map[string]struct{} + for _, pn := range pns { + stackIds[pn.StackId] = struct{}{} + } + // tasks for keycloak & k8s. Unassign old role + for stackId := range stackIds { + if err := p.usecase.UnassignKeycloakClientRoleToMember(organizationId, projectId, stackId, projectMemberId); err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + } + pm.ProjectRoleId = pmrReq.ProjectRoleId pm.ProjectUser = nil pm.ProjectRole = nil @@ -888,6 +970,14 @@ func (p ProjectHandler) UpdateProjectMemberRole(w http.ResponseWriter, r *http.R ErrorJSON(w, r, err) return } + // tasks for keycloak & k8s. Assign new role + for stackId := range stackIds { + if err := p.usecase.AssignKeycloakClientRoleToMember(organizationId, projectId, stackId, projectMemberId); err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + } ResponseJSON(w, r, http.StatusOK, domain.CommonProjectResponse{Result: "OK"}) } @@ -929,6 +1019,17 @@ func (p ProjectHandler) UpdateProjectMembersRole(w http.ResponseWriter, r *http. return } + pns, err := p.usecase.GetProjectNamespaces(organizationId, projectId) + if err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + var stackIds map[string]struct{} + for _, pn := range pns { + stackIds[pn.StackId] = struct{}{} + } + for _, pmr := range projectMemberReq.ProjectMemberRoleRequests { pm, err := p.usecase.GetProjectMember(pmr.ProjectMemberId) if err != nil { @@ -942,6 +1043,14 @@ func (p ProjectHandler) UpdateProjectMembersRole(w http.ResponseWriter, r *http. return } + for stackId := range stackIds { + if err := p.usecase.UnassignKeycloakClientRoleToMember(organizationId, projectId, stackId, pm.ID); err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + } + pm.ProjectRoleId = pmr.ProjectRoleId pm.ProjectUser = nil pm.ProjectRole = nil @@ -951,6 +1060,14 @@ func (p ProjectHandler) UpdateProjectMembersRole(w http.ResponseWriter, r *http. ErrorJSON(w, r, err) return } + + for stackId := range stackIds { + if err := p.usecase.AssignKeycloakClientRoleToMember(organizationId, projectId, stackId, pm.ID); err != nil { + log.Error(err) + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + } } ResponseJSON(w, r, http.StatusOK, domain.CommonProjectResponse{Result: "OK"}) @@ -1000,6 +1117,16 @@ func (p ProjectHandler) CreateProjectNamespace(w http.ResponseWriter, r *http.Re CreatedAt: now, } + // tasks for keycloak & k8s + if err := p.usecase.EnsureRequiredSetupForCluster(organizationId, projectId, projectNamespaceReq.StackId); err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + if err := p.usecase.CreateK8SNSRoleBinding(organizationId, projectId, projectNamespaceReq.StackId, projectNamespaceReq.Namespace); err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + if err := p.usecase.CreateProjectNamespace(organizationId, pn); err != nil { ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return @@ -1267,6 +1394,18 @@ func (p ProjectHandler) UpdateProjectNamespace(w http.ResponseWriter, r *http.Re // @Router /organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId} [delete] // @Security JWT func (p ProjectHandler) DeleteProjectNamespace(w http.ResponseWriter, r *http.Request) { + + //ToDo: from donggyu. uncomment lines below after implementing usecase.DeleteProjectNamespace. + // tasks for keycloak & k8s + /*if err := p.usecase.DeleteK8SNSRoleBinding(organizationId, projectId, stackId, projectNamespace); err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + if err := p.usecase.MayRemoveRequiredSetupForCluster(organizationId, projectId, stackId); err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + }*/ + //TODO implement me //vars := mux.Vars(r) diff --git a/internal/keycloak/keycloak.go b/internal/keycloak/keycloak.go index 34a26a8b..4c41f89c 100644 --- a/internal/keycloak/keycloak.go +++ b/internal/keycloak/keycloak.go @@ -36,7 +36,7 @@ type IKeycloak interface { JoinGroup(organizationId string, userId string, groupName string) error LeaveGroup(organizationId string, userId string, groupName string) error - CreateClientRoleWithClientName(organizationId string, clientName string, roleName string) error + EnsureClientRoleWithClientName(organizationId string, clientName string, roleName string) error DeleteClientRoleWithClientName(organizationId string, clientName string, roleName string) error AssignClientRoleToUser(organizationId string, userId string, clientName string, roleName string) error @@ -454,7 +454,7 @@ func (k *Keycloak) LeaveGroup(organizationId string, userId string, groupName st return nil } -func (k *Keycloak) CreateClientRoleWithClientName(organizationId string, clientName string, roleName string) error { +func (k *Keycloak) EnsureClientRoleWithClientName(organizationId string, clientName string, roleName string) error { ctx := context.Background() token := k.adminCliToken diff --git a/internal/kubernetes/kubernetes.go b/internal/kubernetes/kubernetes.go index 15ba1411..0fef1084 100644 --- a/internal/kubernetes/kubernetes.go +++ b/internal/kubernetes/kubernetes.go @@ -262,6 +262,25 @@ func EnsureClusterRole(kubeconfig []byte, projectName string) error { return nil } +func RemoveClusterRole(kubeconfig []byte, projectName string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + // remove clusterrole object + for _, role := range []string{leaderRole, memberRole, viewerRole} { + if err := clientset.RbacV1().ClusterRoles().Delete(context.Background(), projectName+"-"+role, metav1.DeleteOptions{}); err != nil { + log.Error(err) + } + } + + return nil +} + func EnsureClusterRoleBinding(kubeconfig []byte, projectName string) error { config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) if err != nil { @@ -418,6 +437,23 @@ func EnsureCommonClusterRole(kubeconfig []byte, projectName string) error { return nil } +func RemoveCommonClusterRole(kubeconfig []byte, projectName string) error { + config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) + if err != nil { + log.Error(err) + return err + } + + clientset := kubernetes.NewForConfigOrDie(config_user) + + if err := clientset.RbacV1().ClusterRoles().Delete(context.Background(), projectName+"-common", metav1.DeleteOptions{}); err != nil { + log.Error(err) + return err + } + + return nil +} + func EnsureCommonClusterRoleBinding(kubeconfig []byte, projectName string) error { config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) if err != nil { diff --git a/internal/usecase/project.go b/internal/usecase/project.go index 4817bff8..3da7f748 100644 --- a/internal/usecase/project.go +++ b/internal/usecase/project.go @@ -3,6 +3,8 @@ package usecase import ( "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/kubernetes" + "github.com/openinfradev/tks-api/internal/keycloak" + "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/repository" "github.com/openinfradev/tks-api/internal/serializer" argowf "github.com/openinfradev/tks-api/pkg/argo-client" @@ -41,9 +43,18 @@ type IProjectUsecase interface { GetProjectNamespace(organizationId string, projectId string, projectNamespace string, stackId string) (*domain.ProjectNamespace, error) UpdateProjectNamespace(pn *domain.ProjectNamespace) error DeleteProjectNamespace(organizationId string, projectId string, projectNamespace string, stackId string) error + + EnsureRequiredSetupForCluster(organizationId string, projectId string, stackId string) error + MayRemoveRequiredSetupForCluster(organizationId string, projectId string, stackId string) error + + CreateK8SNSRoleBinding(organizationId string, projectId string, stackId string, namespace string) error + DeleteK8SNSRoleBinding(organizationId string, projectId string, stackId string, namespace string) error GetProjectKubeconfig(organizationId string, projectId string) (string, error) } + AssignKeycloakClientRoleToMember(organizationId string, projectId string, stackId string, projectMemberId string) error + UnassignKeycloakClientRoleToMember(organizationId string, projectId string, stackId string, projectMemberId string) error +} type ProjectUsecase struct { projectRepo repository.IProjectRepository userRepository repository.IUserRepository @@ -52,9 +63,10 @@ type ProjectUsecase struct { appgroupRepository repository.IAppGroupRepository organizationRepository repository.IOrganizationRepository argo argowf.ArgoClient + kc keycloak.IKeycloak } -func NewProjectUsecase(r repository.Repository, argoClient argowf.ArgoClient) IProjectUsecase { +func NewProjectUsecase(r repository.Repository, kc keycloak.IKeycloak, argoClient argowf.ArgoClient) IProjectUsecase { return &ProjectUsecase{ projectRepo: r.Project, userRepository: r.User, @@ -63,6 +75,7 @@ func NewProjectUsecase(r repository.Repository, argoClient argowf.ArgoClient) IP appgroupRepository: r.AppGroup, organizationRepository: r.Organization, argo: argoClient, + kc: kc, } } @@ -72,6 +85,7 @@ func (u *ProjectUsecase) CreateProject(p *domain.Project) (string, error) { log.Error(err) return "", errors.Wrap(err, "Failed to create project.") } + return projectId, nil } @@ -360,6 +374,248 @@ func (u *ProjectUsecase) DeleteProjectNamespace(organizationId string, projectId return nil } +func (u *ProjectUsecase) EnsureRequiredSetupForCluster(organizationId string, projectId string, stackId string) error { + pns, err := u.projectRepo.GetProjectNamespaces(organizationId, projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + var alreadySetUp bool + for _, pn := range pns { + if pn.StackId == stackId { + alreadySetUp = true + break + } + } + + // if already set up, it means that required setup is already done + if alreadySetUp { + return nil + } + + if err := u.createK8SInitialResource(organizationId, projectId, stackId); err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + if err := u.createKeycloakClientRoles(organizationId, projectId, stackId); err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + projectMembers, err := u.GetProjectMembersByProjectId(projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + for _, pm := range projectMembers { + err = u.assignEachKeycloakClientRoleToMember(organizationId, projectId, stackId, pm.ProjectUserId.String(), pm.ProjectRole.Name) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + } + + return nil +} +func (u *ProjectUsecase) MayRemoveRequiredSetupForCluster(organizationId string, projectId string, stackId string) error { + pns, err := u.projectRepo.GetProjectNamespaces(organizationId, projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + var nsCount int + for _, pn := range pns { + if pn.StackId == stackId { + nsCount++ + } + } + + // if there are more than one namespace, it means that required setup is needed on the other namespace + if nsCount > 1 { + return nil + } + + if err := u.deleteK8SInitialResource(organizationId, projectId, stackId); err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + projectMembers, err := u.GetProjectMembersByProjectId(projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + for _, pm := range projectMembers { + err = u.unassignKeycloakClientRoleToMember(organizationId, projectId, stackId, pm.ProjectUserId.String(), pm.ProjectRole.Name) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + } + + if err := u.deleteKeycloakClientRoles(organizationId, projectId, stackId); err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + return nil +} +func (u *ProjectUsecase) createK8SInitialResource(organizationId string, projectId string, stackId string) error { + kubeconfig, err := kubernetes.GetKubeConfig(stackId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + pr, err := u.GetProject(organizationId, projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + err = kubernetes.EnsureClusterRole(kubeconfig, pr.Name) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + err = kubernetes.EnsureCommonClusterRole(kubeconfig, pr.Name) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + err = kubernetes.EnsureCommonClusterRoleBinding(kubeconfig, pr.Name) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + return nil +} +func (u *ProjectUsecase) deleteK8SInitialResource(organizationId string, projectId string, stackId string) error { + kubeconfig, err := kubernetes.GetKubeConfig(stackId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + pr, err := u.GetProject(organizationId, projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + err = kubernetes.RemoveClusterRole(kubeconfig, pr.Name) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + err = kubernetes.RemoveCommonClusterRole(kubeconfig, pr.Name) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + err = kubernetes.RemoveCommonClusterRoleBinding(kubeconfig, pr.Name) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + return nil +} +func (u *ProjectUsecase) createKeycloakClientRoles(organizationId string, projectId string, stackId string) error { + // create Roles in keycloak + for _, role := range []string{string(ProjectLeader), string(ProjectMember), string(ProjectViewer)} { + err := u.kc.EnsureClientRoleWithClientName(organizationId, stackId+"-k8s-api", role+"@"+projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + } + return nil +} +func (u *ProjectUsecase) deleteKeycloakClientRoles(organizationId string, projectId string, stackId string) error { + // first check whether the stac + + // delete Roles in keycloak + for _, role := range []string{string(ProjectLeader), string(ProjectMember), string(ProjectViewer)} { + err := u.kc.DeleteClientRoleWithClientName(organizationId, stackId+"-k8s-api", role+"@"+projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + } + return nil +} +func (u *ProjectUsecase) CreateK8SNSRoleBinding(organizationId string, projectId string, stackId string, namespace string) error { + kubeconfig, err := kubernetes.GetKubeConfig(stackId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + pr, err := u.GetProject(organizationId, projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + err = kubernetes.EnsureRoleBinding(kubeconfig, pr.Name, namespace) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + + return nil +} +func (u *ProjectUsecase) DeleteK8SNSRoleBinding(organizationId string, projectId string, stackId string, namespace string) error { + //TODO implement me + panic("implement me") +} + +func (u *ProjectUsecase) AssignKeycloakClientRoleToMember(organizationId string, projectId string, stackId string, projectMemberId string) error { + pm, err := u.GetProjectMember(projectMemberId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + err = u.assignEachKeycloakClientRoleToMember(organizationId, projectId, stackId, pm.ProjectUserId.String(), pm.ProjectRole.Name) + return nil +} + +func (u *ProjectUsecase) assignEachKeycloakClientRoleToMember(organizationId string, projectId string, stackId string, userId string, roleName string) error { + err := u.kc.AssignClientRoleToUser(organizationId, userId, stackId+"-k8s-api", roleName+"@"+projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + return nil +} + +func (u *ProjectUsecase) UnassignKeycloakClientRoleToMember(organizationId string, projectId string, stackId string, projectMemberId string) error { + pm, err := u.GetProjectMember(projectMemberId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + err = u.unassignKeycloakClientRoleToMember(organizationId, projectId, stackId, pm.ProjectUserId.String(), pm.ProjectRole.Name) + return nil +} + +func (u *ProjectUsecase) unassignKeycloakClientRoleToMember(organizationId string, projectId string, stackId string, userId string, roleName string) error { + err := u.kc.UnassignClientRoleToUser(organizationId, userId, stackId+"-k8s-api", roleName+"@"+projectId) + if err != nil { + log.Error(err) + return errors.Wrap(err, "Failed to create project namespace.") + } + return nil +} + func (u *ProjectUsecase) GetProjectKubeconfig(organizationId string, projectId string) (string, error) { projectNamespaces, err := u.projectRepo.GetProjectNamespaces(organizationId, projectId) if err != nil { From a40aff092eb91f81563880812bfc9bf8d3f425cf Mon Sep 17 00:00:00 2001 From: donggyu Date: Wed, 21 Feb 2024 13:43:48 +0900 Subject: [PATCH 5/8] merge up-to-date commits --- internal/kubernetes/kubernetes.go | 1 + internal/kubernetes/kubernetes_test.go | 1 + 2 files changed, 2 insertions(+) diff --git a/internal/kubernetes/kubernetes.go b/internal/kubernetes/kubernetes.go index 0fef1084..0c8fb3b0 100644 --- a/internal/kubernetes/kubernetes.go +++ b/internal/kubernetes/kubernetes.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "gopkg.in/yaml.v3" "os" "strings" diff --git a/internal/kubernetes/kubernetes_test.go b/internal/kubernetes/kubernetes_test.go index 6e25b0bb..9505998b 100644 --- a/internal/kubernetes/kubernetes_test.go +++ b/internal/kubernetes/kubernetes_test.go @@ -2,6 +2,7 @@ package kubernetes_test import ( "github.com/openinfradev/tks-api/internal/kubernetes" + "gopkg.in/yaml.v3" "os" "reflect" "testing" From 89c05f14983acd5e831c0eca3a9a358ff087bf3e Mon Sep 17 00:00:00 2001 From: donggyu Date: Wed, 21 Feb 2024 13:44:03 +0900 Subject: [PATCH 6/8] merge up-to-date commits --- internal/delivery/http/project.go | 10 +++++----- internal/usecase/project.go | 6 ++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/internal/delivery/http/project.go b/internal/delivery/http/project.go index df18232c..55f3f5de 100644 --- a/internal/delivery/http/project.go +++ b/internal/delivery/http/project.go @@ -505,7 +505,7 @@ func (p ProjectHandler) AddProjectMember(w http.ResponseWriter, r *http.Request) ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return } - var stackIds map[string]struct{} + stackIds := make(map[string]struct{}) for _, pn := range pns { stackIds[pn.StackId] = struct{}{} } @@ -798,7 +798,7 @@ func (p ProjectHandler) RemoveProjectMember(w http.ResponseWriter, r *http.Reque ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return } - var stackIds map[string]struct{} + stackIds := make(map[string]struct{}) for _, pn := range pns { stackIds[pn.StackId] = struct{}{} } @@ -861,7 +861,7 @@ func (p ProjectHandler) RemoveProjectMembers(w http.ResponseWriter, r *http.Requ ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return } - var stackIds map[string]struct{} + stackIds := make(map[string]struct{}) for _, pn := range pns { stackIds[pn.StackId] = struct{}{} } @@ -948,7 +948,7 @@ func (p ProjectHandler) UpdateProjectMemberRole(w http.ResponseWriter, r *http.R ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return } - var stackIds map[string]struct{} + stackIds := make(map[string]struct{}) for _, pn := range pns { stackIds[pn.StackId] = struct{}{} } @@ -1025,7 +1025,7 @@ func (p ProjectHandler) UpdateProjectMembersRole(w http.ResponseWriter, r *http. ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) return } - var stackIds map[string]struct{} + stackIds := make(map[string]struct{}) for _, pn := range pns { stackIds[pn.StackId] = struct{}{} } diff --git a/internal/usecase/project.go b/internal/usecase/project.go index 3da7f748..67f9f476 100644 --- a/internal/usecase/project.go +++ b/internal/usecase/project.go @@ -2,7 +2,6 @@ package usecase import ( "github.com/google/uuid" - "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/keycloak" "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/repository" @@ -50,7 +49,6 @@ type IProjectUsecase interface { CreateK8SNSRoleBinding(organizationId string, projectId string, stackId string, namespace string) error DeleteK8SNSRoleBinding(organizationId string, projectId string, stackId string, namespace string) error GetProjectKubeconfig(organizationId string, projectId string) (string, error) -} AssignKeycloakClientRoleToMember(organizationId string, projectId string, stackId string, projectMemberId string) error UnassignKeycloakClientRoleToMember(organizationId string, projectId string, stackId string, projectMemberId string) error @@ -404,7 +402,7 @@ func (u *ProjectUsecase) EnsureRequiredSetupForCluster(organizationId string, pr return errors.Wrap(err, "Failed to create project namespace.") } - projectMembers, err := u.GetProjectMembersByProjectId(projectId) + projectMembers, err := u.GetProjectMembers(projectId, ProjectAll) if err != nil { log.Error(err) return errors.Wrap(err, "Failed to create project namespace.") @@ -442,7 +440,7 @@ func (u *ProjectUsecase) MayRemoveRequiredSetupForCluster(organizationId string, return errors.Wrap(err, "Failed to create project namespace.") } - projectMembers, err := u.GetProjectMembersByProjectId(projectId) + projectMembers, err := u.GetProjectMembers(projectId, ProjectAll) if err != nil { log.Error(err) return errors.Wrap(err, "Failed to create project namespace.") From 3c7c91c5157c5639ed802fb41ae3168576861b07 Mon Sep 17 00:00:00 2001 From: donggyu Date: Mon, 26 Feb 2024 14:25:39 +0900 Subject: [PATCH 7/8] remove unused function --- internal/kubernetes/kubernetes.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/internal/kubernetes/kubernetes.go b/internal/kubernetes/kubernetes.go index 0c8fb3b0..2af15b06 100644 --- a/internal/kubernetes/kubernetes.go +++ b/internal/kubernetes/kubernetes.go @@ -191,21 +191,6 @@ func GetKubernetesVserion() (string, error) { return information.GitVersion, nil } -func GetKubeconfigById(clusterId string) ([]byte, error) { - clientset, err := GetClientAdminCluster() - if err != nil { - return nil, err - } - - secrets, err := clientset.CoreV1().Secrets(clusterId).Get(context.TODO(), clusterId+"-tks-kubeconfig", metav1.GetOptions{}) - if err != nil { - log.Error(err) - return nil, err - } - - return secrets.Data["value"], nil -} - func GetResourceApiVersion(kubeconfig []byte, kind string) (string, error) { config_user, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) if err != nil { From eedf6b37d186bf5ad26c06baabd8adb299a0d411 Mon Sep 17 00:00:00 2001 From: donggyu Date: Mon, 26 Feb 2024 14:29:27 +0900 Subject: [PATCH 8/8] solve confict --- internal/route/route.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/route/route.go b/internal/route/route.go index e97a514a..e3419bee 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -80,7 +80,7 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa Dashboard: usecase.NewDashboardUsecase(repoFactory, cache), Alert: usecase.NewAlertUsecase(repoFactory), Stack: usecase.NewStackUsecase(repoFactory, argoClient, usecase.NewDashboardUsecase(repoFactory, cache)), - Project: usecase.NewProjectUsecase(repoFactory, argoClient), + Project: usecase.NewProjectUsecase(repoFactory, kc, argoClient), } customMiddleware := internalMiddleware.NewMiddleware(