Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding the kardinal manager deploy and kardinal manager remove CLI commands #10

Merged
merged 4 commits into from
Jul 4, 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
2 changes: 2 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
container_pkgs.nettools
container_pkgs.gnugrep
container_pkgs.coreutils
container_pkgs.cacert
];
pathsToLink = ["/bin"];
};
Expand All @@ -166,6 +167,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"
leoporoli marked this conversation as resolved.
Show resolved Hide resolved

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
Loading