Skip to content

Commit 0b90032

Browse files
committed
[tmpnet] Enable installation of chaos mesh to local kind cluster
1 parent e2231cd commit 0b90032

File tree

3 files changed

+148
-42
lines changed

3 files changed

+148
-42
lines changed

scripts/kind-with-registry.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ nodes:
4747
- role: control-plane
4848
extraPortMappings:
4949
# Exposing a nodeport for nginx ingress is the reason this script needed to be copied and customized
50-
# This port must match the value used to deploy the nginx controller by tests/fixture/tmpnet/start-kind-cluster.go
50+
# This port must match the ingressNodePort constant in tests/fixture/tmpnet/start_kind_cluster.go
5151
- containerPort: 30791
5252
hostPort: 30791
5353
protocol: TCP

tests/fixture/tmpnet/start_kind_cluster.go

Lines changed: 142 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ const (
4545
ingressChartRepo = "https://kubernetes.github.io/ingress-nginx"
4646
ingressChartName = "ingress-nginx/ingress-nginx"
4747
ingressControllerName = "ingress-nginx-controller"
48+
ingressNodePort = 30791
49+
50+
// Chaos Mesh constants
51+
chaosMeshNamespace = "chaos-mesh"
52+
chaosMeshReleaseName = "chaos-mesh"
53+
chaosMeshChartRepo = "https://charts.chaos-mesh.org"
54+
chaosMeshChartName = "chaos-mesh/chaos-mesh"
55+
chaosMeshChartVersion = "2.7.2"
56+
chaosMeshControllerName = "chaos-controller-manager"
57+
chaosMeshDashboardName = "chaos-dashboard"
58+
chaosMeshDashboardHost = "chaos-mesh.localhost"
4859
)
4960

5061
//go:embed yaml/tmpnet-rbac.yaml
@@ -57,6 +68,7 @@ func StartKindCluster(
5768
configPath string,
5869
startMetricsCollector bool,
5970
startLogsCollector bool,
71+
installChaosMesh bool,
6072
) error {
6173
configContext := KindKubeconfigContext
6274

@@ -116,6 +128,12 @@ func StartKindCluster(
116128
return fmt.Errorf("failed to create defaults ConfigMap: %w", err)
117129
}
118130

131+
if installChaosMesh {
132+
if err := deployChaosMesh(ctx, log, configPath, configContext); err != nil {
133+
return fmt.Errorf("failed to deploy chaos mesh: %w", err)
134+
}
135+
}
136+
119137
return nil
120138
}
121139

@@ -342,7 +360,7 @@ func deployIngressController(ctx context.Context, log logging.Logger, configPath
342360
"--wait",
343361
"--set", "controller.service.type=NodePort",
344362
// This port value must match the port configured in scripts/kind-with-registry.sh
345-
"--set", "controller.service.nodePorts.http=30791",
363+
"--set", fmt.Sprintf("controller.service.nodePorts.http=%d", ingressNodePort),
346364
"--set", "controller.admissionWebhooks.enabled=false",
347365
"--set", "controller.config.proxy-read-timeout=600",
348366
"--set", "controller.config.proxy-send-timeout=600",
@@ -355,7 +373,7 @@ func deployIngressController(ctx context.Context, log logging.Logger, configPath
355373
return fmt.Errorf("failed to install nginx-ingress: %w", err)
356374
}
357375

358-
return waitForIngressController(ctx, log, configPath, configContext)
376+
return waitForDeployment(ctx, log, configPath, configContext, ingressNamespace, ingressControllerName, "nginx ingress controller")
359377
}
360378

361379
// isIngressControllerRunning checks if the nginx ingress controller is already running.
@@ -371,42 +389,6 @@ func isIngressControllerRunning(ctx context.Context, log logging.Logger, configP
371389
return isRunning, nil
372390
}
373391

