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

feat: Option to delete the base cluster topology #16

Merged
merged 7 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}

laurentluce marked this conversation as resolved.
Show resolved Hide resolved
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 {
laurentluce marked this conversation as resolved.
Show resolved Hide resolved
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
Loading