Skip to content

Commit

Permalink
Merge pull request #342 from kube-tarian/feature/cluster_delete
Browse files Browse the repository at this point in the history
delete cluster is pushed
  • Loading branch information
vramk23 authored Dec 16, 2023
2 parents 5e441d0 + 54dc52a commit 77dbeca
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 9 deletions.
173 changes: 164 additions & 9 deletions capten/agent/internal/crossplane/cluster_claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"

"github.com/google/uuid"
"github.com/intelops/go-common/credentials"
"github.com/intelops/go-common/logging"
captenstore "github.com/kube-tarian/kad/capten/agent/internal/capten-store"
"github.com/kube-tarian/kad/capten/agent/internal/temporalclient"
Expand All @@ -24,15 +25,17 @@ import (
var (
readyStatusType = "ready"

clusterNotReadyStatus = "NotReady"
clusterReadyStatus = "Ready"
readyStatusValue = "True"
NorReadyStatusValue = "False"
clusterSecretName = "%s-cluster"
kubeConfig = "kubeconfig"
k8sEndpoint = "endpoint"
k8sClusterCA = "clusterCA"
managedClusterEntityName = "managedcluster"
clusterNotReadyStatus = "NotReady"
clusterReadyStatus = "Ready"
clusterDeletingStatus = "Deleting"
clusterFailedToDeleteStatus = "FailedToDelete"
readyStatusValue = "True"
NorReadyStatusValue = "False"
clusterSecretName = "%s-cluster"
kubeConfig = "kubeconfig"
k8sEndpoint = "endpoint"
k8sClusterCA = "clusterCA"
managedClusterEntityName = "managedcluster"
)

var (
Expand Down Expand Up @@ -119,6 +122,18 @@ func (h *ClusterClaimSyncHandler) OnUpdate(oldObj, newObj interface{}) {

func (h *ClusterClaimSyncHandler) OnDelete(obj interface{}) {
h.log.Info("Crossplane ClusterCliam Delete Callback")

newCcObj, err := getClusterClaimObj(obj)
if newCcObj == nil {
h.log.Errorf("failed to read ClusterCliam object, %v", err)
return
}

if err = h.deleteManagedClusters(*newCcObj); err != nil {
h.log.Errorf("failed to delete ClusterCliam object, %v", err)
return
}

}

func (h *ClusterClaimSyncHandler) Sync() error {
Expand Down Expand Up @@ -149,6 +164,11 @@ func (h *ClusterClaimSyncHandler) Sync() error {
return fmt.Errorf("failed to update clusters in DB, %v", err)
}
h.log.Info("cluster-claims resources synched")

if err := h.syncClusterClaimsWithDB(clObj.Items); err != nil {
return fmt.Errorf("failed to sync clusters in DB, %v", err)
}

return nil
}

Expand Down Expand Up @@ -267,3 +287,138 @@ func (h *ClusterClaimSyncHandler) getClusterClaimStatus(conditions []model.Clust
}
return
}

func (h *ClusterClaimSyncHandler) deleteManagedClusters(clusterCliam model.ClusterClaim) error {

clusters, err := h.getManagedClusters()
if err != nil {
return fmt.Errorf("failed to get managed clusters from DB, %v", err)
}

var clusterFound bool
var managedCluster *captenpluginspb.ManagedCluster
for _, v := range clusters {
if v.ClusterName == clusterCliam.Metadata.Name {
clusterFound = true
managedCluster = v
break
}
}

if !clusterFound {
h.log.Info("failed to delete managed cluster from DB, %s Cluster is not stored in ManagedClusters table", clusterCliam.Metadata.Name)
return nil
}

managedCluster.ClusterDeployStatus = clusterDeletingStatus
if err := h.dbStore.UpsertManagedCluster(managedCluster); err != nil {
return fmt.Errorf("failed to update managed cluster from DB, %v", err)
}

err = h.triggerClusterDelete(clusterCliam.Spec.Id, managedCluster)
if err != nil {
return fmt.Errorf("failed to trigger cluster delete workflow, %v", err)
}

h.log.Infof("triggered cluster delete workflow for cluster %s", managedCluster.ClusterName)

return nil
}

func (h *ClusterClaimSyncHandler) triggerClusterDelete(clusterName string, managedCluster *captenpluginspb.ManagedCluster) error {
wd := workers.NewConfig(h.tc, h.log)

proj, err := h.dbStore.GetCrossplaneProject()
if err != nil {
return err
}
ci := model.CrossplaneClusterUpdate{RepoURL: proj.GitProjectUrl, GitProjectId: proj.GitProjectId,
ManagedClusterName: clusterName, ManagedClusterId: managedCluster.Id}

wkfId, err := wd.SendAsyncEvent(context.TODO(), &model.ConfigureParameters{Resource: model.CrossPlaneResource, Action: model.CrossPlaneProjectDelete}, ci)
if err != nil {
managedCluster.ClusterDeployStatus = clusterFailedToDeleteStatus
if err := h.dbStore.UpsertManagedCluster(managedCluster); err != nil {
return fmt.Errorf("failed to update managed cluster from DB, %v", err)
}
return fmt.Errorf("failed to send event to workflow to configure %s, %v", managedCluster.ClusterEndpoint, err)
}

h.log.Infof("Crossplane project delete %s config workflow %s created", managedCluster.ClusterEndpoint, wkfId)

go h.monitorCrossplaneWorkflow(managedCluster, wkfId)

return nil
}

func (h *ClusterClaimSyncHandler) monitorCrossplaneWorkflow(managedCluster *captenpluginspb.ManagedCluster, wkfId string) {
// during system reboot start monitoring, add it in map or somewhere.
wd := workers.NewConfig(h.tc, h.log)
_, err := wd.GetWorkflowInformation(context.TODO(), wkfId)
if err != nil {
managedCluster.ClusterDeployStatus = clusterFailedToDeleteStatus
if err := h.dbStore.UpsertManagedCluster(managedCluster); err != nil {
h.log.Errorf("failed to update managed cluster from DB, %v", err)
return
}
h.log.Errorf("failed to send event to workflow to configure %s, %v", managedCluster.ClusterEndpoint, err)
return
}

if err := h.dbStore.DeleteManagedClusterById(managedCluster.Id); err != nil {
h.log.Errorf("failed to delete managed cluster from DB, %v", err)
return
}

if err = h.deleteManagedClusterCredential(context.TODO(), managedCluster.Id); err != nil {
h.log.Errorf("failed to delete credential for %s, %v", managedCluster.Id, err)
return
}

h.log.Infof("Crossplane project delete %s config workflow %s completed", managedCluster.ClusterEndpoint, wkfId)
}

func (h *ClusterClaimSyncHandler) deleteManagedClusterCredential(ctx context.Context, id string) error {
credPath := fmt.Sprintf("%s/%s/%s", credentials.GenericCredentialType, managedClusterEntityName, id)
credAdmin, err := credentials.NewCredentialAdmin(ctx)
if err != nil {
h.log.Audit("security", "storecred", "failed", "system", "failed to intialize credentials client for %s", credPath)
h.log.Errorf("failed to delete credential for %s, %v", credPath, err)
return err
}

err = credAdmin.DeleteCredential(ctx, credentials.GenericCredentialType, managedClusterEntityName, id)
if err != nil {
h.log.Audit("security", "storecred", "failed", "system", "failed to store crendential for %s", credPath)
h.log.Errorf("failed to delete credential for %s, %v", credPath, err)
return err
}
h.log.Audit("security", "storecred", "success", "system", "credential stored for %s", credPath)
h.log.Infof("deleted credential for entity %s", credPath)
return nil
}

func (h *ClusterClaimSyncHandler) syncClusterClaimsWithDB(clusterClaims []model.ClusterClaim) error {

clusters, err := h.getManagedClusters()
if err != nil {
return fmt.Errorf("failed to get managed clusters from DB, %v", err)
}

for _, cm := range clusterClaims {
var isDeleteManagedCluster = true
for _, c := range clusters {
if c.ClusterName == cm.Metadata.Name {
isDeleteManagedCluster = false
break
}
}

if isDeleteManagedCluster {
if err = h.deleteManagedClusters(cm); err != nil {
return fmt.Errorf("failed to delete ClusterCliam object, %v", err)
}
}
}
return nil
}
3 changes: 3 additions & 0 deletions capten/agent/internal/crossplane/package_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ func (h *ProvidersSyncHandler) updateCrossplaneProvider(k8sProviders []model.Pro
ProviderName: dbProvider.ProviderName,
}

v, _ := json.Marshal(provider)
fmt.Println("Provider ===>" + string(v))

if err := h.dbStore.UpdateCrossplaneProvider(&provider); err != nil {
h.log.Errorf("failed to update provider %s details in db, %v", k8sProvider.Name, err)
continue
Expand Down
12 changes: 12 additions & 0 deletions capten/config-worker/internal/crossplane/activity.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ func processConfigurationActivity(ctx context.Context, params model.ConfigurePar
return string(model.WorkFlowStatusFailed), fmt.Errorf("failed to configure crossplane project")
}
return status, nil
case model.CrossPlaneProjectDelete:
reqLocal := &model.CrossplaneClusterUpdate{}
if err := json.Unmarshal(payload, reqLocal); err != nil {
logger.Errorf("failed to unmarshall the crossplane req for %s, %v", model.CrossPlaneClusterUpdate, err)
return string(model.WorkFlowStatusFailed), fmt.Errorf("failed to unmarshall the crossplane req for %s", model.CrossPlaneClusterUpdate)
}
status, err := cp.configureClusterDelete(ctx, reqLocal)
if err != nil {
logger.Errorf("failed to configure crossplane project for %s, %v", model.CrossPlaneClusterUpdate, err)
return status, fmt.Errorf("failed to configure crossplane project for %s", model.CrossPlaneClusterUpdate)
}
return status, nil
default:
return string(model.WorkFlowStatusFailed), fmt.Errorf("invalid crossplane action")
}
Expand Down
90 changes: 90 additions & 0 deletions capten/config-worker/internal/crossplane/config_cluster_updates.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,96 @@ func (cp *CrossPlaneApp) syncDefaultAppVaules(clusterName, defaultAppVaulesPath,
return nil
}

func (cp *CrossPlaneApp) configureClusterDelete(ctx context.Context, req *model.CrossplaneClusterUpdate) (status string, err error) {
logger.Infof("configuring crossplane project for cluster %s delete", req.ManagedClusterName)

accessToken, err := cp.helper.GetAccessToken(ctx, req.GitProjectId)
if err != nil {
return string(agentmodel.WorkFlowStatusFailed), errors.WithMessage(err, "failed to get token from vault")
}

logger.Infof("cloning default templates %s to project %s", cp.pluginConfig.TemplateGitRepo, req.RepoURL)
_, customerRepo, err := cp.helper.CloneRepos(ctx, cp.pluginConfig.TemplateGitRepo, req.RepoURL, accessToken)
if err != nil {
return string(agentmodel.WorkFlowStatusFailed), errors.WithMessage(err, "failed to clone repos")
}
logger.Infof("cloned default templates to project %s", req.RepoURL)

defer os.RemoveAll(customerRepo)

clusterValuesFile := filepath.Join(customerRepo, cp.pluginConfig.ClusterEndpointUpdates.ClusterValuesFile)
err = removeClusterValues(clusterValuesFile, req.ManagedClusterName)
if err != nil {
return string(agentmodel.WorkFlowStatusFailed), errors.WithMessage(err, "failed to replace the file")
}

dirToDelete := filepath.Join(customerRepo, cp.pluginConfig.ClusterEndpointUpdates.ClusterDefaultAppValuesPath, req.ManagedClusterName)
logger.Infof("for the culster %s, removing the cluster folder from git repo through path %s", req.ManagedClusterName, dirToDelete)
if err := os.RemoveAll(dirToDelete); err != nil {
return string(agentmodel.WorkFlowStatusFailed), errors.WithMessage(err, "failed to remove cluster folder")
}

fmt.Printf("accesstoken => %s \n", accessToken)
fmt.Printf("cp.pluginConfig.TemplateGitRepo => %s \n", cp.pluginConfig.TemplateGitRepo)
fmt.Printf("req.RepoURL => %s \n", req.RepoURL)
fmt.Printf("clusterValuesFile => %s \n", clusterValuesFile)
fmt.Printf("req.ManagedClusterName => %s \n", req.ManagedClusterName)
fmt.Printf("dirToDelete => %s \n", dirToDelete)

err = cp.helper.AddToGit(ctx, model.CrossPlaneProjectDelete, req.RepoURL, accessToken)
if err != nil {
return string(agentmodel.WorkFlowStatusFailed), errors.WithMessage(err, "failed to add git repo")
}

logger.Infof("added cloned project %s changed to git", req.RepoURL)

return string(agentmodel.WorkFlowStatusCompleted), nil
}

func removeClusterValues(valuesFileName, clusterName string) error {
logger.Infof("for the culster %s, removing the cluster values from %s file", clusterName, valuesFileName)
data, err := os.ReadFile(valuesFileName)
if err != nil {
return err
}

jsonData, err := k8s.ConvertYamlToJson(data)
if err != nil {
return err
}

var clusterConfig ClusterConfigValues
err = json.Unmarshal(jsonData, &clusterConfig)
if err != nil {
return err
}

clusters := []Cluster{}
if clusterConfig.Clusters != nil {
clusters = *clusterConfig.Clusters
}

for _, cluster := range clusters {
if cluster.Name != clusterName {
clusters = append(clusters, cluster)
}
}

clusterConfig.Clusters = &clusters
jsonBytes, err := json.Marshal(clusterConfig)
if err != nil {
return err
}

yamlBytes, err := k8s.ConvertJsonToYaml(jsonBytes)
if err != nil {
return err
}

err = os.WriteFile(valuesFileName, yamlBytes, os.ModeAppend)
return err
}

func (cp *CrossPlaneApp) prepareTemplateVaules(clusterName string) map[string]string {
val := map[string]string{
"DomainName": cp.cfg.DomainName,
Expand Down
1 change: 1 addition & 0 deletions capten/model/crossplane_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const (
CrossPlaneResource = "crossplane"
CrossPlaneClusterUpdate = "crossplane-cluster-update"
CrossPlaneProjectSync = "crossplane-project-sync"
CrossPlaneProjectDelete = "crossplane-project-delete"
)

type CrossplaneProviderStatus string
Expand Down

0 comments on commit 77dbeca

Please sign in to comment.