Skip to content
This repository has been archived by the owner on Oct 21, 2024. It is now read-only.

Commit

Permalink
feat: Option to delete the base cluster topology (#16)
Browse files Browse the repository at this point in the history
* Support for deleting the base cluster topology

* Cleanup

* Lint

* Cleanup

* Cleanup

* Add CI test

* Remove uneeded Sprintf
  • Loading branch information
laurentluce authored Sep 10, 2024
1 parent 3ee91d8 commit a49ab71
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 24 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/ci-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,11 @@ jobs:
- name: Delete template
run: |
KARDINAL_CLI_DEV_MODE=TRUE kardinal template delete extra-item-shared
- name: Delete base topology and dev flows
run: |
KARDINAL_CLI_DEV_MODE=TRUE kardinal flow delete prod
if KARDINAL_CLI_DEV_MODE=TRUE kardinal flow ls | grep prod; then echo "Topologies not deleted"; exit 1; fi
tenant_id=${{ steps.tenant.outputs.id }}
deployments=$(curl http://localhost:8080/tenant/${tenant_id}/cluster-resources | jq -r '.deployments[].metadata.name' | tr " " "\n" | sort -g | tr "\n" " " | xargs)
if [ "${deployments}" != "" ]; then echo "Deployments list not empty"; exit 1; fi
97 changes: 74 additions & 23 deletions kontrol-service/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"

api "github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api/api/golang/server"
apitypes "github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api/api/golang/types"
managerapi "github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api/api/golang/server"
Expand Down Expand Up @@ -80,10 +81,10 @@ func (sv *Server) PostTenantUuidDeploy(_ context.Context, request api.PostTenant
namespace := *request.Body.Namespace

if namespace == "" {
namespace = "prod"
namespace = prodFlowId
}

flowId := "prod"
flowId := prodFlowId
err, urls := applyProdOnlyFlow(sv, request.Uuid, serviceConfigs, ingressConfigs, namespace, flowId)
if err != nil {
errMsg := fmt.Sprintf("An error occurred deploying flow '%v'", prodFlowId)
Expand All @@ -102,13 +103,29 @@ func (sv *Server) DeleteTenantUuidFlowFlowId(_ context.Context, request api.Dele
logrus.Infof("deleting dev flow for tenant '%s'", request.Uuid)
sv.analyticsWrapper.TrackEvent(EVENT_FLOW_DELETE, request.Uuid)

_, allFlows, _, _, _, err := getTenantTopologies(sv, request.Uuid)
clusterTopology, allFlows, _, _, _, err := getTenantTopologies(sv, request.Uuid)
if err != nil {
resourceType := "tenant"
missing := api.NotFoundJSONResponse{ResourceType: resourceType, Id: request.Uuid}
return api.DeleteTenantUuidFlowFlowId404JSONResponse{NotFoundJSONResponse: missing}, nil
}

if request.FlowId == clusterTopology.Namespace {
// We received a request to delete the base topology so we do that + the flows
err = deleteTenantTopologies(sv, request.Uuid)
if err != nil {
errMsg := "An error occurred deleting the topologies"
errResp := api.ErrorJSONResponse{
Error: err.Error(),
Msg: &errMsg,
}
return api.DeleteTenantUuidFlowFlowId500JSONResponse{errResp}, nil
}

logrus.Infof("Successfully deleted topologies.")
return api.DeleteTenantUuidFlowFlowId2xxResponse{StatusCode: 200}, nil
}

if flowTopology, found := allFlows[request.FlowId]; found {
logrus.Infof("deleting flow %s", request.FlowId)
pluginRunner := plugins.NewPluginRunner(plugins.NewGitPluginProviderImpl(), request.Uuid, sv.db)
Expand Down Expand Up @@ -494,14 +511,6 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop
return nil, nil, nil, nil, nil, fmt.Errorf("Cannot find tenant %s", tenantUuidStr)
}

var clusterTopology resolved.ClusterTopology
//TODO fix it throws an error if tenant.BaseClusterTopology is nil, which is the case when there is no tenant saved in the dB yet
err = json.Unmarshal(tenant.BaseClusterTopology, &clusterTopology)
if err != nil {
logrus.Errorf("An error occurred decoding the cluster topology for tenant '%v'", tenant.TenantId)
return nil, nil, nil, nil, nil, err
}

flows := map[string]resolved.ClusterTopology{}
for _, flow := range tenant.Flows {
var clusterTopology resolved.ClusterTopology
Expand All @@ -525,28 +534,70 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop
}

var baseClusterTopology resolved.ClusterTopology
err = json.Unmarshal(tenant.BaseClusterTopology, &baseClusterTopology)
if err != nil {
logrus.Errorf("An error occurred decoding the cluster topology for tenant '%v'", tenantUuidStr)
return nil, nil, nil, nil, nil, err
if tenant.BaseClusterTopology != nil {
err = json.Unmarshal(tenant.BaseClusterTopology, &baseClusterTopology)
if err != nil {
logrus.Errorf("An error occurred decoding the cluster topology for tenant '%v'", tenantUuidStr)
return nil, nil, nil, nil, nil, err
}
} else {
baseClusterTopology.FlowID = prodFlowId
baseClusterTopology.Namespace = prodFlowId
}

var serviceConfigs []apitypes.ServiceConfig
err = json.Unmarshal(tenant.ServiceConfigs, &serviceConfigs)
if err != nil {
logrus.Errorf("An error occurred decoding the service configs for tenant '%v'", tenantUuidStr)
return nil, nil, nil, nil, nil, err
if tenant.ServiceConfigs != nil {
err = json.Unmarshal(tenant.ServiceConfigs, &serviceConfigs)
if err != nil {
logrus.Errorf("An error occurred decoding the service configs for tenant '%v'", tenantUuidStr)
return nil, nil, nil, nil, nil, err
}
}

var ingressConfigs []apitypes.IngressConfig
err = json.Unmarshal(tenant.IngressConfigs, &ingressConfigs)
if err != nil {
logrus.Errorf("An error occurred decoding the ingress configs for tenant '%v'", tenantUuidStr)
return nil, nil, nil, nil, nil, err
if tenant.IngressConfigs != nil {
err = json.Unmarshal(tenant.IngressConfigs, &ingressConfigs)
if err != nil {
logrus.Errorf("An error occurred decoding the ingress configs for tenant '%v'", tenantUuidStr)
return nil, nil, nil, nil, nil, err
}
}

return &baseClusterTopology, flows, tenantTemplates, serviceConfigs, ingressConfigs, nil
}

func deleteTenantTopologies(sv *Server, tenantUuidStr string) error {
tenant, err := sv.db.GetTenant(tenantUuidStr)
if err != nil {
logrus.Errorf("an error occured while getting the tenant %s\n: '%v'", tenantUuidStr, err.Error())
return err
}

tenant.BaseClusterTopology = nil
tenant.ServiceConfigs = nil
tenant.IngressConfigs = nil

err = sv.db.SaveTenant(tenant)
if err != nil {
logrus.Errorf("an error occured while saving tenant %s. erro was \n: '%v'", tenant.TenantId, err.Error())
return err
}

err = sv.db.DeleteTenantFlows(tenant.TenantId)
if err != nil {
logrus.Errorf("an error occured while deleting tenant flows %s. erro was \n: '%v'", tenant.TenantId, err.Error())
return err
}

err = sv.db.DeleteTenantPluginConfigs(tenant.TenantId)
if err != nil {
logrus.Errorf("an error occured while deleting tenant plugin configs %s. erro was \n: '%v'", tenant.TenantId, err.Error())
return err
}

return nil
}

func newClIAPITemplates(templates []templates.Template) []apitypes.Template {
var apiTypeTemplates []apitypes.Template
for _, template := range templates {
Expand Down
11 changes: 11 additions & 0 deletions kontrol-service/database/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,14 @@ func (db *Db) DeleteFlow(
logrus.Infof("Success! Deleted flow %s in database", flowId)
return nil
}

func (db *Db) DeleteTenantFlows(
tenantId string,
) error {
result := db.db.Where("tenant_id = ?", tenantId).Delete(&Flow{})
if result.Error != nil {
return stacktrace.Propagate(result.Error, "An internal error has occurred deleting the tenants %s flows", tenantId)
}
logrus.Infof("Success! Deleted tenant %s flows in database", tenantId)
return nil
}
11 changes: 11 additions & 0 deletions kontrol-service/database/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ func (db *Db) DeletePluginConfig(
return nil
}

func (db *Db) DeleteTenantPluginConfigs(
tenantId string,
) error {
result := db.db.Where("tenant_id = ?", tenantId).Delete(&PluginConfig{})
if result.Error != nil {
return stacktrace.Propagate(result.Error, "An internal error has occurred deleting the tenant %s plugin configs", tenantId)
}

return nil
}

func (db *Db) GetPluginConfigByFlowID(
tenantId string,
flowId string,
Expand Down
11 changes: 10 additions & 1 deletion kontrol-service/engine/flow/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,16 @@ func getGateway(ingresses []*resolved.Ingress, namespace string) *istioclient.Ga
}
extHosts = lo.Uniq(extHosts)

ingressId := ingresses[0].IngressID
// We need to return a gateway as part of the cluster resources so we return a dummy one
// if there are no ingresses defined. This can happen when the tenant does not have a base
// cluster topology: no initial deploy or the topologies have been deleted. This gateway also allows
// us to communicate the namespace to the kardinal manager helping the resources to be cleaned up.
ingressId := "dummy"
if len(ingresses) > 0 {
ingressId = ingresses[0].IngressID
} else {
extHosts = []string{"dummy.kardinal.dev"}
}

return &istioclient.Gateway{
TypeMeta: metav1.TypeMeta{
Expand Down

0 comments on commit a49ab71

Please sign in to comment.