Skip to content

Commit

Permalink
feat: adding the kardinal manager deploy and `kardinal manager remo…
Browse files Browse the repository at this point in the history
…ve` CLI commands (#10)
  • Loading branch information
leoporoli authored Jul 4, 2024
1 parent 7c38358 commit af8843c
Show file tree
Hide file tree
Showing 9 changed files with 443 additions and 7 deletions.
2 changes: 2 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
container_pkgs.nettools
container_pkgs.gnugrep
container_pkgs.coreutils
container_pkgs.cacert
];
pathsToLink = ["/bin"];
};
Expand All @@ -170,6 +171,7 @@
if !needsCrossCompilation
then ["${service}/bin/${service.pname}"]
else ["${service}/bin/${os}_${arch}/${service.pname}"];
config.Env = ["SSL_CERT_FILE=${container_pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"];
};
};
}) {
Expand Down
99 changes: 95 additions & 4 deletions kardinal-cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"context"
"encoding/json"
"fmt"
"kardinal.cli/tenant"
"log"
"net/http"

"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
"github.com/kurtosis-tech/stacktrace"
"github.com/spf13/cobra"
"kardinal.cli/deployment"
"kardinal.cli/tenant"
"log"
"net/http"

api "github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api/api/golang/client"
api_types "github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api/api/golang/types"
Expand All @@ -21,6 +22,17 @@ const (
devMode = true
kontrolServiceApiUrl = "ad718d90d54d54dd084dea50a9f011af-1140086995.us-east-1.elb.amazonaws.com"
kontrolServicePort = 8080

kontrolLocationLocalMinikube = "local-minikube"
kontrolLocationKloudKontrol = "kloud-kontrol"

kontrolClusterResourcesEndpointTmpl = "%s://%s/tenant/%s/cluster-resources"

localMinikubeKontrolAPIHost = "host.minikube.internal:8080"
kloudKontrolAPIHost = "app.kardinal.dev/api"

httpSchme = "http"
httpsScheme = httpSchme + "s"
)

var composeFile string
Expand All @@ -35,6 +47,11 @@ var flowCmd = &cobra.Command{
Short: "Manage deployment flows",
}

var managerCmd = &cobra.Command{
Use: "manager",
Short: "Manage Kardinal manager",
}

var deployCmd = &cobra.Command{
Use: "deploy",
Short: "Deploy services",
Expand Down Expand Up @@ -94,10 +111,47 @@ var deleteCmd = &cobra.Command{
},
}

var deployManagerCmd = &cobra.Command{
Use: fmt.Sprintf("deploy [kontrol location] accepted values: %s and %s ", kontrolLocationLocalMinikube, kontrolLocationKloudKontrol),
Short: "Deploy Kardinal manager into the cluster",
ValidArgs: []string{kontrolLocationLocalMinikube, kontrolLocationKloudKontrol},
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
Run: func(cmd *cobra.Command, args []string) {

kontroLocation := args[0]

tenantUuid, err := tenant.GetOrCreateUserTenantUUID()
if err != nil {
log.Fatal("Error getting or creating user tenant UUID", err)
}

if err := deployManager(tenantUuid.String(), kontroLocation); err != nil {
log.Fatal("Error deploying Kardinal manager", err)
}

fmt.Printf("Kardinal manager deployed using '%s' Kontrol", kontroLocation)
},
}

var removeManagerCmd = &cobra.Command{
Use: "remove",
Short: "Remove Kardinal manager from the cluster",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
if err := removeManager(); err != nil {
log.Fatal("Error removing Kardinal manager", err)
}

fmt.Print("Kardinal manager removed from cluster")
},
}