374-
// waitForIngressController waits for the nginx ingress controller to be ready.
375-
func waitForIngressController(ctx context.Context, log logging.Logger, configPath string, configContext string) error {
376-
clientset, err := GetClientset(log, configPath, configContext)
377-
if err != nil {
378-
return fmt.Errorf("failed to get clientset: %w", err)
379-
}
380-
381-
return wait.PollUntilContextCancel(ctx, statusCheckInterval, true /* immediate */, func(ctx context.Context) (bool, error) {
382-
deployment, err := clientset.AppsV1().Deployments(ingressNamespace).Get(ctx, ingressControllerName, metav1.GetOptions{})
383-
if err != nil {
384-
log.Debug("failed to get nginx ingress controller deployment",
385-
zap.String("namespace", ingressNamespace),
386-
zap.String("deployment", ingressControllerName),
387-
zap.Error(err),
388-
)
389-
return false, nil
390-
}
391-
if deployment.Status.ReadyReplicas == 0 {
392-
log.Debug("waiting for nginx ingress controller to become ready",
393-
zap.String("namespace", ingressNamespace),
394-
zap.String("deployment", ingressControllerName),
395-
zap.Int32("readyReplicas", deployment.Status.ReadyReplicas),
396-
zap.Int32("replicas", deployment.Status.Replicas),
397-
)
398-
return false, nil
399-
}
400-
401-
log.Info("nginx ingress controller is ready",
402-
zap.String("namespace", ingressNamespace),
403-
zap.String("deployment", ingressControllerName),
404-
zap.Int32("readyReplicas", deployment.Status.ReadyReplicas),
405-
)
406-
return true, nil
407-
})
408-
}
409-
410392
// runHelmCommand runs a Helm command with the given arguments.
411393
func runHelmCommand(ctx context.Context, args ...string) error {
412394
cmd := exec.CommandContext(ctx, "helm", args...)
@@ -448,7 +430,7 @@ func createDefaultsConfigMap(ctx context.Context, log logging.Logger, configPath
448430
Namespace: namespace,
449431
},
450432
Data: map[string]string{
451-
ingressHostKey: "localhost:30791",
433+
ingressHostKey: fmt.Sprintf("localhost:%d", ingressNodePort),
452434
},
453435
}
454436

