Skip to content

Commit

Permalink
[CLI]:Add TCP connection check (#584)
Browse files Browse the repository at this point in the history
* Add websocket connection

* Rename websocket to TCP

* Refactor

* Refactor

* Up version

* Refactor

* Change store type

* Change tcp connection tester name

* Change tcp connection tester name

* Up version

* Fix
  • Loading branch information
PhilippPlotnikov authored Sep 29, 2022
1 parent 3c2e87f commit d803269
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION=v0.0.529
VERSION=v0.0.530

OUT_DIR=dist
YEAR?=$(shell date +"%Y")
Expand Down
8 changes: 7 additions & 1 deletion cmd/commands/runtime_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,13 @@ func preInstallationChecks(ctx context.Context, opts *RuntimeInstallOptions) err
}

if !opts.SkipClusterChecks {
err = kubeutil.EnsureClusterRequirements(ctx, opts.KubeFactory, opts.RuntimeName, cfConfig.GetCurrentContext().URL)
err = kubeutil.EnsureClusterRequirements(ctx, kubeutil.RuntimeInstallOptions{
KubeFactory: opts.KubeFactory,
Namespace: opts.RuntimeName,
ContextUrl: cfConfig.GetCurrentContext().URL,
AccessMode: opts.AccessMode,
TunnelRegisterHost: opts.TunnelRegisterHost,
})
}
handleCliStep(reporter.InstallStepRunPreCheckValidateClusterRequirements, "Ensuring cluster requirements", err, true, false)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions docs/releases/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ cf version

```bash
# download and extract the binary
curl -L --output - https://github.com/codefresh-io/cli-v2/releases/download/v0.0.529/cf-linux-amd64.tar.gz | tar zx
curl -L --output - https://github.com/codefresh-io/cli-v2/releases/download/v0.0.530/cf-linux-amd64.tar.gz | tar zx

# move the binary to your $PATH
mv ./cf-linux-amd64 /usr/local/bin/cf
Expand All @@ -36,7 +36,7 @@ cf version

```bash
# download and extract the binary
curl -L --output - https://github.com/codefresh-io/cli-v2/releases/download/v0.0.529/cf-darwin-amd64.tar.gz | tar zx
curl -L --output - https://github.com/codefresh-io/cli-v2/releases/download/v0.0.530/cf-darwin-amd64.tar.gz | tar zx