func init() {
rootCmd.AddCommand(flowCmd)
rootCmd.AddCommand(managerCmd)
rootCmd.AddCommand(deployCmd)
flowCmd.AddCommand(createCmd, deleteCmd)
managerCmd.AddCommand(deployManagerCmd, removeManagerCmd)

flowCmd.PersistentFlags().StringVarP(&composeFile, "docker-compose", "d", "", "Path to the Docker Compose file")
flowCmd.MarkPersistentFlagRequired("docker-compose")
Expand Down Expand Up @@ -206,6 +260,43 @@ func deleteFlow(tenantUuid api_types.Uuid, services []types.ServiceConfig) {
fmt.Printf("Response: %s\n", string(resp.Body))
}

func deployManager(tenantUuid api_types.Uuid, kontrolLocation string) error {
var (
ctx = context.Background()
scheme string
host string
)

switch kontrolLocation {
case kontrolLocationLocalMinikube:
scheme = httpSchme
host = localMinikubeKontrolAPIHost
case kontrolLocationKloudKontrol:
scheme = httpsScheme
host = kloudKontrolAPIHost
default:
return stacktrace.NewError("invalid kontrol location: %s", kontrolLocation)
}

clusterResourcesURL := fmt.Sprintf(kontrolClusterResourcesEndpointTmpl, scheme, host, tenantUuid)

if err := deployment.DeployKardinalManagerInCluster(ctx, clusterResourcesURL); err != nil {
return stacktrace.Propagate(err, "An error occurred deploying Kardinal manager into the cluster with cluster resources URL '%s'", clusterResourcesURL)
}

return nil
}

func removeManager() error {
ctx := context.Background()

if err := deployment.RemoveKardinalManagerFromCluster(ctx); err != nil {
return stacktrace.Propagate(err, "An error occurred removing Kardinal manager from the cluster")
}

return nil
}

func getKontrolServiceClient() *api.ClientWithResponses {
if devMode {
client, err := api.NewClientWithResponses("http://localhost:8080", api.WithHTTPClient(http.DefaultClient))
Expand Down
6 changes: 6 additions & 0 deletions kardinal-cli/consts/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package consts

const (
KardinalAppIDLabelKey = "dev.kardinal.app-id"
KardinalManagerAppIDLabelValue = "kardinal-manager"
)
141 changes: 141 additions & 0 deletions kardinal-cli/deployment/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package deployment

import (
"bytes"
"context"
"github.com/kurtosis-tech/stacktrace"
"kardinal.cli/consts"
"text/template"
)

const (
kardinalNamespace = "default"
kardinalManagerDeploymentTmplName = "kardinal-manager-deployment"

kardinalManagerDeploymentTmpl = `
apiVersion: v1
kind: ServiceAccount
metadata:
name: kardinal-manager
namespace: {{.Namespace}}
labels:
{{.KardinalAppIDLabelKey}}: {{.KardinalManagerAppIDLabelValue}}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kardinal-manager-role
labels:
{{.KardinalAppIDLabelKey}}: {{.KardinalManagerAppIDLabelValue}}
rules:
- apiGroups: ["*"]
resources: ["namespaces", "pods", "services", "deployments", "virtualservices", "workloadgroups", "workloadentries", "sidecars", "serviceentries", "gateways", "envoyfilters", "destinationrules"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kardinal-manager-binding
labels:
{{.KardinalAppIDLabelKey}}: {{.KardinalManagerAppIDLabelValue}}
subjects:
- kind: ServiceAccount
name: kardinal-manager
namespace: default
roleRef:
kind: ClusterRole
name: kardinal-manager-role
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kardinal-manager
namespace: {{.Namespace}}
labels:
{{.KardinalAppIDLabelKey}}: {{.KardinalManagerAppIDLabelValue}}
spec:
replicas: 1
selector:
matchLabels:
{{.KardinalAppIDLabelKey}}: {{.KardinalManagerAppIDLabelValue}}
template:
metadata:
labels:
{{.KardinalAppIDLabelKey}}: {{.KardinalManagerAppIDLabelValue}}
spec:
serviceAccountName: kardinal-manager
containers:
- name: kardinal-manager
image: kurtosistech/kardinal-manager:latest
# TODO: Policy to local dev only - figure a way to remove it
imagePullPolicy: Never
env:
- name: KUBERNETES_SERVICE_HOST
value: "kubernetes.default.svc"
- name: KUBERNETES_SERVICE_PORT
value: "443"
- name: KARDINAL_MANAGER_CLUSTER_CONFIG_ENDPOINT
value: "{{.ClusterResourcesURL}}"
- name: KARDINAL_MANAGER_FETCHER_JOB_DURATION_SECONDS
value: "10"
`
)

type templateData struct {
Namespace string
ClusterResourcesURL string
KardinalAppIDLabelKey string
KardinalManagerAppIDLabelValue string
}

func DeployKardinalManagerInCluster(ctx context.Context, clusterResourcesURL string) error {
kubernetesClientObj, err := createKubernetesClient()
if err != nil {
return stacktrace.Propagate(err, "An error occurred while creating the Kubernetes client")
}

kardinalManagerDeploymentTemplate, err := template.New(kardinalManagerDeploymentTmplName).Parse(kardinalManagerDeploymentTmpl)
if err != nil {
return stacktrace.Propagate(err, "An error occurred while parsing the kardinal-manager deployment template")
}

templateDataObj := templateData{
Namespace: kardinalNamespace,
ClusterResourcesURL: clusterResourcesURL,
KardinalAppIDLabelKey: consts.KardinalAppIDLabelKey,
KardinalManagerAppIDLabelValue: consts.KardinalManagerAppIDLabelValue,
}

yamlFileContentsBuffer := &bytes.Buffer{}

if err = kardinalManagerDeploymentTemplate.Execute(yamlFileContentsBuffer, templateDataObj); err != nil {
return stacktrace.Propagate(err, "An error occurred while executing the template '%s' with data objects '%+v'", kardinalManagerDeploymentTmplName, templateDataObj)
}

if err = kubernetesClientObj.ApplyYamlFileContentInNamespace(ctx, kardinalNamespace, yamlFileContentsBuffer.Bytes()); err != nil {
return stacktrace.Propagate(err, "An error occurred while applying the kardinal-manager deployment")
}

return nil
}

func RemoveKardinalManagerFromCluster(ctx context.Context) error {
kubernetesClientObj, err := createKubernetesClient()
if err != nil {
return stacktrace.Propagate(err, "An error occurred while creating the Kubernetes client")
}

labels := map[string]string{
consts.KardinalAppIDLabelKey: consts.KardinalManagerAppIDLabelValue,
}

if err = kubernetesClientObj.RemoveNamespaceResourcesByLabels(ctx, kardinalNamespace, labels); err != nil {
return stacktrace.Propagate(err, "An error occurred while removing the kardinal-manager from the cluster using labels '%+v'", labels)
}

return nil
}
Loading

0 comments on commit af8843c

Please sign in to comment.