@@ -459,3 +441,124 @@ func createDefaultsConfigMap(ctx context.Context, log logging.Logger, configPath
459441

460442
return nil
461443
}
444+
445+
// deployChaosMesh deploys Chaos Mesh using Helm.
446+
func deployChaosMesh(ctx context.Context, log logging.Logger, configPath string, configContext string) error {
447+
log.Info("checking if chaos mesh is already running")
448+
449+
isRunning, err := isChaosMeshRunning(ctx, log, configPath, configContext)
450+
if err != nil {
451+
return fmt.Errorf("failed to check chaos mesh status: %w", err)
452+
}
453+
if isRunning {
454+
log.Info("chaos mesh already running")
455+
return nil
456+
}
457+
458+
log.Info("deploying chaos mesh using Helm")
459+
460+
// Add the helm repo for chaos-mesh
461+
if err := runHelmCommand(ctx, "repo", "add", "chaos-mesh", chaosMeshChartRepo); err != nil {
462+
return fmt.Errorf("failed to add chaos mesh helm repo: %w", err)
463+
}
464+
if err := runHelmCommand(ctx, "repo", "update"); err != nil {
465+
return fmt.Errorf("failed to update helm repos: %w", err)
466+
}
467+
468+
// Install Chaos Mesh with all required settings including ingress
469+
args := []string{
470+
"install",
471+
chaosMeshReleaseName,
472+
chaosMeshChartName,
473+
"--namespace", chaosMeshNamespace,
474+
"--create-namespace",
475+
"--version", chaosMeshChartVersion,
476+
"--wait",
477+
"--set", "chaosDaemon.runtime=containerd",
478+
"--set", "chaosDaemon.socketPath=/run/containerd/containerd.sock",
479+
"--set", "dashboard.persistentVolume.enabled=true",
480+
"--set", "dashboard.persistentVolume.storageClass=standard",
481+
"--set", "dashboard.securityMode=false",
482+
"--set", "controllerManager.leaderElection.enabled=false",
483+
"--set", "dashboard.ingress.enabled=true",
484+
"--set", "dashboard.ingress.ingressClassName=nginx",
485+
"--set", "dashboard.ingress.hosts[0].name=" + chaosMeshDashboardHost,
486+
}
487+
488+
if err := runHelmCommand(ctx, args...); err != nil {
489+
return fmt.Errorf("failed to install chaos mesh: %w", err)
490+
}
491+
492+
// Wait for Chaos Mesh to be ready
493+
if err := waitForChaosMesh(ctx, log, configPath, configContext); err != nil {
494+
return fmt.Errorf("chaos mesh deployment failed: %w", err)
495+
}
496+
497+
// Log access information
498+
log.Info("Chaos Mesh installed successfully",
499+
zap.String("dashboardURL", fmt.Sprintf("http://%s:%d", chaosMeshDashboardHost, ingressNodePort)),
500+
)
501+
log.Warn("Chaos Mesh dashboard security is disabled - use only for local development")
502+
503+
return nil
504+
}
505+
506+
// isChaosMeshRunning checks if Chaos Mesh is already running.
507+
func isChaosMeshRunning(ctx context.Context, log logging.Logger, configPath string, configContext string) (bool, error) {
508+
clientset, err := GetClientset(log, configPath, configContext)
509+
if err != nil {
510+
return false, err
511+
}
512+
513+
// Check if controller manager deployment exists
514+
_, err = clientset.AppsV1().Deployments(chaosMeshNamespace).Get(ctx, chaosMeshControllerName, metav1.GetOptions{})
515+
return !apierrors.IsNotFound(err), nil
516+
}
517+
518+
// waitForChaosMesh waits for Chaos Mesh components to be ready.
519+
func waitForChaosMesh(ctx context.Context, log logging.Logger, configPath string, configContext string) error {
520+
// Wait for controller manager
521+
if err := waitForDeployment(ctx, log, configPath, configContext, chaosMeshNamespace, chaosMeshControllerName, "chaos mesh controller manager"); err != nil {
522+
return fmt.Errorf("controller manager not ready: %w", err)
523+
}
524+
525+
// Wait for dashboard
526+
return waitForDeployment(ctx, log, configPath, configContext, chaosMeshNamespace, chaosMeshDashboardName, "chaos mesh dashboard")
527+
}
528+
529+
// waitForDeployment waits for a deployment to have at least one ready replica.
530+
func waitForDeployment(ctx context.Context, log logging.Logger, configPath string, configContext string, namespace string, deploymentName string, displayName string) error {
531+
clientset, err := GetClientset(log, configPath, configContext)
532+
if err != nil {
533+
return fmt.Errorf("failed to get clientset: %w", err)
534+
}
535+
536+
log.Info("waiting for " + displayName + " to be ready")
537+
return wait.PollUntilContextCancel(ctx, statusCheckInterval, true /* immediate */, func(ctx context.Context) (bool, error) {
538+
deployment, err := clientset.AppsV1().Deployments(namespace).Get(ctx, deploymentName, metav1.GetOptions{})
539+
if err != nil {
540+
log.Debug("failed to get "+displayName+" deployment",
541+
zap.String("namespace", namespace),
542+
zap.String("deployment", deploymentName),
543+
zap.Error(err),
544+
)
545+
return false, nil
546+
}
547+
if deployment.Status.ReadyReplicas == 0 {
548+
log.Debug("waiting for "+displayName+" to become ready",
549+
zap.String("namespace", namespace),
550+
zap.String("deployment", deploymentName),
551+
zap.Int32("readyReplicas", deployment.Status.ReadyReplicas),
552+
zap.Int32("replicas", deployment.Status.Replicas),
553+
)
554+
return false, nil
555+
}
556+
557+
log.Info(displayName+" is ready",
558+
zap.String("namespace", namespace),
559+
zap.String("deployment", deploymentName),
560+
zap.Int32("readyReplicas", deployment.Status.ReadyReplicas),
561+
)
562+
return true, nil
563+
})
564+
}

tests/fixture/tmpnet/tmpnetctl/main.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,9 @@ func main() {
267267
rootCmd.AddCommand(checkLogsCmd)
268268

269269
var (
270-
kubeconfigVars *flags.KubeconfigVars
271-
collectorVars *flags.CollectorVars
270+
kubeconfigVars *flags.KubeconfigVars
271+
collectorVars *flags.CollectorVars
272+
installChaosMesh bool
272273
)
273274
startKindClusterCmd := &cobra.Command{
274275
Use: "start-kind-cluster",
@@ -298,11 +299,13 @@ func main() {
298299
kubeconfigVars.Path,
299300
collectorVars.StartMetricsCollector,
300301
collectorVars.StartLogsCollector,
302+
installChaosMesh,
301303
)
302304
},
303305
}
304306
kubeconfigVars = flags.NewKubeconfigFlagSetVars(startKindClusterCmd.PersistentFlags())
305307
collectorVars = flags.NewCollectorFlagSetVars(startKindClusterCmd.PersistentFlags())
308+
startKindClusterCmd.PersistentFlags().BoolVar(&installChaosMesh, "install-chaos-mesh", false, "Install Chaos Mesh in the kind cluster")
306309
rootCmd.AddCommand(startKindClusterCmd)
307310

308311
if err := rootCmd.Execute(); err != nil {

0 commit comments

Comments
 (0)