# move the binary to your $PATH
mv ./cf-darwin-amd64 /usr/local/bin/cf
Expand Down
2 changes: 1 addition & 1 deletion manifests/runtime.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ metadata:
namespace: "{{ namespace }}"
spec:
defVersion: 2.0.0
version: 0.0.529
version: 0.0.530
bootstrapSpecifier: github.com/codefresh-io/cli-v2/manifests/argo-cd
components:
- name: events
Expand Down
4 changes: 4 additions & 0 deletions pkg/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ type Store struct {
NetworkTesterName string
NetworkTesterGenerateName string
NetworkTesterImage string
TCPConnectionTesterGenerateName string
TCPConnectionTesterName string
MinKubeVersion string
MaxKubeVersion string
MasterIngressName string
Expand Down Expand Up @@ -236,6 +238,8 @@ func init() {
s.NetworkTesterName = "cf-network-tester"
s.NetworkTesterGenerateName = "cf-network-tester-"
s.NetworkTesterImage = "quay.io/codefresh/cf-venona-network-tester:latest"
s.TCPConnectionTesterGenerateName = "cf-tcp-connections-tester-"
s.TCPConnectionTesterName = "cf-tcp-connections-tester"
s.MinKubeVersion = "v1.18.0"
s.MaxKubeVersion = "v1.25.0"
s.MasterIngressName = "-master"
Expand Down
101 changes: 85 additions & 16 deletions pkg/util/kube/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/codefresh-io/cli-v2/pkg/store"

"github.com/argoproj-labs/argocd-autopilot/pkg/kube"
platmodel "github.com/codefresh-io/go-sdk/pkg/codefresh/model"
authv1 "k8s.io/api/authorization/v1"
batchv1 "k8s.io/api/batch/v1"
v1 "k8s.io/api/core/v1"
Expand All @@ -37,6 +38,14 @@ import (
)

type (
RuntimeInstallOptions struct {
KubeFactory kube.Factory
Namespace string
ContextUrl string
AccessMode platmodel.AccessMode
TunnelRegisterHost string
}

rbacValidation struct {
Namespace string
Resource string
Expand All @@ -53,16 +62,19 @@ type (
LaunchJobOptions struct {
Client kubernetes.Interface
Namespace string
JobName *string
Image *string
ContainerName string
GenerateName string
Image string
Env []v1.EnvVar
RestartPolicy v1.RestartPolicy
BackOffLimit int32
}
)

func EnsureClusterRequirements(ctx context.Context, kubeFactory kube.Factory, namespace string, contextUrl string) error {
func EnsureClusterRequirements(ctx context.Context, runtimeInstallOptions RuntimeInstallOptions) error {
requirementsValidationErrorMessage := "cluster does not meet minimum requirements"
namespace := runtimeInstallOptions.Namespace
kubeFactory := runtimeInstallOptions.KubeFactory
var specificErrorMessages []string

client, err := kubeFactory.KubernetesClientSet()
Expand Down Expand Up @@ -173,16 +185,67 @@ func EnsureClusterRequirements(ctx context.Context, kubeFactory kube.Factory, na
return fmt.Errorf("%s: %v", requirementsValidationErrorMessage, specificErrorMessages)
}

err = runNetworkTest(ctx, kubeFactory, contextUrl)
err = runNetworkTest(ctx, kubeFactory, runtimeInstallOptions.ContextUrl)
if err != nil {
return fmt.Errorf("cluster network tests failed: %w ", err)
}

log.G(ctx).Info("Network test finished successfully")

if runtimeInstallOptions.AccessMode == platmodel.AccessModeTunnel {
err = runTCPConnectionTest(ctx, &runtimeInstallOptions)
if err != nil {
return fmt.Errorf("cluster TCP connection tests failed: %w ", err)
}

log.G(ctx).Info("TCP connection test finished successfully")
}
return nil
}

func runTCPConnectionTest(ctx context.Context, runtimeInstallOptions *RuntimeInstallOptions) error {
const tcpConnectionTestsTimeout = 120 * time.Second
envVars := map[string]string{
"TUNNEL_REGISTER_HOST": runtimeInstallOptions.TunnelRegisterHost,
}
env := prepareEnvVars(envVars)

client, err := runtimeInstallOptions.KubeFactory.KubernetesClientSet()
if err != nil {
return fmt.Errorf("failed to create kubernetes client: %w", err)
}

job, err := launchJob(ctx, client, LaunchJobOptions{
Namespace: store.Get().DefaultNamespace,
ContainerName: store.Get().TCPConnectionTesterName,
GenerateName: store.Get().TCPConnectionTesterGenerateName,
Image: store.Get().NetworkTesterImage,
Env: env,
RestartPolicy: v1.RestartPolicyNever,
BackOffLimit: 0,
})
if err != nil {
return err
}

defer func() {
err := deleteJob(ctx, client, job)
if err != nil {
log.G(ctx).Errorf("fail to delete tester pod: %s", err.Error())
}
}()

log.G(ctx).Info("Running TCP connection test...")
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
timeoutChan := time.After(tcpConnectionTestsTimeout)
podLastState, err := handleJobPodStates(ctx, client, job, ticker, timeoutChan)
if err != nil {
return err
}
return checkPodLastState(ctx, client, podLastState)
}

func GetClusterSecret(ctx context.Context, kubeFactory kube.Factory, namespace string, name string) (*v1.Secret, error) {
client, err := kubeFactory.KubernetesClientSet()
if err != nil {
Expand Down Expand Up @@ -295,8 +358,9 @@ func runNetworkTest(ctx context.Context, kubeFactory kube.Factory, urls ...strin

job, err := launchJob(ctx, client, LaunchJobOptions{
Namespace: store.Get().DefaultNamespace,
JobName: &store.Get().NetworkTesterName,
Image: &store.Get().NetworkTesterImage,
ContainerName: store.Get().NetworkTesterName,
GenerateName: store.Get().NetworkTesterGenerateName,
Image: store.Get().NetworkTesterImage,
Env: env,
RestartPolicy: v1.RestartPolicyNever,
BackOffLimit: 0,
Expand All @@ -315,17 +379,24 @@ func runNetworkTest(ctx context.Context, kubeFactory kube.Factory, urls ...strin
log.G(ctx).Info("Running network test...")
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
var podLastState *v1.Pod
timeoutChan := time.After(networkTestsTimeout)
podLastState, err := handleJobPodStates(ctx, client, job, ticker, timeoutChan)
if err != nil {
return err
}
return checkPodLastState(ctx, client, podLastState)
}

func handleJobPodStates(ctx context.Context, client kubernetes.Interface, job *batchv1.Job, ticker *time.Ticker, timeoutChan <-chan time.Time) (*v1.Pod, error) {
var podLastState *v1.Pod
Loop:
for {
select {
case <-ticker.C:
log.G(ctx).Debug("Waiting for network tester to finish")
currentPod, err := getPodByJob(ctx, client, job)
if err != nil {
return err
return nil, err
}

if currentPod == nil {
Expand Down Expand Up @@ -353,11 +424,10 @@ Loop:
break Loop
}
case <-timeoutChan:
return fmt.Errorf("network test timeout reached!")
return nil, fmt.Errorf("network test timeout reached!")
}
}

return checkPodLastState(ctx, client, podLastState)
return podLastState, nil
}

func prepareEnvVars(vars map[string]string) []v1.EnvVar {
Expand All @@ -368,7 +438,6 @@ func prepareEnvVars(vars map[string]string) []v1.EnvVar {
Value: value,
})
}

return env
}

Expand Down Expand Up @@ -449,16 +518,16 @@ func testNode(n v1.Node, req validationRequest) []string {
func launchJob(ctx context.Context, client kubernetes.Interface, opts LaunchJobOptions) (*batchv1.Job, error) {
jobSpec := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: *opts.JobName,
Namespace: opts.Namespace,
GenerateName: opts.GenerateName,
Namespace: opts.Namespace,
},
Spec: batchv1.JobSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: *opts.JobName,
Image: *opts.Image,
Name: opts.ContainerName,
Image: opts.Image,
Env: opts.Env,
},
},
Expand Down

0 comments on commit d803269

Please sign in to comment.