mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-02-15 18:39:58 +00:00
Compare commits
168 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
139336d4ee | ||
|
|
f68fed0de8 | ||
|
|
1d7d242e6c | ||
|
|
aa904e23c7 | ||
|
|
baf0e65337 | ||
|
|
a33a3467fc | ||
|
|
a9b598bc41 | ||
|
|
0aee367ad5 | ||
|
|
8c7d9ea8fd | ||
|
|
fab0f713ed | ||
|
|
2563cc1922 | ||
|
|
26c9f42eba | ||
|
|
00dd3a93df | ||
|
|
d02293ab55 | ||
|
|
60cfa92efb | ||
|
|
01b187aaa3 | ||
|
|
38d121556c | ||
|
|
2d73b46b44 | ||
|
|
466b9099bd | ||
|
|
bbe3338c3c | ||
|
|
2780791068 | ||
|
|
e65656c1df | ||
|
|
df7d1ac10c | ||
|
|
c342885cae | ||
|
|
44adb397c1 | ||
|
|
657ea8570c | ||
|
|
686dd5fba1 | ||
|
|
90e6e99386 | ||
|
|
aa9109df12 | ||
|
|
9a37781355 | ||
|
|
5ce10b626f | ||
|
|
26d75da588 | ||
|
|
95edac9f8f | ||
|
|
f6c4d43eb1 | ||
|
|
47b9cd0c8d | ||
|
|
fb06545887 | ||
|
|
ea594ea70a | ||
|
|
3cc543827a | ||
|
|
18addbb980 | ||
|
|
d2b9bddf78 | ||
|
|
3ebf816a68 | ||
|
|
504ecc4f83 | ||
|
|
562dff0d6c | ||
|
|
02990912b7 | ||
|
|
0aedc023aa | ||
|
|
0801ea8c74 | ||
|
|
83be3558ed | ||
|
|
100b397cdf | ||
|
|
c2cad11e0a | ||
|
|
c42481deb8 | ||
|
|
39d1b77045 | ||
|
|
f19db77228 | ||
|
|
077fc6c126 | ||
|
|
aeeb9e6c9f | ||
|
|
384ed4e16b | ||
|
|
5dafc015bb | ||
|
|
d1b17d4534 | ||
|
|
b9333e4d67 | ||
|
|
c962864d0b | ||
|
|
07b080e97a | ||
|
|
e4684a10af | ||
|
|
8b5e55d53a | ||
|
|
ee968adec5 | ||
|
|
2e7fad77a9 | ||
|
|
7f6f710b3f | ||
|
|
261df8261f | ||
|
|
e14bc8064b | ||
|
|
6f3b2c6755 | ||
|
|
bdaa626f30 | ||
|
|
e1ada1768d | ||
|
|
b05dbed71e | ||
|
|
9b66600602 | ||
|
|
d826b95687 | ||
|
|
0dac046f57 | ||
|
|
abc506af1a | ||
|
|
08f42a7b96 | ||
|
|
b90edfe1fb | ||
|
|
c32a13094e | ||
|
|
3f01b2de60 | ||
|
|
bdf81380d8 | ||
|
|
889730e9e5 | ||
|
|
3b3927ce3a | ||
|
|
8e07226060 | ||
|
|
b7f0dd7f3c | ||
|
|
d9ec538aff | ||
|
|
362b17dec4 | ||
|
|
4216f07ec7 | ||
|
|
a4d35599df | ||
|
|
bcc1a36d71 | ||
|
|
b4a3a0451e | ||
|
|
1a2892d46e | ||
|
|
db8c9ec163 | ||
|
|
b11619fbfa | ||
|
|
49ce15f9da | ||
|
|
65c5df3211 | ||
|
|
de7f598001 | ||
|
|
28fa6e494f | ||
|
|
0c68c0f99f | ||
|
|
cedb7bc8bc | ||
|
|
ca35177b44 | ||
|
|
08b96c2663 | ||
|
|
606fddc776 | ||
|
|
9a95fa364c | ||
|
|
72a18871b1 | ||
|
|
0a00dfbaf5 | ||
|
|
b9a7cfb4fa | ||
|
|
f0b68cb44b | ||
|
|
dcd42798c7 | ||
|
|
384f62f94f | ||
|
|
7312addb65 | ||
|
|
41ba509428 | ||
|
|
85da7f71ac | ||
|
|
6ca727373c | ||
|
|
f4c6613e6e | ||
|
|
37f615c9bb | ||
|
|
ac9298d681 | ||
|
|
2a20dc173c | ||
|
|
a6dd98d241 | ||
|
|
5d15667a03 | ||
|
|
43e9e90f7d | ||
|
|
776f9ce9af | ||
|
|
e62ebea8d8 | ||
|
|
eee641082e | ||
|
|
a1096cf2b9 | ||
|
|
1c31f5df01 | ||
|
|
6e0f2aa10a | ||
|
|
22e8490b93 | ||
|
|
17e038e703 | ||
|
|
4cb4ba568b | ||
|
|
79cc2e70b6 | ||
|
|
fe2423e9d9 | ||
|
|
964d30bf80 | ||
|
|
4b2c678fa3 | ||
|
|
a9fdde4110 | ||
|
|
4eeab41e6d | ||
|
|
dce7de6cc9 | ||
|
|
c809117b2c | ||
|
|
2c6c71cf49 | ||
|
|
1533d1ec28 | ||
|
|
edf5c8cd6d | ||
|
|
6c69fb6bc4 | ||
|
|
4dd941f8d9 | ||
|
|
90294e32c1 | ||
|
|
5f4a856c5e | ||
|
|
4e3233ade8 | ||
|
|
846f253a03 | ||
|
|
f128ae3993 | ||
|
|
38da25ecc8 | ||
|
|
bf777f9fca | ||
|
|
3c4272c6d1 | ||
|
|
920535b643 | ||
|
|
b55dd5b072 | ||
|
|
f5cf15d657 | ||
|
|
fe623438c4 | ||
|
|
1c35a9f143 | ||
|
|
d6766a8ac5 | ||
|
|
eaa21f0789 | ||
|
|
ac6aee07f5 | ||
|
|
5b428c5636 | ||
|
|
894f97ca41 | ||
|
|
45f8c8a834 | ||
|
|
75ff80218b | ||
|
|
6255e1d4ef | ||
|
|
8ea606fb59 | ||
|
|
c9d41c53ca | ||
|
|
3995dae16d | ||
|
|
447fcf1b31 | ||
|
|
7e7fa772e1 |
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -10,6 +10,9 @@ assignees: ''
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Provide more information**
|
||||
Running on EKS, AKS, GKE, Minikube, Rancher, OpenShift? Number of Nodes? CNI?
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Run `kubeshark <command> ...`
|
||||
|
||||
35
.github/workflows/helm.yml
vendored
Normal file
35
.github/workflows/helm.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
name: Release Helm Charts
|
||||
|
||||
jobs:
|
||||
release:
|
||||
# depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions
|
||||
# see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "$GITHUB_ACTOR"
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v3
|
||||
|
||||
- name: Run chart-releaser
|
||||
uses: helm/chart-releaser-action@v1.5.0
|
||||
with:
|
||||
charts_dir: .
|
||||
charts_repo_url: https://kubeshark.github.io/kubeshark
|
||||
env:
|
||||
CR_TOKEN: "${{ secrets.HELM_TOKEN }}"
|
||||
10
.github/workflows/linter.yml
vendored
10
.github/workflows/linter.yml
vendored
@@ -16,16 +16,18 @@ jobs:
|
||||
name: Golint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- uses: actions/setup-go@v2
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.17'
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Go lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout=10m
|
||||
|
||||
42
.github/workflows/release.yml
vendored
42
.github/workflows/release.yml
vendored
@@ -14,21 +14,23 @@ jobs:
|
||||
name: Build and publish a new release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go 1.17
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17'
|
||||
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Version
|
||||
id: version
|
||||
shell: bash
|
||||
run: |
|
||||
echo "##[set-output name=tag;]$(echo ${GITHUB_REF#refs/*/})"
|
||||
echo "##[set-output name=build_timestamp;]$(echo $(date +%s))"
|
||||
echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
|
||||
{
|
||||
echo "tag=${GITHUB_REF#refs/*/}"
|
||||
echo "build_timestamp=$(date +%s)"
|
||||
echo "branch=${GITHUB_REF#refs/heads/}"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build
|
||||
run: make build-all VER='${{ steps.version.outputs.tag }}' BUILD_TIMESTAMP='${{ steps.version.outputs.build_timestamp }}'
|
||||
@@ -53,23 +55,35 @@ jobs:
|
||||
needs: [release]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Version
|
||||
id: version
|
||||
shell: bash
|
||||
run: |
|
||||
{
|
||||
echo "tag=${GITHUB_REF#refs/*/}"
|
||||
echo "build_timestamp=$(date +%s)"
|
||||
echo "branch=${GITHUB_REF#refs/heads/}"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Fetch all tags
|
||||
run: git fetch --force --tags
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.17
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: ${{ env.GITHUB_REF_NAME }}
|
||||
args: release --rm-dist
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.HOMEBREW_TOKEN }}
|
||||
VER: ${{ steps.version.outputs.tag }}
|
||||
BUILD_TIMESTAMP: ${{ steps.version.outputs.build_timestamp }}
|
||||
|
||||
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
@@ -15,17 +15,17 @@ jobs:
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Set up Go 1.17
|
||||
uses: actions/setup-go@v2
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.17'
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Test
|
||||
run: make test
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v2
|
||||
uses: codecov/codecov-action@v3
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -56,4 +56,11 @@ cypress.env.json
|
||||
# Object files
|
||||
*.o
|
||||
|
||||
# Binaries
|
||||
bin
|
||||
|
||||
# Scripts
|
||||
scripts/
|
||||
|
||||
# CWD config YAML
|
||||
kubeshark.yaml
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Contributing to Kubeshark
|
||||
|
||||
|
||||
17
Makefile
17
Makefile
@@ -15,15 +15,23 @@ help: ## Print this help message.
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
|
||||
build-debug: ## Build for debuging.
|
||||
export CGO_ENABLED=1
|
||||
export GCLFAGS='-gcflags="all=-N -l"'
|
||||
${MAKE} build-base
|
||||
|
||||
build: ## Build.
|
||||
export CGO_ENABLED=0
|
||||
export LDFLAGS_EXT='-extldflags=-static -s -w'
|
||||
${MAKE} build-base
|
||||
|
||||
build-race: ## Build with -race flag.
|
||||
export CGO_ENABLED=1
|
||||
export GCLFAGS='-race'
|
||||
export LDFLAGS_EXT='-extldflags=-static -s -w'
|
||||
${MAKE} build-base
|
||||
|
||||
build-base: ## Build binary (select the platform via GOOS / GOARCH env variables).
|
||||
CGO_ENABLED=0 go build ${GCLFAGS} -ldflags="${LDFLAGS_EXT} \
|
||||
go build ${GCLFAGS} -ldflags="${LDFLAGS_EXT} \
|
||||
-X 'github.com/kubeshark/kubeshark/misc.GitCommitHash=$(COMMIT_HASH)' \
|
||||
-X 'github.com/kubeshark/kubeshark/misc.Branch=$(GIT_BRANCH)' \
|
||||
-X 'github.com/kubeshark/kubeshark/misc.BuildTimestamp=$(BUILD_TIMESTAMP)' \
|
||||
@@ -33,6 +41,7 @@ build-base: ## Build binary (select the platform via GOOS / GOARCH env variables
|
||||
cd bin && shasum -a 256 kubeshark_${SUFFIX} > kubeshark_${SUFFIX}.sha256
|
||||
|
||||
build-all: ## Build for all supported platforms.
|
||||
export CGO_ENABLED=0
|
||||
echo "Compiling for every OS and Platform" && \
|
||||
mkdir -p bin && sed s/_VER_/$(VER)/g RELEASE.md.TEMPLATE > bin/README.md && \
|
||||
$(MAKE) build GOOS=linux GOARCH=amd64 && \
|
||||
@@ -53,3 +62,9 @@ test: ## Run cli tests.
|
||||
|
||||
lint: ## Lint the source code.
|
||||
golangci-lint run
|
||||
|
||||
kubectl-view-all-resources: ## This command outputs all Kubernetes resources using YAML format and pipes it to VS Code
|
||||
./kubectl.sh view-all-resources
|
||||
|
||||
kubectl-view-kubeshark-resources: ## This command outputs all Kubernetes resources in "kubeshark" namespace using YAML format and pipes it to VS Code
|
||||
./kubectl.sh view-kubeshark-resources
|
||||
|
||||
78
README.md
78
README.md
@@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/kubeshark/assets/master/svg/kubeshark-logo.svg" alt="Kubeshark: Traffic viewer for Kubernetes." height="128px"/>
|
||||
<img src="https://raw.githubusercontent.com/kubeshark/assets/master/svg/kubeshark-logo.svg" alt="Kubeshark: Traffic analyzer for Kubernetes." height="128px"/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -9,10 +9,10 @@
|
||||
<a href="https://github.com/kubeshark/kubeshark/releases/latest">
|
||||
<img alt="GitHub Latest Release" src="https://img.shields.io/github/v/release/kubeshark/kubeshark?logo=GitHub&style=flat-square">
|
||||
</a>
|
||||
<a href="https://hub.docker.com/r/kubeshark/kubeshark">
|
||||
<a href="https://hub.docker.com/r/kubeshark/worker">
|
||||
<img alt="Docker pulls" src="https://img.shields.io/docker/pulls/kubeshark/kubeshark?color=%23099cec&logo=Docker&style=flat-square">
|
||||
</a>
|
||||
<a href="https://hub.docker.com/r/kubeshark/kubeshark">
|
||||
<a href="https://hub.docker.com/r/kubeshark/worker">
|
||||
<img alt="Image size" src="https://img.shields.io/docker/image-size/kubeshark/kubeshark/latest?logo=Docker&style=flat-square">
|
||||
</a>
|
||||
<a href="https://discord.gg/WkvRGMUcx7">
|
||||
@@ -23,87 +23,59 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<p align="center">
|
||||
Mizu (by UP9) is now Kubeshark, read more about it <a href="https://www.kubeshark.co/mizu-is-now-kubeshark">here</a>.
|
||||
<b>
|
||||
<span>NEW: </span><a href="https://github.com/kubeshark/kubeshark/releases/tag/39.4">Version 39.4</a> is out, introducing
|
||||
<a href="https://docs.kubeshark.co/en/automation_scripting">Scripting</a>,
|
||||
<a href="https://docs.kubeshark.co/en/automation_hooks">L4/L7 hooks</a>, and so much more...
|
||||
</b>
|
||||
</p>
|
||||
|
||||
Kubeshark, the API Traffic Viewer for kubernetes, provides deep visibility and monitoring of all API traffic and payloads going in, out and across containers and pods inside a Kubernetes cluster.
|
||||
|
||||
Think of a combination of Chrome Dev Tools, TCPDump and Wireshark, re-invented for Kubernetes.
|
||||
**Kubeshark** is an API Traffic Analyzer for [**Kubernetes**](https://kubernetes.io/) providing real-time, protocol-level visibility into Kubernetes’ internal network, capturing and monitoring all traffic and payloads going in, out and across containers, pods, nodes and clusters.
|
||||
|
||||

|
||||
|
||||
## Download
|
||||
Think [TCPDump](https://en.wikipedia.org/wiki/Tcpdump) and [Wireshark](https://www.wireshark.org/) re-invented for Kubernetes
|
||||
|
||||
Kubeshark uses a ~45MB pre-compiled executable binary to communicate with the Kubernetes API. We recommend downloading the `kubeshark` CLI by using one of these options:
|
||||
## Getting Started
|
||||
|
||||
- Choose the right binary, download and use directly from [the latest stable release](https://github.com/kubeshark/kubeshark/releases/latest).
|
||||
|
||||
- Use the shell script below :point_down: to automatically download the right binary for your operating system and CPU architecture:
|
||||
|
||||
```shell
|
||||
sh <(curl -Ls https://kubeshark.co/install)
|
||||
```
|
||||
|
||||
- Compile it from source using `make` command then use `./bin/kubeshark__` executable.
|
||||
|
||||
## Run
|
||||
|
||||
Use the `kubeshark` CLI to capture and view streaming API traffic in real time.
|
||||
Download **Kubeshark**'s binary distribution [latest release](https://github.com/kubeshark/kubeshark/releases/latest) and run following one of these examples:
|
||||
|
||||
```shell
|
||||
kubeshark tap
|
||||
```
|
||||
|
||||
### Troubleshooting Installation
|
||||
If something doesn't work or simply to play it safe prior to installing;
|
||||
```shell
|
||||
kubeshark tap -n sock-shop "(catalo*|front-end*)"
|
||||
```
|
||||
|
||||
> Make sure you have access to https://hub.docker.com/
|
||||
Running any of the :point_up: above commands will open the [Web UI](https://docs.kubeshark.co/en/ui) in your browser which streams the traffic in your Kubernetes cluster in real-time.
|
||||
|
||||
> Make sure `kubeshark` executable in your `PATH`.
|
||||
### Homebrew
|
||||
|
||||
### Select Pods
|
||||
|
||||
#### Monitoring a Specific Pod:
|
||||
[Homebrew](https://brew.sh/) :beer: users can add Kubeshark formulae with:
|
||||
|
||||
```shell
|
||||
kubeshark tap catalogue-b87b45784-sxc8q
|
||||
brew tap kubeshark/kubeshark
|
||||
```
|
||||
|
||||
#### Monitoring a Set of Pods Using Regex:
|
||||
and install Kubeshark CLI with:
|
||||
|
||||
```shell
|
||||
kubeshark tap "(catalo*|front-end*)"
|
||||
brew install kubeshark
|
||||
```
|
||||
|
||||
### Specify the Namespace
|
||||
## Building From Source
|
||||
|
||||
By default, Kubeshark targets the `default` namespace.
|
||||
To specify a different namespace:
|
||||
|
||||
```
|
||||
kubeshark tap -n sock-shop
|
||||
```
|
||||
|
||||
### Specify All Namespaces
|
||||
|
||||
The default strategy of Kubeshark waits for the new pods
|
||||
to be created. To simply tap all existing namespaces run:
|
||||
|
||||
```
|
||||
kubeshark tap -A
|
||||
```
|
||||
Clone this repository and run `make` command to build it. After the build is complete, the executable can be found at `./bin/kubeshark__`.
|
||||
|
||||
## Documentation
|
||||
|
||||
Visit our documentation website: [docs.kubeshark.co](https://docs.kubeshark.co)
|
||||
|
||||
The documentation resources are open-source and can be found on GitHub: [kubeshark/docs](https://github.com/kubeshark/docs)
|
||||
To learn more, read the [documentation](https://docs.kubeshark.co).
|
||||
|
||||
## Contributing
|
||||
|
||||
We ❤️ pull requests! See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution guide.
|
||||
We :heart: pull requests! See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution guide.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
package check
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/kubeshark/kubeshark/docker"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
core "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func ImagePullInCluster(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||
log.Info().Str("procedure", "image-pull-in-cluster").Msg("Checking:")
|
||||
|
||||
namespace := "default"
|
||||
podName := fmt.Sprintf("%s-test", misc.Program)
|
||||
|
||||
defer func() {
|
||||
if err := kubernetesProvider.RemovePod(ctx, namespace, podName); err != nil {
|
||||
log.Error().
|
||||
Str("namespace", namespace).
|
||||
Str("pod", podName).
|
||||
Err(err).
|
||||
Msg("While removing test pod!")
|
||||
}
|
||||
}()
|
||||
|
||||
if err := createImagePullInClusterPod(ctx, kubernetesProvider, namespace, podName); err != nil {
|
||||
log.Error().
|
||||
Str("namespace", namespace).
|
||||
Str("pod", podName).
|
||||
Err(err).
|
||||
Msg("While creating test pod!")
|
||||
return false
|
||||
}
|
||||
|
||||
if err := checkImagePulled(ctx, kubernetesProvider, namespace, podName); err != nil {
|
||||
log.Printf("%v cluster is not able to pull %s containers from docker hub, err: %v", misc.Program, fmt.Sprintf(utils.Red, "✗"), err)
|
||||
log.Error().
|
||||
Str("namespace", namespace).
|
||||
Str("pod", podName).
|
||||
Err(err).
|
||||
Msg("Unable to pull images from Docker Hub!")
|
||||
return false
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Str("namespace", namespace).
|
||||
Str("pod", podName).
|
||||
Msg("Pulling images from Docker Hub is passed.")
|
||||
return true
|
||||
}
|
||||
|
||||
func checkImagePulled(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespace string, podName string) error {
|
||||
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", podName))
|
||||
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{namespace}, podWatchHelper)
|
||||
|
||||
timeAfter := time.After(30 * time.Second)
|
||||
|
||||
for {
|
||||
select {
|
||||
case wEvent, ok := <-eventChan:
|
||||
if !ok {
|
||||
eventChan = nil
|
||||
continue
|
||||
}
|
||||
|
||||
pod, err := wEvent.ToPod()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if pod.Status.Phase == core.PodRunning {
|
||||
return nil
|
||||
}
|
||||
case err, ok := <-errorChan:
|
||||
if !ok {
|
||||
errorChan = nil
|
||||
continue
|
||||
}
|
||||
|
||||
return err
|
||||
case <-timeAfter:
|
||||
return fmt.Errorf("image not pulled in time")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createImagePullInClusterPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespace string, podName string) error {
|
||||
image := docker.GetWorkerImage()
|
||||
log.Info().Str("image", image).Msg("Testing image pull:")
|
||||
var zero int64
|
||||
pod := &core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: core.PodSpec{
|
||||
Containers: []core.Container{
|
||||
{
|
||||
Name: "probe",
|
||||
Image: image,
|
||||
ImagePullPolicy: "Always",
|
||||
Command: []string{"cat"},
|
||||
Stdin: true,
|
||||
},
|
||||
},
|
||||
TerminationGracePeriodSeconds: &zero,
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := kubernetesProvider.CreatePod(ctx, namespace, pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -2,48 +2,16 @@ package check
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
"github.com/rs/zerolog/log"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
func KubernetesPermissions(ctx context.Context, embedFS embed.FS, kubernetesProvider *kubernetes.Provider) bool {
|
||||
func KubernetesPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||
log.Info().Str("procedure", "kubernetes-permissions").Msg("Checking:")
|
||||
|
||||
var filePath string
|
||||
if config.Config.IsNsRestrictedMode() {
|
||||
filePath = "permissionFiles/permissions-ns-tap.yaml"
|
||||
} else {
|
||||
filePath = "permissionFiles/permissions-all-namespaces-tap.yaml"
|
||||
}
|
||||
|
||||
data, err := embedFS.ReadFile(filePath)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("While checking Kubernetes permissions!")
|
||||
return false
|
||||
}
|
||||
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, _, err := decode(data, nil, nil)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("While checking Kubernetes permissions!")
|
||||
return false
|
||||
}
|
||||
|
||||
switch resource := obj.(type) {
|
||||
case *rbac.Role:
|
||||
return checkRulesPermissions(ctx, kubernetesProvider, resource.Rules, config.Config.SelfNamespace)
|
||||
case *rbac.ClusterRole:
|
||||
return checkRulesPermissions(ctx, kubernetesProvider, resource.Rules, "")
|
||||
}
|
||||
|
||||
log.Error().Msg("While checking Kubernetes permissions! Resource of types 'Role' or 'ClusterRole' are not found in permission files.")
|
||||
return false
|
||||
return checkRulesPermissions(ctx, kubernetesProvider, kubernetesProvider.BuildClusterRole().Rules, "")
|
||||
}
|
||||
|
||||
func checkRulesPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider, rules []rbac.PolicyRule, namespace string) bool {
|
||||
|
||||
@@ -12,20 +12,17 @@ import (
|
||||
func KubernetesResources(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||
log.Info().Str("procedure", "k8s-components").Msg("Checking:")
|
||||
|
||||
exist, err := kubernetesProvider.DoesNamespaceExist(ctx, config.Config.SelfNamespace)
|
||||
allResourcesExist := checkResourceExist(config.Config.SelfNamespace, "namespace", exist, err)
|
||||
exist, err := kubernetesProvider.DoesNamespaceExist(ctx, config.Config.Tap.SelfNamespace)
|
||||
allResourcesExist := checkResourceExist(config.Config.Tap.SelfNamespace, "namespace", exist, err)
|
||||
|
||||
exist, err = kubernetesProvider.DoesConfigMapExist(ctx, config.Config.SelfNamespace, kubernetes.ConfigMapName)
|
||||
allResourcesExist = checkResourceExist(kubernetes.ConfigMapName, "config map", exist, err) && allResourcesExist
|
||||
|
||||
exist, err = kubernetesProvider.DoesServiceAccountExist(ctx, config.Config.SelfNamespace, kubernetes.ServiceAccountName)
|
||||
exist, err = kubernetesProvider.DoesServiceAccountExist(ctx, config.Config.Tap.SelfNamespace, kubernetes.ServiceAccountName)
|
||||
allResourcesExist = checkResourceExist(kubernetes.ServiceAccountName, "service account", exist, err) && allResourcesExist
|
||||
|
||||
if config.Config.IsNsRestrictedMode() {
|
||||
exist, err = kubernetesProvider.DoesRoleExist(ctx, config.Config.SelfNamespace, kubernetes.RoleName)
|
||||
exist, err = kubernetesProvider.DoesRoleExist(ctx, config.Config.Tap.SelfNamespace, kubernetes.RoleName)
|
||||
allResourcesExist = checkResourceExist(kubernetes.RoleName, "role", exist, err) && allResourcesExist
|
||||
|
||||
exist, err = kubernetesProvider.DoesRoleBindingExist(ctx, config.Config.SelfNamespace, kubernetes.RoleBindingName)
|
||||
exist, err = kubernetesProvider.DoesRoleBindingExist(ctx, config.Config.Tap.SelfNamespace, kubernetes.RoleBindingName)
|
||||
allResourcesExist = checkResourceExist(kubernetes.RoleBindingName, "role binding", exist, err) && allResourcesExist
|
||||
} else {
|
||||
exist, err = kubernetesProvider.DoesClusterRoleExist(ctx, kubernetes.ClusterRoleName)
|
||||
@@ -35,7 +32,7 @@ func KubernetesResources(ctx context.Context, kubernetesProvider *kubernetes.Pro
|
||||
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleBindingName, "cluster role binding", exist, err) && allResourcesExist
|
||||
}
|
||||
|
||||
exist, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.SelfNamespace, kubernetes.HubServiceName)
|
||||
exist, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.Tap.SelfNamespace, kubernetes.HubServiceName)
|
||||
allResourcesExist = checkResourceExist(kubernetes.HubServiceName, "service", exist, err) && allResourcesExist
|
||||
|
||||
allResourcesExist = checkPodResourcesExist(ctx, kubernetesProvider) && allResourcesExist
|
||||
@@ -44,7 +41,7 @@ func KubernetesResources(ctx context.Context, kubernetesProvider *kubernetes.Pro
|
||||
}
|
||||
|
||||
func checkPodResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.SelfNamespace, kubernetes.HubPodName); err != nil {
|
||||
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.Tap.SelfNamespace, kubernetes.HubPodName); err != nil {
|
||||
log.Error().
|
||||
Str("name", kubernetes.HubPodName).
|
||||
Err(err).
|
||||
@@ -66,7 +63,7 @@ func checkPodResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.
|
||||
Str("name", kubernetes.HubPodName).
|
||||
Msg("Pod is running.")
|
||||
|
||||
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.SelfNamespace, kubernetes.WorkerPodName); err != nil {
|
||||
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.Tap.SelfNamespace, kubernetes.WorkerPodName); err != nil {
|
||||
log.Error().
|
||||
Str("name", kubernetes.WorkerPodName).
|
||||
Err(err).
|
||||
|
||||
@@ -12,14 +12,14 @@ func ServerConnection(kubernetesProvider *kubernetes.Provider) bool {
|
||||
|
||||
var connectedToHub, connectedToFront bool
|
||||
|
||||
if err := checkProxy(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.SrcPort), "/echo", kubernetesProvider); err != nil {
|
||||
if err := checkProxy(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port), "/echo", kubernetesProvider); err != nil {
|
||||
log.Error().Err(err).Msg("Couldn't connect to Hub using proxy!")
|
||||
} else {
|
||||
connectedToHub = true
|
||||
log.Info().Msg("Connected successfully to Hub using proxy.")
|
||||
}
|
||||
|
||||
if err := checkProxy(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Front.SrcPort), "", kubernetesProvider); err != nil {
|
||||
if err := checkProxy(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Front.Port), "", kubernetesProvider); err != nil {
|
||||
log.Error().Err(err).Msg("Couldn't connect to Front using proxy!")
|
||||
} else {
|
||||
connectedToFront = true
|
||||
|
||||
@@ -2,7 +2,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@@ -12,11 +11,6 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed permissionFiles
|
||||
embedFS embed.FS
|
||||
)
|
||||
|
||||
func runCheck() {
|
||||
log.Info().Msg(fmt.Sprintf("Checking the %s resources...", misc.Software))
|
||||
|
||||
@@ -30,12 +24,9 @@ func runCheck() {
|
||||
}
|
||||
|
||||
if checkPassed {
|
||||
checkPassed = check.KubernetesPermissions(ctx, embedFS, kubernetesProvider)
|
||||
checkPassed = check.KubernetesPermissions(ctx, kubernetesProvider)
|
||||
}
|
||||
|
||||
if checkPassed {
|
||||
checkPassed = check.ImagePullInCluster(ctx, kubernetesProvider)
|
||||
}
|
||||
if checkPassed {
|
||||
checkPassed = check.KubernetesResources(ctx, kubernetesProvider)
|
||||
}
|
||||
|
||||
10
cmd/clean.go
10
cmd/clean.go
@@ -3,7 +3,10 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -18,4 +21,11 @@ var cleanCmd = &cobra.Command{
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(cleanCmd)
|
||||
|
||||
defaultTapConfig := configStructs.TapConfig{}
|
||||
if err := defaults.Set(&defaultTapConfig); err != nil {
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
|
||||
cleanCmd.Flags().StringP(configStructs.SelfNamespaceLabel, "s", defaultTapConfig.SelfNamespace, "Self-namespace of Kubeshark")
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
)
|
||||
|
||||
func performCleanCommand() {
|
||||
kubernetesProvider, err := getKubernetesProviderForCli()
|
||||
kubernetesProvider, err := getKubernetesProviderForCli(false, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
finishSelfExecution(kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.SelfNamespace)
|
||||
finishSelfExecution(kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.Tap.SelfNamespace, false)
|
||||
}
|
||||
|
||||
@@ -18,32 +18,32 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func startProxyReportErrorIfAny(kubernetesProvider *kubernetes.Provider, ctx context.Context, cancel context.CancelFunc, serviceName string, proxyPortLabel string, srcPort uint16, dstPort uint16, healthCheck string) {
|
||||
httpServer, err := kubernetes.StartProxy(kubernetesProvider, config.Config.Tap.Proxy.Host, srcPort, config.Config.SelfNamespace, serviceName, cancel)
|
||||
func startProxyReportErrorIfAny(kubernetesProvider *kubernetes.Provider, ctx context.Context, serviceName string, podName string, proxyPortLabel string, srcPort uint16, dstPort uint16, healthCheck string) {
|
||||
httpServer, err := kubernetes.StartProxy(kubernetesProvider, config.Config.Tap.Proxy.Host, srcPort, config.Config.Tap.SelfNamespace, serviceName)
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(errormessage.FormatError(err)).
|
||||
Msg(fmt.Sprintf("Error occured while running k8s proxy. Try setting different port by using --%s", proxyPortLabel))
|
||||
cancel()
|
||||
Msg(fmt.Sprintf("Error occured while running K8s proxy. Try setting different port using --%s", proxyPortLabel))
|
||||
return
|
||||
}
|
||||
|
||||
connector := connect.NewConnector(kubernetes.GetLocalhostOnPort(srcPort), connect.DefaultRetries, connect.DefaultTimeout)
|
||||
if err := connector.TestConnection(healthCheck); err != nil {
|
||||
log.Error().Msg("Couldn't connect using proxy, stopping proxy and trying to create port-forward..")
|
||||
log.Warn().
|
||||
Str("service", serviceName).
|
||||
Msg("Couldn't connect using proxy, stopping proxy and trying to create port-forward...")
|
||||
if err := httpServer.Shutdown(ctx); err != nil {
|
||||
log.Error().
|
||||
Err(errormessage.FormatError(err)).
|
||||
Msg("Error occurred while stopping proxy.")
|
||||
}
|
||||
|
||||
podRegex, _ := regexp.Compile(kubernetes.HubPodName)
|
||||
if _, err := kubernetes.NewPortForward(kubernetesProvider, config.Config.SelfNamespace, podRegex, srcPort, dstPort, ctx, cancel); err != nil {
|
||||
podRegex, _ := regexp.Compile(podName)
|
||||
if _, err := kubernetes.NewPortForward(kubernetesProvider, config.Config.Tap.SelfNamespace, podRegex, srcPort, dstPort, ctx); err != nil {
|
||||
log.Error().
|
||||
Str("pod-regex", podRegex.String()).
|
||||
Err(errormessage.FormatError(err)).
|
||||
Msg(fmt.Sprintf("Error occured while running port forward. Try setting different port by using --%s", proxyPortLabel))
|
||||
cancel()
|
||||
Msg(fmt.Sprintf("Error occured while running port forward. Try setting different port using --%s", proxyPortLabel))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -53,13 +53,12 @@ func startProxyReportErrorIfAny(kubernetesProvider *kubernetes.Provider, ctx con
|
||||
Str("service", serviceName).
|
||||
Err(errormessage.FormatError(err)).
|
||||
Msg("Couldn't connect to service.")
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getKubernetesProviderForCli() (*kubernetes.Provider, error) {
|
||||
func getKubernetesProviderForCli(silent bool, dontCheckVersion bool) (*kubernetes.Provider, error) {
|
||||
kubeConfigPath := config.Config.KubeConfigPath()
|
||||
kubernetesProvider, err := kubernetes.NewProvider(kubeConfigPath, config.Config.Kube.Context)
|
||||
if err != nil {
|
||||
@@ -67,22 +66,26 @@ func getKubernetesProviderForCli() (*kubernetes.Provider, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Info().Str("path", kubeConfigPath).Msg("Using kubeconfig:")
|
||||
if !silent {
|
||||
log.Info().Str("path", kubeConfigPath).Msg("Using kubeconfig:")
|
||||
}
|
||||
|
||||
if err := kubernetesProvider.ValidateNotProxy(); err != nil {
|
||||
handleKubernetesProviderError(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kubernetesVersion, err := kubernetesProvider.GetKubernetesVersion()
|
||||
if err != nil {
|
||||
handleKubernetesProviderError(err)
|
||||
return nil, err
|
||||
}
|
||||
if !dontCheckVersion {
|
||||
kubernetesVersion, err := kubernetesProvider.GetKubernetesVersion()
|
||||
if err != nil {
|
||||
handleKubernetesProviderError(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := kubernetes.ValidateKubernetesVersion(kubernetesVersion); err != nil {
|
||||
handleKubernetesProviderError(err)
|
||||
return nil, err
|
||||
if err := kubernetes.ValidateKubernetesVersion(kubernetesVersion); err != nil {
|
||||
handleKubernetesProviderError(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return kubernetesProvider, nil
|
||||
@@ -97,11 +100,13 @@ func handleKubernetesProviderError(err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func finishSelfExecution(kubernetesProvider *kubernetes.Provider, isNsRestrictedMode bool, selfNamespace string) {
|
||||
func finishSelfExecution(kubernetesProvider *kubernetes.Provider, isNsRestrictedMode bool, selfNamespace string, withoutCleanup bool) {
|
||||
removalCtx, cancel := context.WithTimeout(context.Background(), cleanupTimeout)
|
||||
defer cancel()
|
||||
dumpLogsIfNeeded(removalCtx, kubernetesProvider)
|
||||
resources.CleanUpSelfResources(removalCtx, cancel, kubernetesProvider, isNsRestrictedMode, selfNamespace)
|
||||
if !withoutCleanup {
|
||||
resources.CleanUpSelfResources(removalCtx, cancel, kubernetesProvider, isNsRestrictedMode, selfNamespace)
|
||||
}
|
||||
}
|
||||
|
||||
func dumpLogsIfNeeded(ctx context.Context, kubernetesProvider *kubernetes.Provider) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
@@ -28,7 +29,7 @@ var configCmd = &cobra.Command{
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Info().Str("config-path", config.Config.ConfigFilePath).Msg("Template file written to config path.")
|
||||
log.Info().Str("config-path", config.ConfigFilePath).Msg("Template file written to config path.")
|
||||
} else {
|
||||
template, err := utils.PrettyYaml(configWithDefaults)
|
||||
if err != nil {
|
||||
@@ -36,7 +37,7 @@ var configCmd = &cobra.Command{
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug().Str("template", template).Msg("Writing template config...")
|
||||
log.Debug().Str("template", template).Msg("Printing template config...")
|
||||
fmt.Printf("%v", template)
|
||||
}
|
||||
|
||||
@@ -52,5 +53,5 @@ func init() {
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
|
||||
configCmd.Flags().BoolP(configStructs.RegenerateConfigName, "r", defaultConfig.Config.Regenerate, fmt.Sprintf("Regenerate the config file with default values to path %s or to chosen path using --%s", defaultConfig.ConfigFilePath, config.ConfigFilePathCommandName))
|
||||
configCmd.Flags().BoolP(configStructs.RegenerateConfigName, "r", defaultConfig.Config.Regenerate, fmt.Sprintf("Regenerate the config file with default values to path %s", path.Join(misc.GetDotFolderPath(), "config.yaml")))
|
||||
}
|
||||
|
||||
112
cmd/console.go
Normal file
112
cmd/console.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var consoleCmd = &cobra.Command{
|
||||
Use: "console",
|
||||
Short: "Stream the scripting console logs into shell",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
runConsole()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(consoleCmd)
|
||||
|
||||
defaultTapConfig := configStructs.TapConfig{}
|
||||
if err := defaults.Set(&defaultTapConfig); err != nil {
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
|
||||
consoleCmd.Flags().Uint16(configStructs.ProxyHubPortLabel, defaultTapConfig.Proxy.Hub.Port, "Provide a custom port for the Hub")
|
||||
consoleCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the Hub")
|
||||
}
|
||||
|
||||
func runConsole() {
|
||||
hubUrl := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port)
|
||||
response, err := http.Get(fmt.Sprintf("%s/echo", hubUrl))
|
||||
if err != nil || response.StatusCode != 200 {
|
||||
log.Info().Msg(fmt.Sprintf(utils.Yellow, "Couldn't connect to Hub. Establishing proxy..."))
|
||||
runProxy(false, true)
|
||||
}
|
||||
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
signal.Notify(interrupt, os.Interrupt)
|
||||
|
||||
log.Info().Str("host", config.Config.Tap.Proxy.Host).Uint16("port", config.Config.Tap.Proxy.Hub.Port).Msg("Connecting to:")
|
||||
u := url.URL{
|
||||
Scheme: "ws",
|
||||
Host: fmt.Sprintf("%s:%d", config.Config.Tap.Proxy.Host, config.Config.Tap.Proxy.Hub.Port),
|
||||
Path: "/scripts/logs",
|
||||
}
|
||||
|
||||
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(done)
|
||||
for {
|
||||
_, message, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
msg := string(message)
|
||||
if strings.Contains(msg, ":ERROR]") {
|
||||
msg = fmt.Sprintf(utils.Red, msg)
|
||||
fmt.Fprintln(os.Stderr, msg)
|
||||
} else {
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
case <-interrupt:
|
||||
log.Warn().Msg(fmt.Sprintf(utils.Yellow, "Received interrupt, exiting..."))
|
||||
|
||||
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
441
cmd/helmChart.go
Normal file
441
cmd/helmChart.go
Normal file
@@ -0,0 +1,441 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
"github.com/kubeshark/kubeshark/misc/fsUtils"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/ohler55/ojg/jp"
|
||||
"github.com/ohler55/ojg/oj"
|
||||
"github.com/otiai10/copy"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var helmChartCmd = &cobra.Command{
|
||||
Use: "helm-chart",
|
||||
Short: "Generate Helm chart of Kubeshark",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
runHelmChart()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Maintainer describes a Chart maintainer.
|
||||
type Maintainer struct {
|
||||
// Name is a user name or organization name
|
||||
Name string `json:"name,omitempty"`
|
||||
// Email is an optional email address to contact the named maintainer
|
||||
Email string `json:"email,omitempty"`
|
||||
// URL is an optional URL to an address for the named maintainer
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// Metadata for a Chart file. This models the structure of a Chart.yaml file.
|
||||
type Metadata struct {
|
||||
// The name of the chart. Required.
|
||||
Name string `json:"name,omitempty"`
|
||||
// The URL to a relevant project page, git repo, or contact person
|
||||
Home string `json:"home,omitempty"`
|
||||
// Source is the URL to the source code of this chart
|
||||
Sources []string `json:"sources,omitempty"`
|
||||
// A SemVer 2 conformant version string of the chart. Required.
|
||||
Version string `json:"version,omitempty"`
|
||||
// A one-sentence description of the chart
|
||||
Description string `json:"description,omitempty"`
|
||||
// A list of string keywords
|
||||
Keywords []string `json:"keywords,omitempty"`
|
||||
// A list of name and URL/email address combinations for the maintainer(s)
|
||||
Maintainers []*Maintainer `json:"maintainers,omitempty"`
|
||||
// The URL to an icon file.
|
||||
Icon string `json:"icon,omitempty"`
|
||||
// The API Version of this chart. Required.
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
// The condition to check to enable chart
|
||||
Condition string `json:"condition,omitempty"`
|
||||
// The tags to check to enable chart
|
||||
Tags string `json:"tags,omitempty"`
|
||||
// The version of the application enclosed inside of this chart.
|
||||
AppVersion string `json:"appVersion,omitempty"`
|
||||
// Whether or not this chart is deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// Annotations are additional mappings uninterpreted by Helm,
|
||||
// made available for inspection by other applications.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
// KubeVersion is a SemVer constraint specifying the version of Kubernetes required.
|
||||
KubeVersion string `json:"kubeVersion,omitempty"`
|
||||
// Dependencies are a list of dependencies for a chart.
|
||||
Dependencies []*Dependency `json:"dependencies,omitempty"`
|
||||
// Specifies the chart type: application or library
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// Dependency describes a chart upon which another chart depends.
|
||||
//
|
||||
// Dependencies can be used to express developer intent, or to capture the state
|
||||
// of a chart.
|
||||
type Dependency struct {
|
||||
// Name is the name of the dependency.
|
||||
//
|
||||
// This must mach the name in the dependency's Chart.yaml.
|
||||
Name string `json:"name"`
|
||||
// Version is the version (range) of this chart.
|
||||
//
|
||||
// A lock file will always produce a single version, while a dependency
|
||||
// may contain a semantic version range.
|
||||
Version string `json:"version,omitempty"`
|
||||
// The URL to the repository.
|
||||
//
|
||||
// Appending `index.yaml` to this string should result in a URL that can be
|
||||
// used to fetch the repository index.
|
||||
Repository string `json:"repository"`
|
||||
// A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
|
||||
Condition string `json:"condition,omitempty"`
|
||||
// Tags can be used to group charts for enabling/disabling together
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Enabled bool determines if chart should be loaded
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
// ImportValues holds the mapping of source values to parent key to be imported. Each item can be a
|
||||
// string or pair of child/parent sublist items.
|
||||
ImportValues []interface{} `json:"import-values,omitempty"`
|
||||
// Alias usable alias to be used for the chart
|
||||
Alias string `json:"alias,omitempty"`
|
||||
}
|
||||
|
||||
var namespaceMappings = map[string]interface{}{
|
||||
"metadata.name": "{{ .Values.tap.selfnamespace }}",
|
||||
}
|
||||
var serviceAccountMappings = map[string]interface{}{
|
||||
"metadata.namespace": "{{ .Values.tap.selfnamespace }}",
|
||||
}
|
||||
var clusterRoleMappings = serviceAccountMappings
|
||||
var clusterRoleBindingMappings = map[string]interface{}{
|
||||
"metadata.namespace": "{{ .Values.tap.selfnamespace }}",
|
||||
"subjects[0].namespace": "{{ .Values.tap.selfnamespace }}",
|
||||
}
|
||||
var hubPodMappings = map[string]interface{}{
|
||||
"metadata.namespace": "{{ .Values.tap.selfnamespace }}",
|
||||
"spec.containers[0].env": []map[string]interface{}{
|
||||
{
|
||||
"name": "POD_REGEX",
|
||||
"value": "{{ .Values.tap.regex }}",
|
||||
},
|
||||
{
|
||||
"name": "NAMESPACES",
|
||||
"value": "{{ gt (len .Values.tap.namespaces) 0 | ternary (join \",\" .Values.tap.namespaces) \"\" }}",
|
||||
},
|
||||
{
|
||||
"name": "LICENSE",
|
||||
"value": "{{ .Values.license }}",
|
||||
},
|
||||
{
|
||||
"name": "SCRIPTING_ENV",
|
||||
"value": "{}",
|
||||
},
|
||||
{
|
||||
"name": "SCRIPTING_SCRIPTS",
|
||||
"value": "[]",
|
||||
},
|
||||
},
|
||||
"spec.containers[0].image": "{{ .Values.tap.docker.registry }}/hub:{{ .Values.tap.docker.tag }}",
|
||||
"spec.containers[0].imagePullPolicy": "{{ .Values.tap.docker.imagepullpolicy }}",
|
||||
"spec.containers[0].resources.limits.cpu": "{{ .Values.tap.resources.hub.limits.cpu }}",
|
||||
"spec.containers[0].resources.limits.memory": "{{ .Values.tap.resources.hub.limits.memory }}",
|
||||
"spec.containers[0].resources.requests.cpu": "{{ .Values.tap.resources.hub.requests.cpu }}",
|
||||
"spec.containers[0].resources.requests.memory": "{{ .Values.tap.resources.hub.requests.memory }}",
|
||||
"spec.containers[0].command[0]": "{{ .Values.tap.debug | ternary \"./hub -debug\" \"./hub\" }}",
|
||||
}
|
||||
var hubServiceMappings = serviceAccountMappings
|
||||
var frontPodMappings = map[string]interface{}{
|
||||
"metadata.namespace": "{{ .Values.tap.selfnamespace }}",
|
||||
"spec.containers[0].image": "{{ .Values.tap.docker.registry }}/front:{{ .Values.tap.docker.tag }}",
|
||||
"spec.containers[0].imagePullPolicy": "{{ .Values.tap.docker.imagepullpolicy }}",
|
||||
}
|
||||
var frontServiceMappings = serviceAccountMappings
|
||||
var persistentVolumeMappings = map[string]interface{}{
|
||||
"metadata.namespace": "{{ .Values.tap.selfnamespace }}",
|
||||
"spec.resources.requests.storage": "{{ .Values.tap.storagelimit }}",
|
||||
"spec.storageClassName": "{{ .Values.tap.storageclass }}",
|
||||
}
|
||||
var workerDaemonSetMappings = map[string]interface{}{
|
||||
"metadata.namespace": "{{ .Values.tap.selfnamespace }}",
|
||||
"spec.template.spec.containers[0].image": "{{ .Values.tap.docker.registry }}/worker:{{ .Values.tap.docker.tag }}",
|
||||
"spec.template.spec.containers[0].imagePullPolicy": "{{ .Values.tap.docker.imagepullpolicy }}",
|
||||
"spec.template.spec.containers[0].resources.limits.cpu": "{{ .Values.tap.resources.worker.limits.cpu }}",
|
||||
"spec.template.spec.containers[0].resources.limits.memory": "{{ .Values.tap.resources.worker.limits.memory }}",
|
||||
"spec.template.spec.containers[0].resources.requests.cpu": "{{ .Values.tap.resources.worker.requests.cpu }}",
|
||||
"spec.template.spec.containers[0].resources.requests.memory": "{{ .Values.tap.resources.worker.requests.memory }}",
|
||||
"spec.template.spec.containers[0].command[0]": "{{ .Values.tap.debug | ternary \"./worker -debug\" \"./worker\" }}",
|
||||
"spec.template.spec.containers[0].command[4]": "{{ .Values.tap.proxy.worker.srvport }}",
|
||||
"spec.template.spec.containers[0].command[6]": "{{ .Values.tap.packetcapture }}",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(helmChartCmd)
|
||||
}
|
||||
|
||||
func runHelmChart() {
|
||||
namespace,
|
||||
serviceAccount,
|
||||
clusterRole,
|
||||
clusterRoleBinding,
|
||||
hubPod,
|
||||
hubService,
|
||||
frontPod,
|
||||
frontService,
|
||||
persistentVolume,
|
||||
workerDaemonSet,
|
||||
err := generateManifests()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
err = dumpHelmChart(map[string]interface{}{
|
||||
"00-namespace.yaml": template(namespace, namespaceMappings),
|
||||
"01-service-account.yaml": template(serviceAccount, serviceAccountMappings),
|
||||
"02-cluster-role.yaml": template(clusterRole, clusterRoleMappings),
|
||||
"03-cluster-role-binding.yaml": template(clusterRoleBinding, clusterRoleBindingMappings),
|
||||
"04-hub-pod.yaml": template(hubPod, hubPodMappings),
|
||||
"05-hub-service.yaml": template(hubService, hubServiceMappings),
|
||||
"06-front-pod.yaml": template(frontPod, frontPodMappings),
|
||||
"07-front-service.yaml": template(frontService, frontServiceMappings),
|
||||
"08-persistent-volume-claim.yaml": template(persistentVolume, persistentVolumeMappings),
|
||||
"09-worker-daemon-set.yaml": template(workerDaemonSet, workerDaemonSetMappings),
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func template(object interface{}, mappings map[string]interface{}) (template interface{}) {
|
||||
var err error
|
||||
var data []byte
|
||||
data, err = json.Marshal(object)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
var obj interface{}
|
||||
obj, err = oj.Parse(data)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
for path, value := range mappings {
|
||||
var x jp.Expr
|
||||
x, err = jp.ParseString(path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
err = x.Set(obj, value)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
newJson := oj.JSON(obj)
|
||||
|
||||
err = json.Unmarshal([]byte(newJson), &template)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleHubPod(manifest string) string {
|
||||
lines := strings.Split(manifest, "\n")
|
||||
|
||||
for i, line := range lines {
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "hostPort:") {
|
||||
lines[i] = " hostPort: {{ .Values.tap.proxy.hub.srvport }}"
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func handleFrontPod(manifest string) string {
|
||||
lines := strings.Split(manifest, "\n")
|
||||
|
||||
for i, line := range lines {
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "hostPort:") {
|
||||
lines[i] = " hostPort: {{ .Values.tap.proxy.front.srvport }}"
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func handlePVCManifest(manifest string) string {
|
||||
return fmt.Sprintf("{{- if .Values.tap.persistentstorage }}\n%s{{- end }}\n", manifest)
|
||||
}
|
||||
|
||||
func handleDaemonSetManifest(manifest string) string {
|
||||
lines := strings.Split(manifest, "\n")
|
||||
|
||||
for i, line := range lines {
|
||||
if strings.TrimSpace(line) == "- mountPath: /app/data" {
|
||||
lines[i] = fmt.Sprintf("{{- if .Values.tap.persistentstorage }}\n%s", line)
|
||||
}
|
||||
|
||||
if strings.TrimSpace(line) == "name: kubeshark-persistent-volume" {
|
||||
lines[i] = fmt.Sprintf("%s\n{{- end }}", line)
|
||||
}
|
||||
|
||||
if strings.TrimSpace(line) == "- name: kubeshark-persistent-volume" {
|
||||
lines[i] = fmt.Sprintf("{{- if .Values.tap.persistentstorage }}\n%s", line)
|
||||
}
|
||||
|
||||
if strings.TrimSpace(line) == "claimName: kubeshark-persistent-volume-claim" {
|
||||
lines[i] = fmt.Sprintf("%s\n{{- end }}", line)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "- containerPort:") {
|
||||
lines[i] = " - containerPort: {{ .Values.tap.proxy.worker.srvport }}"
|
||||
}
|
||||
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "hostPort:") {
|
||||
lines[i] = " hostPort: {{ .Values.tap.proxy.worker.srvport }}"
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func dumpHelmChart(objects map[string]interface{}) error {
|
||||
folder := filepath.Join(".", "helm-chart")
|
||||
templatesFolder := filepath.Join(folder, "templates")
|
||||
|
||||
err := fsUtils.RemoveFilesByExtension(templatesFolder, "yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(templatesFolder, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sort by filenames
|
||||
filenames := make([]string, 0)
|
||||
for filename := range objects {
|
||||
filenames = append(filenames, filename)
|
||||
}
|
||||
sort.Strings(filenames)
|
||||
|
||||
// Generate templates
|
||||
for _, filename := range filenames {
|
||||
manifest, err := utils.PrettyYamlOmitEmpty(objects[filename])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if filename == "04-hub-pod.yaml" {
|
||||
manifest = handleHubPod(manifest)
|
||||
}
|
||||
|
||||
if filename == "06-front-pod.yaml" {
|
||||
manifest = handleFrontPod(manifest)
|
||||
}
|
||||
|
||||
if filename == "08-persistent-volume-claim.yaml" {
|
||||
manifest = handlePVCManifest(manifest)
|
||||
}
|
||||
|
||||
if filename == "09-worker-daemon-set.yaml" {
|
||||
manifest = handleDaemonSetManifest(manifest)
|
||||
}
|
||||
|
||||
path := filepath.Join(templatesFolder, filename)
|
||||
err = os.WriteFile(path, []byte(manifestHeader+manifest), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info().Msgf("Helm chart template generated: %s", path)
|
||||
}
|
||||
|
||||
// Copy LICENSE
|
||||
licenseSrcPath := filepath.Join(".", "LICENSE")
|
||||
licenseDstPath := filepath.Join(folder, "LICENSE")
|
||||
err = copy.Copy(licenseSrcPath, licenseDstPath)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Str("path", licenseSrcPath).Msg("Couldn't find the license:")
|
||||
} else {
|
||||
log.Info().Msgf("Helm chart license copied: %s", licenseDstPath)
|
||||
}
|
||||
|
||||
// Generate Chart.yaml
|
||||
chartMetadata := Metadata{
|
||||
APIVersion: "v2",
|
||||
Name: misc.Program,
|
||||
Description: misc.Description,
|
||||
Home: misc.Website,
|
||||
Sources: []string{"https://github.com/kubeshark/kubeshark/tree/master/helm-chart"},
|
||||
Keywords: []string{
|
||||
"kubeshark",
|
||||
"packet capture",
|
||||
"traffic capture",
|
||||
"traffic analyzer",
|
||||
"network sniffer",
|
||||
"observability",
|
||||
"devops",
|
||||
"microservice",
|
||||
"forensics",
|
||||
"api",
|
||||
},
|
||||
Maintainers: []*Maintainer{
|
||||
{
|
||||
Name: misc.Software,
|
||||
Email: misc.Email,
|
||||
URL: misc.Website,
|
||||
},
|
||||
},
|
||||
Version: misc.Ver,
|
||||
AppVersion: misc.Ver,
|
||||
KubeVersion: fmt.Sprintf(">= %s-0", kubernetes.MinKubernetesServerVersion),
|
||||
Type: "application",
|
||||
}
|
||||
|
||||
chart, err := utils.PrettyYamlOmitEmpty(chartMetadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := filepath.Join(folder, "Chart.yaml")
|
||||
err = os.WriteFile(path, []byte(chart), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info().Msgf("Helm chart Chart.yaml generated: %s", path)
|
||||
|
||||
// Generate values.yaml
|
||||
values, err := utils.PrettyYaml(config.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path = filepath.Join(folder, "values.yaml")
|
||||
err = os.WriteFile(path, []byte(values), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info().Msgf("Helm chart values.yaml generated: %s", path)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -18,7 +18,7 @@ var logsCmd = &cobra.Command{
|
||||
Use: "logs",
|
||||
Short: "Create a ZIP file with logs for GitHub issues or troubleshooting",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
kubernetesProvider, err := getKubernetesProviderForCli()
|
||||
kubernetesProvider, err := getKubernetesProviderForCli(false, false)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
229
cmd/manifests.go
Normal file
229
cmd/manifests.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/docker"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
"github.com/kubeshark/kubeshark/misc/fsUtils"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
const manifestSeperator = "---"
|
||||
const manifestHeader = "# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!\n" + manifestSeperator + "\n"
|
||||
|
||||
var manifestsCmd = &cobra.Command{
|
||||
Use: "manifests",
|
||||
Short: "Generate Kubernetes manifests of Kubeshark",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
runManifests()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(manifestsCmd)
|
||||
|
||||
defaultManifestsConfig := config.ManifestsConfig{}
|
||||
if err := defaults.Set(&defaultManifestsConfig); err != nil {
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
|
||||
manifestsCmd.Flags().Bool("dump", defaultManifestsConfig.Dump, "Enable the debug mode")
|
||||
}
|
||||
|
||||
func runManifests() {
|
||||
namespace,
|
||||
serviceAccount,
|
||||
clusterRole,
|
||||
clusterRoleBinding,
|
||||
hubPod,
|
||||
hubService,
|
||||
frontPod,
|
||||
frontService,
|
||||
persistentVolume,
|
||||
workerDaemonSet,
|
||||
err := generateManifests()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
if config.Config.Manifests.Dump {
|
||||
err = dumpManifests(map[string]interface{}{
|
||||
"00-namespace.yaml": namespace,
|
||||
"01-service-account.yaml": serviceAccount,
|
||||
"02-cluster-role.yaml": clusterRole,
|
||||
"03-cluster-role-binding.yaml": clusterRoleBinding,
|
||||
"04-hub-pod.yaml": hubPod,
|
||||
"05-hub-service.yaml": hubService,
|
||||
"06-front-pod.yaml": frontPod,
|
||||
"07-front-service.yaml": frontService,
|
||||
"08-persistent-volume-claim.yaml": persistentVolume,
|
||||
"09-worker-daemon-set.yaml": workerDaemonSet,
|
||||
})
|
||||
} else {
|
||||
err = printManifests([]interface{}{
|
||||
namespace,
|
||||
serviceAccount,
|
||||
clusterRole,
|
||||
clusterRoleBinding,
|
||||
hubPod,
|
||||
hubService,
|
||||
frontPod,
|
||||
frontService,
|
||||
workerDaemonSet,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func generateManifests() (
|
||||
namespace *v1.Namespace,
|
||||
serviceAccount *v1.ServiceAccount,
|
||||
clusterRole *rbac.ClusterRole,
|
||||
clusterRoleBinding *rbac.ClusterRoleBinding,
|
||||
hubPod *v1.Pod,
|
||||
hubService *v1.Service,
|
||||
frontPod *v1.Pod,
|
||||
frontService *v1.Service,
|
||||
persistentVolumeClaim *v1.PersistentVolumeClaim,
|
||||
workerDaemonSet *kubernetes.DaemonSet,
|
||||
err error,
|
||||
) {
|
||||
config.Config.License = ""
|
||||
persistentStorage := config.Config.Tap.PersistentStorage
|
||||
config.Config.Tap.PersistentStorage = true
|
||||
|
||||
var kubernetesProvider *kubernetes.Provider
|
||||
kubernetesProvider, err = getKubernetesProviderForCli(true, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
namespace = kubernetesProvider.BuildNamespace(config.Config.Tap.SelfNamespace)
|
||||
|
||||
serviceAccount = kubernetesProvider.BuildServiceAccount()
|
||||
|
||||
clusterRole = kubernetesProvider.BuildClusterRole()
|
||||
|
||||
clusterRoleBinding = kubernetesProvider.BuildClusterRoleBinding()
|
||||
|
||||
hubPod, err = kubernetesProvider.BuildHubPod(&kubernetes.PodOptions{
|
||||
Namespace: config.Config.Tap.SelfNamespace,
|
||||
PodName: kubernetes.HubPodName,
|
||||
PodImage: docker.GetHubImage(),
|
||||
ServiceAccountName: kubernetes.ServiceAccountName,
|
||||
Resources: config.Config.Tap.Resources.Hub,
|
||||
ImagePullPolicy: config.Config.ImagePullPolicy(),
|
||||
ImagePullSecrets: config.Config.ImagePullSecrets(),
|
||||
Debug: config.Config.Tap.Debug,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hubService = kubernetesProvider.BuildHubService(config.Config.Tap.SelfNamespace)
|
||||
|
||||
frontPod, err = kubernetesProvider.BuildFrontPod(&kubernetes.PodOptions{
|
||||
Namespace: config.Config.Tap.SelfNamespace,
|
||||
PodName: kubernetes.FrontPodName,
|
||||
PodImage: docker.GetHubImage(),
|
||||
ServiceAccountName: kubernetes.ServiceAccountName,
|
||||
Resources: config.Config.Tap.Resources.Hub,
|
||||
ImagePullPolicy: config.Config.ImagePullPolicy(),
|
||||
ImagePullSecrets: config.Config.ImagePullSecrets(),
|
||||
Debug: config.Config.Tap.Debug,
|
||||
}, config.Config.Tap.Proxy.Host, fmt.Sprintf("%d", config.Config.Tap.Proxy.Hub.Port))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
frontService = kubernetesProvider.BuildFrontService(config.Config.Tap.SelfNamespace)
|
||||
|
||||
persistentVolumeClaim, err = kubernetesProvider.BuildPersistentVolumeClaim()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
workerDaemonSet, err = kubernetesProvider.BuildWorkerDaemonSet(
|
||||
docker.GetWorkerImage(),
|
||||
kubernetes.WorkerDaemonSetName,
|
||||
kubernetes.ServiceAccountName,
|
||||
config.Config.Tap.Resources.Worker,
|
||||
config.Config.ImagePullPolicy(),
|
||||
config.Config.ImagePullSecrets(),
|
||||
config.Config.Tap.ServiceMesh,
|
||||
config.Config.Tap.Tls,
|
||||
config.Config.Tap.Debug,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
config.Config.Tap.PersistentStorage = persistentStorage
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func dumpManifests(objects map[string]interface{}) error {
|
||||
folder := filepath.Join(".", "manifests")
|
||||
|
||||
err := fsUtils.RemoveFilesByExtension(folder, "yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(folder, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sort by filenames
|
||||
filenames := make([]string, 0)
|
||||
for filename := range objects {
|
||||
filenames = append(filenames, filename)
|
||||
}
|
||||
sort.Strings(filenames)
|
||||
|
||||
for _, filename := range filenames {
|
||||
manifest, err := utils.PrettyYamlOmitEmpty(objects[filename])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := filepath.Join(folder, filename)
|
||||
err = os.WriteFile(path, []byte(manifestHeader+manifest), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info().Msgf("Manifest generated: %s", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printManifests(objects []interface{}) error {
|
||||
for _, object := range objects {
|
||||
manifest, err := utils.PrettyYamlOmitEmpty(object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(manifestSeperator)
|
||||
fmt.Println(manifest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
# This example shows permissions that enrich the logs with additional info
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-runner-debug-clusterrole
|
||||
rules:
|
||||
- apiGroups: ["events.k8s.io"]
|
||||
resources: ["events"]
|
||||
verbs: ["watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["get"]
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-runner-debug-clusterrolebindings
|
||||
subjects:
|
||||
- kind: User
|
||||
name: user-with-clusterwide-access
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: kubeshark-runner-debug-clusterrole
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
@@ -1,37 +0,0 @@
|
||||
# This example shows permissions that are required for Kubeshark to resolve IPs to service names
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-resolver-clusterrole
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["serviceaccounts"]
|
||||
verbs: ["get", "create"]
|
||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||
resources: ["clusterroles"]
|
||||
verbs: ["get", "list", "create", "delete"]
|
||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||
resources: ["clusterrolebindings"]
|
||||
verbs: ["get", "list", "create", "delete"]
|
||||
- apiGroups: ["", "apps", "extensions"]
|
||||
resources: ["pods"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["", "apps", "extensions"]
|
||||
resources: ["services"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["", "apps", "extensions"]
|
||||
resources: ["endpoints"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-resolver-clusterrolebindings
|
||||
subjects:
|
||||
- kind: User
|
||||
name: user-with-clusterwide-access
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: kubeshark-resolver-clusterrole
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
@@ -1,40 +0,0 @@
|
||||
# This example shows the permissions that are required in order to run the `kubeshark tap` command
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-runner-clusterrole
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["list", "watch", "create"]
|
||||
- apiGroups: [""]
|
||||
resources: ["services"]
|
||||
verbs: ["get", "create"]
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["daemonsets"]
|
||||
verbs: ["create", "patch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["namespaces"]
|
||||
verbs: ["list", "watch", "create", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
verbs: ["get", "create"]
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps"]
|
||||
verbs: ["create"]
|
||||
- apiGroups: [""]
|
||||
resources: ["pods/log"]
|
||||
verbs: ["get"]
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-runner-clusterrolebindings
|
||||
subjects:
|
||||
- kind: User
|
||||
name: user-with-clusterwide-access
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: kubeshark-runner-clusterrole
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
@@ -1,25 +0,0 @@
|
||||
# This example shows permissions that enrich the logs with additional info in namespace-restricted mode
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-runner-debug-role
|
||||
rules:
|
||||
- apiGroups: ["events.k8s.io"]
|
||||
resources: ["events"]
|
||||
verbs: ["watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["get"]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-runner-debug-rolebindings
|
||||
subjects:
|
||||
- kind: User
|
||||
name: user-with-restricted-access
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: kubeshark-runner-debug-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
@@ -1,37 +0,0 @@
|
||||
# This example shows permissions that are required for Kubeshark to resolve IPs to service names in namespace-restricted mode
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-resolver-role
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["serviceaccounts"]
|
||||
verbs: ["get", "list", "create", "delete"]
|
||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||
resources: ["roles"]
|
||||
verbs: ["get", "list", "create", "delete"]
|
||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||
resources: ["rolebindings"]
|
||||
verbs: ["get", "list", "create", "delete"]
|
||||
- apiGroups: ["", "apps", "extensions"]
|
||||
resources: ["pods"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["", "apps", "extensions"]
|
||||
resources: ["services"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["", "apps", "extensions"]
|
||||
resources: ["endpoints"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-resolver-rolebindings
|
||||
subjects:
|
||||
- kind: User
|
||||
name: user-with-restricted-access
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: kubeshark-resolver-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
@@ -1,37 +0,0 @@
|
||||
# This example shows the permissions that are required in order to run the `kubeshark tap` command in namespace-restricted mode
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-runner-role
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["list", "watch", "create"]
|
||||
- apiGroups: [""]
|
||||
resources: ["services"]
|
||||
verbs: ["get", "create", "delete"]
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["daemonsets"]
|
||||
verbs: ["create", "patch", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
verbs: ["get", "create", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps"]
|
||||
verbs: ["create", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["pods/log"]
|
||||
verbs: ["get"]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kubeshark-runner-rolebindings
|
||||
subjects:
|
||||
- kind: User
|
||||
name: user-with-restricted-access
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: kubeshark-runner-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
125
cmd/pro.go
Normal file
125
cmd/pro.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
"github.com/kubeshark/kubeshark/internal/connect"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var proCmd = &cobra.Command{
|
||||
Use: "pro",
|
||||
Short: "Acquire a Pro license",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
acquireLicense()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
const (
|
||||
PRO_URL = "https://console.kubeshark.co"
|
||||
PRO_PORT = 5252
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(proCmd)
|
||||
|
||||
defaultTapConfig := configStructs.TapConfig{}
|
||||
if err := defaults.Set(&defaultTapConfig); err != nil {
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
|
||||
proCmd.Flags().Uint16(configStructs.ProxyHubPortLabel, defaultTapConfig.Proxy.Hub.Port, "Provide a custom port for the Hub")
|
||||
proCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the Hub")
|
||||
}
|
||||
|
||||
func acquireLicense() {
|
||||
hubUrl := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port)
|
||||
response, err := http.Get(fmt.Sprintf("%s/echo", hubUrl))
|
||||
if err != nil || response.StatusCode != 200 {
|
||||
log.Info().Msg(fmt.Sprintf(utils.Yellow, "Couldn't connect to Hub. Establishing proxy..."))
|
||||
runProxy(false, true)
|
||||
}
|
||||
|
||||
connector = connect.NewConnector(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port), connect.DefaultRetries, connect.DefaultTimeout)
|
||||
|
||||
log.Info().Str("url", PRO_URL).Msg("Opening in the browser:")
|
||||
utils.OpenBrowser(PRO_URL)
|
||||
|
||||
runLicenseRecieverServer()
|
||||
}
|
||||
|
||||
func updateLicense(licenseKey string) {
|
||||
log.Info().Str("key", licenseKey).Msg("Received license:")
|
||||
|
||||
config.Config.License = licenseKey
|
||||
err := config.WriteConfig(&config.Config)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
}
|
||||
|
||||
connector.PostLicenseSingle(config.Config.License)
|
||||
|
||||
log.Info().Msg("Updated the license. Exiting.")
|
||||
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
os.Exit(0)
|
||||
}()
|
||||
}
|
||||
|
||||
func runLicenseRecieverServer() {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
ginApp := gin.New()
|
||||
ginApp.Use(func(c *gin.Context) {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, x-session-token")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
|
||||
c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
})
|
||||
|
||||
ginApp.POST("/", func(c *gin.Context) {
|
||||
data, err := ioutil.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
licenseKey := string(data)
|
||||
|
||||
updateLicense(licenseKey)
|
||||
})
|
||||
|
||||
go func() {
|
||||
if err := ginApp.Run(fmt.Sprintf(":%d", PRO_PORT)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Info().Msg("Alternatively enter your license key:")
|
||||
|
||||
var licenseKey string
|
||||
fmt.Scanf("%s", &licenseKey)
|
||||
|
||||
updateLicense(licenseKey)
|
||||
}
|
||||
10
cmd/proxy.go
10
cmd/proxy.go
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
var proxyCmd = &cobra.Command{
|
||||
Use: "proxy",
|
||||
Short: "Open the web UI (front-end) in the browser via proxy/port-forward.",
|
||||
Short: "Open the web UI (front-end) in the browser via proxy/port-forward",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
runProxy()
|
||||
runProxy(true, false)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -24,7 +24,7 @@ func init() {
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
|
||||
proxyCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.SrcPort, "Provide a custom port for the front-end proxy/port-forward.")
|
||||
proxyCmd.Flags().Uint16(configStructs.ProxyHubPortLabel, defaultTapConfig.Proxy.Hub.SrcPort, "Provide a custom port for the Hub proxy/port-forward.")
|
||||
proxyCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the proxy/port-forward.")
|
||||
proxyCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.Port, "Provide a custom port for the front-end proxy/port-forward")
|
||||
proxyCmd.Flags().Uint16(configStructs.ProxyHubPortLabel, defaultTapConfig.Proxy.Hub.Port, "Provide a custom port for the Hub proxy/port-forward")
|
||||
proxyCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the proxy/port-forward")
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func runProxy() {
|
||||
kubernetesProvider, err := getKubernetesProviderForCli()
|
||||
func runProxy(block bool, noBrowser bool) {
|
||||
kubernetesProvider, err := getKubernetesProviderForCli(false, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -23,10 +23,10 @@ func runProxy() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
exists, err := kubernetesProvider.DoesServiceExist(ctx, config.Config.SelfNamespace, kubernetes.FrontServiceName)
|
||||
exists, err := kubernetesProvider.DoesServiceExist(ctx, config.Config.Tap.SelfNamespace, kubernetes.FrontServiceName)
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Str("service", misc.Program).
|
||||
Str("service", kubernetes.FrontServiceName).
|
||||
Err(err).
|
||||
Msg("Failed to found service!")
|
||||
cancel()
|
||||
@@ -42,36 +42,96 @@ func runProxy() {
|
||||
return
|
||||
}
|
||||
|
||||
url := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Front.SrcPort)
|
||||
exists, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.Tap.SelfNamespace, kubernetes.HubServiceName)
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Str("service", kubernetes.HubServiceName).
|
||||
Err(err).
|
||||
Msg("Failed to found service!")
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
|
||||
response, err := http.Get(fmt.Sprintf("%s/", url))
|
||||
if !exists {
|
||||
log.Error().
|
||||
Str("service", kubernetes.HubServiceName).
|
||||
Str("command", fmt.Sprintf("%s %s", misc.Program, tapCmd.Use)).
|
||||
Msg("Service not found! You should run the command first:")
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
|
||||
var establishedProxy bool
|
||||
|
||||
hubUrl := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port)
|
||||
response, err := http.Get(fmt.Sprintf("%s/echo", hubUrl))
|
||||
if err == nil && response.StatusCode == 200 {
|
||||
log.Info().
|
||||
Str("service", kubernetes.HubServiceName).
|
||||
Int("port", int(config.Config.Tap.Proxy.Hub.Port)).
|
||||
Msg("Found a running service.")
|
||||
|
||||
okToOpen("Hub", hubUrl, true)
|
||||
} else {
|
||||
startProxyReportErrorIfAny(
|
||||
kubernetesProvider,
|
||||
ctx,
|
||||
kubernetes.HubServiceName,
|
||||
kubernetes.HubPodName,
|
||||
configStructs.ProxyHubPortLabel,
|
||||
config.Config.Tap.Proxy.Hub.Port,
|
||||
configStructs.ContainerPort,
|
||||
"/echo",
|
||||
)
|
||||
connector := connect.NewConnector(hubUrl, connect.DefaultRetries, connect.DefaultTimeout)
|
||||
if err := connector.TestConnection("/echo"); err != nil {
|
||||
log.Error().Msg(fmt.Sprintf(utils.Red, "Couldn't connect to Hub."))
|
||||
return
|
||||
}
|
||||
|
||||
establishedProxy = true
|
||||
okToOpen("Hub", hubUrl, true)
|
||||
}
|
||||
|
||||
frontUrl := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Front.Port)
|
||||
response, err = http.Get(fmt.Sprintf("%s/", frontUrl))
|
||||
if err == nil && response.StatusCode == 200 {
|
||||
log.Info().
|
||||
Str("service", kubernetes.FrontServiceName).
|
||||
Int("port", int(config.Config.Tap.Proxy.Front.SrcPort)).
|
||||
Int("port", int(config.Config.Tap.Proxy.Front.Port)).
|
||||
Msg("Found a running service.")
|
||||
|
||||
okToOpen(url)
|
||||
return
|
||||
}
|
||||
log.Info().Msg("Establishing connection to K8s cluster...")
|
||||
startProxyReportErrorIfAny(kubernetesProvider, ctx, cancel, kubernetes.FrontServiceName, configStructs.ProxyFrontPortLabel, config.Config.Tap.Proxy.Front.SrcPort, config.Config.Tap.Proxy.Front.DstPort, "")
|
||||
okToOpen("Kubeshark", frontUrl, noBrowser)
|
||||
} else {
|
||||
startProxyReportErrorIfAny(
|
||||
kubernetesProvider,
|
||||
ctx,
|
||||
kubernetes.FrontServiceName,
|
||||
kubernetes.FrontPodName,
|
||||
configStructs.ProxyFrontPortLabel,
|
||||
config.Config.Tap.Proxy.Front.Port,
|
||||
configStructs.ContainerPort,
|
||||
"",
|
||||
)
|
||||
connector := connect.NewConnector(frontUrl, connect.DefaultRetries, connect.DefaultTimeout)
|
||||
if err := connector.TestConnection(""); err != nil {
|
||||
log.Error().Msg(fmt.Sprintf(utils.Red, "Couldn't connect to Front."))
|
||||
return
|
||||
}
|
||||
|
||||
connector := connect.NewConnector(url, connect.DefaultRetries, connect.DefaultTimeout)
|
||||
if err := connector.TestConnection(""); err != nil {
|
||||
log.Error().Msg(fmt.Sprintf(utils.Red, "Couldn't connect to Front."))
|
||||
return
|
||||
establishedProxy = true
|
||||
okToOpen("Kubeshark", frontUrl, noBrowser)
|
||||
}
|
||||
|
||||
okToOpen(url)
|
||||
|
||||
utils.WaitForTermination(ctx, cancel)
|
||||
if establishedProxy && block {
|
||||
utils.WaitForTermination(ctx, cancel)
|
||||
}
|
||||
}
|
||||
|
||||
func okToOpen(url string) {
|
||||
log.Info().Str("url", url).Msg(fmt.Sprintf(utils.Green, fmt.Sprintf("%s is available at:", misc.Software)))
|
||||
func okToOpen(name string, url string, noBrowser bool) {
|
||||
log.Info().Str("url", url).Msg(fmt.Sprintf(utils.Green, fmt.Sprintf("%s is available at:", name)))
|
||||
|
||||
if !config.Config.HeadlessMode {
|
||||
if !config.Config.HeadlessMode && !noBrowser {
|
||||
utils.OpenBrowser(url)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ import (
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "kubeshark",
|
||||
Short: fmt.Sprintf("%s: The API Traffic Viewer for Kubernetes", misc.Software),
|
||||
Long: fmt.Sprintf(`%s: The API Traffic Viewer for Kubernetes
|
||||
Short: fmt.Sprintf("%s: %s", misc.Software, misc.Description),
|
||||
Long: fmt.Sprintf(`%s: %s
|
||||
An extensible Kubernetes-aware network sniffer and kernel tracer.
|
||||
For more info: %s`, misc.Software, misc.Website),
|
||||
For more info: %s`, misc.Software, misc.Description, misc.Website),
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := config.InitConfig(cmd); err != nil {
|
||||
log.Fatal().Err(err).Send()
|
||||
@@ -32,8 +32,7 @@ func init() {
|
||||
}
|
||||
|
||||
rootCmd.PersistentFlags().StringSlice(config.SetCommandName, []string{}, fmt.Sprintf("Override values using --%s", config.SetCommandName))
|
||||
rootCmd.PersistentFlags().String(config.ConfigFilePathCommandName, defaultConfig.ConfigFilePath, fmt.Sprintf("Override config file path using --%s", config.ConfigFilePathCommandName))
|
||||
rootCmd.PersistentFlags().BoolP(config.DebugFlag, "d", false, "Enable debug mode.")
|
||||
rootCmd.PersistentFlags().BoolP(config.DebugFlag, "d", false, "Enable debug mode")
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
|
||||
152
cmd/scripts.go
Normal file
152
cmd/scripts.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
"github.com/kubeshark/kubeshark/internal/connect"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var scriptsCmd = &cobra.Command{
|
||||
Use: "scripts",
|
||||
Short: "Watch the `scripting.source` directory for changes and update the scripts",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
runScripts()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(scriptsCmd)
|
||||
|
||||
defaultTapConfig := configStructs.TapConfig{}
|
||||
if err := defaults.Set(&defaultTapConfig); err != nil {
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
|
||||
scriptsCmd.Flags().Uint16(configStructs.ProxyHubPortLabel, defaultTapConfig.Proxy.Hub.Port, "Provide a custom port for the Hub")
|
||||
scriptsCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the Hub")
|
||||
}
|
||||
|
||||
func runScripts() {
|
||||
if config.Config.Scripting.Source == "" {
|
||||
log.Error().Msg("`scripting.source` field is empty.")
|
||||
return
|
||||
}
|
||||
|
||||
hubUrl := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port)
|
||||
response, err := http.Get(fmt.Sprintf("%s/echo", hubUrl))
|
||||
if err != nil || response.StatusCode != 200 {
|
||||
log.Info().Msg(fmt.Sprintf(utils.Yellow, "Couldn't connect to Hub. Establishing proxy..."))
|
||||
runProxy(false, true)
|
||||
}
|
||||
|
||||
connector = connect.NewConnector(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port), connect.DefaultRetries, connect.DefaultTimeout)
|
||||
|
||||
watchScripts(true)
|
||||
}
|
||||
|
||||
func watchScripts(block bool) {
|
||||
files := make(map[string]int64)
|
||||
|
||||
scripts, err := config.Config.Scripting.GetScripts()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
for _, script := range scripts {
|
||||
index, err := connector.PostScript(script)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
files[script.Path] = index
|
||||
}
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
if block {
|
||||
defer watcher.Close()
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
// watch for events
|
||||
case event := <-watcher.Events:
|
||||
switch event.Op {
|
||||
case fsnotify.Create:
|
||||
script, err := misc.ReadScriptFile(event.Name)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
continue
|
||||
}
|
||||
|
||||
index, err := connector.PostScript(script)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
continue
|
||||
}
|
||||
|
||||
files[script.Path] = index
|
||||
|
||||
case fsnotify.Write:
|
||||
index := files[event.Name]
|
||||
script, err := misc.ReadScriptFile(event.Name)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
continue
|
||||
}
|
||||
|
||||
err = connector.PutScript(script, index)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
continue
|
||||
}
|
||||
|
||||
case fsnotify.Rename:
|
||||
index := files[event.Name]
|
||||
err := connector.DeleteScript(index)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
continue
|
||||
}
|
||||
|
||||
default:
|
||||
// pass
|
||||
}
|
||||
|
||||
// watch for errors
|
||||
case err := <-watcher.Errors:
|
||||
log.Error().Err(err).Send()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if err := watcher.Add(config.Config.Scripting.Source); err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
}
|
||||
|
||||
log.Info().Str("directory", config.Config.Scripting.Source).Msg("Watching scripts against changes:")
|
||||
|
||||
if block {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
utils.WaitForTermination(ctx, cancel)
|
||||
}
|
||||
}
|
||||
34
cmd/tap.go
34
cmd/tap.go
@@ -15,8 +15,7 @@ import (
|
||||
|
||||
var tapCmd = &cobra.Command{
|
||||
Use: "tap [POD REGEX]",
|
||||
Short: "Capture the network traffic in your Kubernetes cluster.",
|
||||
Long: "Capture the network traffic in your Kubernetes cluster.",
|
||||
Short: "Capture the network traffic in your Kubernetes cluster",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
tap()
|
||||
return nil
|
||||
@@ -44,17 +43,22 @@ func init() {
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
|
||||
tapCmd.Flags().StringP(configStructs.DockerRegistryLabel, "r", defaultTapConfig.Docker.Registry, "The Docker registry that's hosting the images.")
|
||||
tapCmd.Flags().StringP(configStructs.DockerTagLabel, "t", defaultTapConfig.Docker.Tag, "The tag of the Docker images that are going to be pulled.")
|
||||
tapCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.SrcPort, "Provide a custom port for the front-end proxy/port-forward.")
|
||||
tapCmd.Flags().Uint16(configStructs.ProxyHubPortLabel, defaultTapConfig.Proxy.Hub.SrcPort, "Provide a custom port for the Hub proxy/port-forward.")
|
||||
tapCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the proxy/port-forward.")
|
||||
tapCmd.Flags().StringSliceP(configStructs.NamespacesLabel, "n", defaultTapConfig.Namespaces, "Namespaces selector.")
|
||||
tapCmd.Flags().BoolP(configStructs.AllNamespacesLabel, "A", defaultTapConfig.AllNamespaces, "Tap all namespaces.")
|
||||
tapCmd.Flags().String(configStructs.StorageLimitLabel, defaultTapConfig.StorageLimit, "Override the default storage limit. (per node)")
|
||||
tapCmd.Flags().Bool(configStructs.DryRunLabel, defaultTapConfig.DryRun, "Preview of all pods matching the regex, without tapping them.")
|
||||
tapCmd.Flags().StringP(configStructs.PcapLabel, "p", defaultTapConfig.Pcap, fmt.Sprintf("Capture from a PCAP snapshot of %s (.tar.gz) using your Docker Daemon instead of Kubernetes.", misc.Software))
|
||||
tapCmd.Flags().Bool(configStructs.ServiceMeshLabel, defaultTapConfig.ServiceMesh, "Capture the encrypted traffic if the cluster is configured with a service mesh and with mTLS.")
|
||||
tapCmd.Flags().Bool(configStructs.TlsLabel, defaultTapConfig.Tls, "Capture the traffic that's encrypted with OpenSSL or Go crypto/tls libraries.")
|
||||
tapCmd.Flags().Bool(configStructs.DebugLabel, defaultTapConfig.Debug, "Enable the debug mode.")
|
||||
tapCmd.Flags().StringP(configStructs.DockerRegistryLabel, "r", defaultTapConfig.Docker.Registry, "The Docker registry that's hosting the images")
|
||||
tapCmd.Flags().StringP(configStructs.DockerTagLabel, "t", defaultTapConfig.Docker.Tag, "The tag of the Docker images that are going to be pulled")
|
||||
tapCmd.Flags().String(configStructs.DockerImagePullPolicy, defaultTapConfig.Docker.ImagePullPolicy, "ImagePullPolicy for the Docker images")
|
||||
tapCmd.Flags().StringSlice(configStructs.DockerImagePullSecrets, defaultTapConfig.Docker.ImagePullSecrets, "ImagePullSecrets for the Docker images")
|
||||
tapCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.Port, "Provide a custom port for the front-end proxy/port-forward")
|
||||
tapCmd.Flags().Uint16(configStructs.ProxyHubPortLabel, defaultTapConfig.Proxy.Hub.Port, "Provide a custom port for the Hub proxy/port-forward")
|
||||
tapCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the proxy/port-forward")
|
||||
tapCmd.Flags().StringSliceP(configStructs.NamespacesLabel, "n", defaultTapConfig.Namespaces, "Namespaces selector")
|
||||
tapCmd.Flags().StringP(configStructs.SelfNamespaceLabel, "s", defaultTapConfig.SelfNamespace, "Self-namespace of Kubeshark")
|
||||
tapCmd.Flags().Bool(configStructs.PersistentStorageLabel, defaultTapConfig.PersistentStorage, "Enable persistent storage (PersistentVolumeClaim)")
|
||||
tapCmd.Flags().String(configStructs.StorageLimitLabel, defaultTapConfig.StorageLimit, "Override the default storage limit (per node)")
|
||||
tapCmd.Flags().String(configStructs.StorageClassLabel, defaultTapConfig.StorageClass, "Override the default storage class of the PersistentVolumeClaim (per node)")
|
||||
tapCmd.Flags().Bool(configStructs.DryRunLabel, defaultTapConfig.DryRun, "Preview of all pods matching the regex, without tapping them")
|
||||
tapCmd.Flags().StringP(configStructs.PcapLabel, "p", defaultTapConfig.Pcap, fmt.Sprintf("Capture from a PCAP snapshot of %s (.tar.gz) using your Docker Daemon instead of Kubernetes", misc.Software))
|
||||
tapCmd.Flags().Bool(configStructs.ServiceMeshLabel, defaultTapConfig.ServiceMesh, "Capture the encrypted traffic if the cluster is configured with a service mesh and with mTLS")
|
||||
tapCmd.Flags().Bool(configStructs.TlsLabel, defaultTapConfig.Tls, "Capture the traffic that's encrypted with OpenSSL or Go crypto/tls libraries")
|
||||
tapCmd.Flags().Bool(configStructs.IgnoreTaintedLabel, defaultTapConfig.IgnoreTainted, "Ignore tainted pods while running Worker DaemonSet")
|
||||
tapCmd.Flags().Bool(configStructs.DebugLabel, defaultTapConfig.Debug, "Enable the debug mode")
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
"github.com/kubeshark/kubeshark/docker"
|
||||
"github.com/kubeshark/kubeshark/internal/connect"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
@@ -141,10 +142,10 @@ func createAndStartContainers(
|
||||
|
||||
hostConfigFront := &container.HostConfig{
|
||||
PortBindings: nat.PortMap{
|
||||
nat.Port(fmt.Sprintf("%d/tcp", config.Config.Tap.Proxy.Front.DstPort)): []nat.PortBinding{
|
||||
nat.Port(fmt.Sprintf("%d/tcp", configStructs.ContainerPort)): []nat.PortBinding{
|
||||
{
|
||||
HostIP: hostIP,
|
||||
HostPort: fmt.Sprintf("%d", config.Config.Tap.Proxy.Front.SrcPort),
|
||||
HostPort: fmt.Sprintf("%d", config.Config.Tap.Proxy.Front.Port),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -156,7 +157,7 @@ func createAndStartContainers(
|
||||
Env: []string{
|
||||
"REACT_APP_DEFAULT_FILTER= ",
|
||||
"REACT_APP_HUB_HOST= ",
|
||||
fmt.Sprintf("REACT_APP_HUB_PORT=%d", config.Config.Tap.Proxy.Hub.SrcPort),
|
||||
fmt.Sprintf("REACT_APP_HUB_PORT=%d", config.Config.Tap.Proxy.Hub.Port),
|
||||
},
|
||||
}, hostConfigFront, nil, nil, nameFront)
|
||||
if err != nil {
|
||||
@@ -165,16 +166,16 @@ func createAndStartContainers(
|
||||
|
||||
hostConfigHub := &container.HostConfig{
|
||||
PortBindings: nat.PortMap{
|
||||
nat.Port(fmt.Sprintf("%d/tcp", config.Config.Tap.Proxy.Hub.DstPort)): []nat.PortBinding{
|
||||
nat.Port(fmt.Sprintf("%d/tcp", config.Config.Tap.Proxy.Hub.SrvPort)): []nat.PortBinding{
|
||||
{
|
||||
HostIP: hostIP,
|
||||
HostPort: fmt.Sprintf("%d", config.Config.Tap.Proxy.Hub.SrcPort),
|
||||
HostPort: fmt.Sprintf("%d", config.Config.Tap.Proxy.Hub.Port),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cmdHub := []string{"-port", fmt.Sprintf("%d", config.Config.Tap.Proxy.Hub.DstPort)}
|
||||
cmdHub := []string{"-port", fmt.Sprintf("%d", config.Config.Tap.Proxy.Hub.SrvPort)}
|
||||
if config.DebugMode {
|
||||
cmdHub = append(cmdHub, fmt.Sprintf("-%s", config.DebugFlag))
|
||||
}
|
||||
@@ -183,13 +184,13 @@ func createAndStartContainers(
|
||||
Image: imageHub,
|
||||
Cmd: cmdHub,
|
||||
Tty: false,
|
||||
ExposedPorts: nat.PortSet{nat.Port(fmt.Sprintf("%d/tcp", config.Config.Tap.Proxy.Hub.DstPort)): {}},
|
||||
ExposedPorts: nat.PortSet{nat.Port(fmt.Sprintf("%d/tcp", config.Config.Tap.Proxy.Hub.SrvPort)): {}},
|
||||
}, hostConfigHub, nil, nil, nameHub)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cmdWorker := []string{"-f", "./import", "-port", fmt.Sprintf("%d", config.Config.Tap.Proxy.Worker.DstPort)}
|
||||
cmdWorker := []string{"-f", "./import", "-port", fmt.Sprintf("%d", config.Config.Tap.Proxy.Worker.SrvPort)}
|
||||
if config.DebugMode {
|
||||
cmdWorker = append(cmdWorker, fmt.Sprintf("-%s", config.DebugFlag))
|
||||
}
|
||||
@@ -328,14 +329,19 @@ func pcap(tarPath string) {
|
||||
},
|
||||
}
|
||||
|
||||
connector = connect.NewConnector(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.SrcPort), connect.DefaultRetries, connect.DefaultTimeout)
|
||||
connector = connect.NewConnector(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port), connect.DefaultRetries, connect.DefaultTimeout)
|
||||
connector.PostWorkerPodToHub(workerPod)
|
||||
|
||||
// License
|
||||
if config.Config.License != "" {
|
||||
connector.PostLicense(config.Config.License)
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Str("url", kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.SrcPort)).
|
||||
Str("url", kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port)).
|
||||
Msg(fmt.Sprintf(utils.Green, "Hub is available at:"))
|
||||
|
||||
url := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Front.SrcPort)
|
||||
url := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Front.Port)
|
||||
log.Info().Str("url", url).Msg(fmt.Sprintf(utils.Green, fmt.Sprintf("%s is available at:", misc.Software)))
|
||||
|
||||
if !config.Config.HeadlessMode {
|
||||
|
||||
261
cmd/tapRunner.go
261
cmd/tapRunner.go
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kubeshark/kubeshark/docker"
|
||||
@@ -34,11 +35,18 @@ type tapState struct {
|
||||
|
||||
var state tapState
|
||||
var connector *connect.Connector
|
||||
var hubPodReady bool
|
||||
var frontPodReady bool
|
||||
var proxyDone bool
|
||||
|
||||
type Readiness struct {
|
||||
Hub bool
|
||||
Front bool
|
||||
Proxy bool
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
var ready *Readiness
|
||||
|
||||
func tap() {
|
||||
ready = &Readiness{}
|
||||
state.startTime = time.Now()
|
||||
docker.SetRegistry(config.Config.Tap.Docker.Registry)
|
||||
docker.SetTag(config.Config.Tap.Docker.Tag)
|
||||
@@ -50,11 +58,11 @@ func tap() {
|
||||
|
||||
log.Info().
|
||||
Str("limit", config.Config.Tap.StorageLimit).
|
||||
Msg(fmt.Sprintf("%s will store the traffic up to a limit (per node). Oldest TCP streams will be removed once the limit is reached.", misc.Software))
|
||||
Msg(fmt.Sprintf("%s will store the traffic up to a limit (per node). Oldest TCP/UDP streams will be removed once the limit is reached.", misc.Software))
|
||||
|
||||
connector = connect.NewConnector(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.SrcPort), connect.DefaultRetries, connect.DefaultTimeout)
|
||||
connector = connect.NewConnector(kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port), connect.DefaultRetries, connect.DefaultTimeout)
|
||||
|
||||
kubernetesProvider, err := getKubernetesProviderForCli()
|
||||
kubernetesProvider, err := getKubernetesProviderForCli(false, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -62,18 +70,18 @@ func tap() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel() // cancel will be called when this function exits
|
||||
|
||||
state.targetNamespaces = getNamespaces(kubernetesProvider)
|
||||
state.targetNamespaces = kubernetesProvider.GetNamespaces()
|
||||
|
||||
if config.Config.IsNsRestrictedMode() {
|
||||
if len(state.targetNamespaces) != 1 || !utils.Contains(state.targetNamespaces, config.Config.SelfNamespace) {
|
||||
log.Error().Msg(fmt.Sprintf("%s can't resolve IPs in other namespaces when running in namespace restricted mode. You can use the same namespace for --%s and --%s", misc.Software, configStructs.NamespacesLabel, config.SelfNamespaceConfigName))
|
||||
if len(state.targetNamespaces) != 1 || !utils.Contains(state.targetNamespaces, config.Config.Tap.SelfNamespace) {
|
||||
log.Error().Msg(fmt.Sprintf("%s can't resolve IPs in other namespaces when running in namespace restricted mode. You can use the same namespace for --%s and --%s", misc.Software, configStructs.NamespacesLabel, configStructs.SelfNamespaceLabel))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Info().Strs("namespaces", state.targetNamespaces).Msg("Targetting pods in:")
|
||||
log.Info().Strs("namespaces", state.targetNamespaces).Msg("Targeting pods in:")
|
||||
|
||||
if err := printTargettedPodsPreview(ctx, kubernetesProvider, state.targetNamespaces); err != nil {
|
||||
if err := printTargetedPodsPreview(ctx, kubernetesProvider, state.targetNamespaces); err != nil {
|
||||
log.Error().Err(errormessage.FormatError(err)).Msg("Error listing pods!")
|
||||
}
|
||||
|
||||
@@ -82,12 +90,15 @@ func tap() {
|
||||
}
|
||||
|
||||
log.Info().Msg(fmt.Sprintf("Waiting for the creation of %s resources...", misc.Software))
|
||||
if state.selfServiceAccountExists, err = resources.CreateHubResources(ctx, kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.SelfNamespace, config.Config.Tap.Resources.Hub, config.Config.ImagePullPolicy(), config.Config.Tap.Debug); err != nil {
|
||||
if state.selfServiceAccountExists, err = resources.CreateHubResources(ctx, kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.Tap.SelfNamespace, config.Config.Tap.Resources.Hub, config.Config.ImagePullPolicy(), config.Config.ImagePullSecrets(), config.Config.Tap.Debug); err != nil {
|
||||
var statusError *k8serrors.StatusError
|
||||
if errors.As(err, &statusError) && (statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists) {
|
||||
log.Warn().Msg(fmt.Sprintf("%s is already running in this namespace, change the `selfnamespace` configuration or run `%s clean` to remove the currently running %s instance", misc.Software, misc.Program, misc.Software))
|
||||
log.Info().Msg(fmt.Sprintf("%s is already running in this namespace, change the `selfnamespace` configuration or run `%s clean` to remove the currently running %s instance.", misc.Software, misc.Program, misc.Software))
|
||||
postHubStarted(ctx, kubernetesProvider, cancel, true)
|
||||
log.Info().Msg("Updated Hub about the changes in the config. Exiting.")
|
||||
printProxyCommandSuggestion()
|
||||
} else {
|
||||
defer resources.CleanUpSelfResources(ctx, cancel, kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.SelfNamespace)
|
||||
defer resources.CleanUpSelfResources(ctx, cancel, kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.Tap.SelfNamespace)
|
||||
log.Error().Err(errormessage.FormatError(err)).Msg("Error creating resources!")
|
||||
}
|
||||
|
||||
@@ -102,10 +113,17 @@ func tap() {
|
||||
|
||||
// block until exit signal or error
|
||||
utils.WaitForTermination(ctx, cancel)
|
||||
printProxyCommandSuggestion()
|
||||
}
|
||||
|
||||
func printProxyCommandSuggestion() {
|
||||
log.Warn().
|
||||
Str("command", fmt.Sprintf("%s proxy", misc.Program)).
|
||||
Msg(fmt.Sprintf(utils.Yellow, "To re-establish a proxy/port-forward, run:"))
|
||||
}
|
||||
|
||||
func finishTapExecution(kubernetesProvider *kubernetes.Provider) {
|
||||
finishSelfExecution(kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.SelfNamespace)
|
||||
finishSelfExecution(kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.Tap.SelfNamespace, true)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -113,69 +131,20 @@ This function is a bit problematic as it might be detached from the actual pods
|
||||
The alternative would be to wait for Hub to be ready and then query it for the pods it listens to, this has
|
||||
the arguably worse drawback of taking a relatively very long time before the user sees which pods are targeted, if any.
|
||||
*/
|
||||
func printTargettedPodsPreview(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespaces []string) error {
|
||||
func printTargetedPodsPreview(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespaces []string) error {
|
||||
if matchingPods, err := kubernetesProvider.ListAllRunningPodsMatchingRegex(ctx, config.Config.Tap.PodRegex(), namespaces); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if len(matchingPods) == 0 {
|
||||
printNoPodsFoundSuggestion(namespaces)
|
||||
}
|
||||
for _, targettedPod := range matchingPods {
|
||||
log.Info().Msg(fmt.Sprintf("New pod: %s", fmt.Sprintf(utils.Green, targettedPod.Name)))
|
||||
for _, targetedPod := range matchingPods {
|
||||
log.Info().Msg(fmt.Sprintf("Targeted pod: %s", fmt.Sprintf(utils.Green, targetedPod.Name)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func startWorkerSyncer(ctx context.Context, cancel context.CancelFunc, provider *kubernetes.Provider, targetNamespaces []string, startTime time.Time) error {
|
||||
workerSyncer, err := kubernetes.CreateAndStartWorkerSyncer(ctx, provider, kubernetes.WorkerSyncerConfig{
|
||||
TargetNamespaces: targetNamespaces,
|
||||
PodFilterRegex: *config.Config.Tap.PodRegex(),
|
||||
SelfNamespace: config.Config.SelfNamespace,
|
||||
WorkerResources: config.Config.Tap.Resources.Worker,
|
||||
ImagePullPolicy: config.Config.ImagePullPolicy(),
|
||||
SelfServiceAccountExists: state.selfServiceAccountExists,
|
||||
ServiceMesh: config.Config.Tap.ServiceMesh,
|
||||
Tls: config.Config.Tap.Tls,
|
||||
Debug: config.Config.Tap.Debug,
|
||||
}, startTime)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case syncerErr, ok := <-workerSyncer.ErrorOut:
|
||||
if !ok {
|
||||
log.Debug().Msg("workerSyncer err channel closed, ending listener loop")
|
||||
return
|
||||
}
|
||||
log.Error().Msg(getK8sTapManagerErrorText(syncerErr))
|
||||
cancel()
|
||||
case _, ok := <-workerSyncer.TapPodChangesOut:
|
||||
if !ok {
|
||||
log.Debug().Msg("workerSyncer pod changes channel closed, ending listener loop")
|
||||
return
|
||||
}
|
||||
go connector.PostTargettedPodsToHub(workerSyncer.CurrentlyTargettedPods)
|
||||
case pod, ok := <-workerSyncer.WorkerPodsChanges:
|
||||
if !ok {
|
||||
log.Debug().Msg("workerSyncer worker status changed channel closed, ending listener loop")
|
||||
return
|
||||
}
|
||||
go connector.PostWorkerPodToHub(pod)
|
||||
case <-ctx.Done():
|
||||
log.Debug().Msg("workerSyncer event listener loop exiting due to context done")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printNoPodsFoundSuggestion(targetNamespaces []string) {
|
||||
var suggestionStr string
|
||||
if !utils.Contains(targetNamespaces, kubernetes.K8sAllNamespaces) {
|
||||
@@ -184,23 +153,10 @@ func printNoPodsFoundSuggestion(targetNamespaces []string) {
|
||||
log.Warn().Msg(fmt.Sprintf("Did not find any currently running pods that match the regex argument, %s will automatically target matching pods if any are created later%s", misc.Software, suggestionStr))
|
||||
}
|
||||
|
||||
func getK8sTapManagerErrorText(err kubernetes.K8sTapManagerError) string {
|
||||
switch err.TapManagerReason {
|
||||
case kubernetes.TapManagerPodListError:
|
||||
return fmt.Sprintf("Failed to update currently targetted pods: %v", err.OriginalError)
|
||||
case kubernetes.TapManagerPodWatchError:
|
||||
return fmt.Sprintf("Error occured in K8s pod watch: %v", err.OriginalError)
|
||||
case kubernetes.TapManagerWorkerUpdateError:
|
||||
return fmt.Sprintf("Error updating worker: %v", err.OriginalError)
|
||||
default:
|
||||
return fmt.Sprintf("Unknown error occured in K8s tap manager: %v", err.OriginalError)
|
||||
}
|
||||
}
|
||||
|
||||
func watchHubPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
||||
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", kubernetes.HubPodName))
|
||||
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{config.Config.SelfNamespace}, podWatchHelper)
|
||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{config.Config.Tap.SelfNamespace}, podWatchHelper)
|
||||
isPodReady := false
|
||||
|
||||
timeAfter := time.After(120 * time.Second)
|
||||
@@ -214,9 +170,9 @@ func watchHubPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, c
|
||||
|
||||
switch wEvent.Type {
|
||||
case kubernetes.EventAdded:
|
||||
log.Info().Str("pod", kubernetes.HubPodName).Msg("Added pod.")
|
||||
log.Info().Str("pod", kubernetes.HubPodName).Msg("Added:")
|
||||
case kubernetes.EventDeleted:
|
||||
log.Info().Str("pod", kubernetes.HubPodName).Msg("Removed pod.")
|
||||
log.Info().Str("pod", kubernetes.HubPodName).Msg("Removed:")
|
||||
cancel()
|
||||
return
|
||||
case kubernetes.EventModified:
|
||||
@@ -235,12 +191,23 @@ func watchHubPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, c
|
||||
|
||||
if modifiedPod.Status.Phase == core.PodRunning && !isPodReady {
|
||||
isPodReady = true
|
||||
hubPodReady = true
|
||||
postHubStarted(ctx, kubernetesProvider, cancel)
|
||||
|
||||
ready.Lock()
|
||||
ready.Hub = true
|
||||
ready.Unlock()
|
||||
postHubStarted(ctx, kubernetesProvider, cancel, false)
|
||||
}
|
||||
|
||||
ready.Lock()
|
||||
proxyDone := ready.Proxy
|
||||
hubPodReady := ready.Hub
|
||||
frontPodReady := ready.Front
|
||||
ready.Unlock()
|
||||
|
||||
if !proxyDone && hubPodReady && frontPodReady {
|
||||
proxyDone = true
|
||||
ready.Lock()
|
||||
ready.Proxy = true
|
||||
ready.Unlock()
|
||||
postFrontStarted(ctx, kubernetesProvider, cancel)
|
||||
}
|
||||
case kubernetes.EventBookmark:
|
||||
@@ -256,7 +223,7 @@ func watchHubPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, c
|
||||
|
||||
log.Error().
|
||||
Str("pod", kubernetes.HubPodName).
|
||||
Str("namespace", config.Config.SelfNamespace).
|
||||
Str("namespace", config.Config.Tap.SelfNamespace).
|
||||
Err(err).
|
||||
Msg("Failed creating pod.")
|
||||
cancel()
|
||||
@@ -280,7 +247,7 @@ func watchHubPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, c
|
||||
func watchFrontPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
||||
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", kubernetes.FrontPodName))
|
||||
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{config.Config.SelfNamespace}, podWatchHelper)
|
||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{config.Config.Tap.SelfNamespace}, podWatchHelper)
|
||||
isPodReady := false
|
||||
|
||||
timeAfter := time.After(120 * time.Second)
|
||||
@@ -294,9 +261,9 @@ func watchFrontPod(ctx context.Context, kubernetesProvider *kubernetes.Provider,
|
||||
|
||||
switch wEvent.Type {
|
||||
case kubernetes.EventAdded:
|
||||
log.Info().Str("pod", kubernetes.FrontPodName).Msg("Added pod.")
|
||||
log.Info().Str("pod", kubernetes.FrontPodName).Msg("Added:")
|
||||
case kubernetes.EventDeleted:
|
||||
log.Info().Str("pod", kubernetes.FrontPodName).Msg("Removed pod.")
|
||||
log.Info().Str("pod", kubernetes.FrontPodName).Msg("Removed:")
|
||||
cancel()
|
||||
return
|
||||
case kubernetes.EventModified:
|
||||
@@ -315,11 +282,21 @@ func watchFrontPod(ctx context.Context, kubernetesProvider *kubernetes.Provider,
|
||||
|
||||
if modifiedPod.Status.Phase == core.PodRunning && !isPodReady {
|
||||
isPodReady = true
|
||||
frontPodReady = true
|
||||
ready.Lock()
|
||||
ready.Front = true
|
||||
ready.Unlock()
|
||||
}
|
||||
|
||||
ready.Lock()
|
||||
proxyDone := ready.Proxy
|
||||
hubPodReady := ready.Hub
|
||||
frontPodReady := ready.Front
|
||||
ready.Unlock()
|
||||
|
||||
if !proxyDone && hubPodReady && frontPodReady {
|
||||
proxyDone = true
|
||||
ready.Lock()
|
||||
ready.Proxy = true
|
||||
ready.Unlock()
|
||||
postFrontStarted(ctx, kubernetesProvider, cancel)
|
||||
}
|
||||
case kubernetes.EventBookmark:
|
||||
@@ -335,7 +312,7 @@ func watchFrontPod(ctx context.Context, kubernetesProvider *kubernetes.Provider,
|
||||
|
||||
log.Error().
|
||||
Str("pod", kubernetes.FrontPodName).
|
||||
Str("namespace", config.Config.SelfNamespace).
|
||||
Str("namespace", config.Config.Tap.SelfNamespace).
|
||||
Err(err).
|
||||
Msg("Failed creating pod.")
|
||||
cancel()
|
||||
@@ -359,7 +336,7 @@ func watchFrontPod(ctx context.Context, kubernetesProvider *kubernetes.Provider,
|
||||
func watchHubEvents(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
||||
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s", kubernetes.HubPodName))
|
||||
eventWatchHelper := kubernetes.NewEventWatchHelper(kubernetesProvider, podExactRegex, "pod")
|
||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, eventWatchHelper, []string{config.Config.SelfNamespace}, eventWatchHelper)
|
||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, eventWatchHelper, []string{config.Config.Tap.SelfNamespace}, eventWatchHelper)
|
||||
for {
|
||||
select {
|
||||
case wEvent, ok := <-eventChan:
|
||||
@@ -425,39 +402,89 @@ func watchHubEvents(ctx context.Context, kubernetesProvider *kubernetes.Provider
|
||||
}
|
||||
}
|
||||
|
||||
func postHubStarted(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
||||
startProxyReportErrorIfAny(kubernetesProvider, ctx, cancel, kubernetes.HubServiceName, configStructs.ProxyFrontPortLabel, config.Config.Tap.Proxy.Hub.SrcPort, config.Config.Tap.Proxy.Hub.DstPort, "/echo")
|
||||
func postHubStarted(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc, update bool) {
|
||||
startProxyReportErrorIfAny(
|
||||
kubernetesProvider,
|
||||
ctx,
|
||||
kubernetes.HubServiceName,
|
||||
kubernetes.HubPodName,
|
||||
configStructs.ProxyHubPortLabel,
|
||||
config.Config.Tap.Proxy.Hub.Port,
|
||||
configStructs.ContainerPort,
|
||||
"/echo",
|
||||
)
|
||||
|
||||
if err := startWorkerSyncer(ctx, cancel, kubernetesProvider, state.targetNamespaces, state.startTime); err != nil {
|
||||
log.Error().Err(errormessage.FormatError(err)).Msg("Error starting worker syncer")
|
||||
cancel()
|
||||
if !update {
|
||||
// Create workers
|
||||
err := kubernetes.CreateWorkers(
|
||||
kubernetesProvider,
|
||||
state.selfServiceAccountExists,
|
||||
ctx,
|
||||
config.Config.Tap.SelfNamespace,
|
||||
config.Config.Tap.Resources.Worker,
|
||||
config.Config.ImagePullPolicy(),
|
||||
config.Config.ImagePullSecrets(),
|
||||
config.Config.Tap.ServiceMesh,
|
||||
config.Config.Tap.Tls,
|
||||
config.Config.Tap.Debug,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
}
|
||||
} else {
|
||||
// Pod regex
|
||||
connector.PostRegexToHub(config.Config.Tap.PodRegexStr, state.targetNamespaces)
|
||||
|
||||
// License
|
||||
if config.Config.License != "" {
|
||||
connector.PostLicense(config.Config.License)
|
||||
}
|
||||
|
||||
// Scripting
|
||||
connector.PostEnv(config.Config.Scripting.Env)
|
||||
|
||||
scripts, err := config.Config.Scripting.GetScripts()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
}
|
||||
|
||||
for _, script := range scripts {
|
||||
_, err = connector.PostScript(script)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
connector.PostScriptDone()
|
||||
}
|
||||
|
||||
url := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.SrcPort)
|
||||
log.Info().Str("url", url).Msg(fmt.Sprintf(utils.Green, "Hub is available at:"))
|
||||
if !update {
|
||||
// Hub proxy URL
|
||||
url := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Hub.Port)
|
||||
log.Info().Str("url", url).Msg(fmt.Sprintf(utils.Green, "Hub is available at:"))
|
||||
}
|
||||
|
||||
if config.Config.Scripting.Source != "" && config.Config.Scripting.WatchScripts {
|
||||
watchScripts(false)
|
||||
}
|
||||
}
|
||||
|
||||
func postFrontStarted(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
||||
startProxyReportErrorIfAny(kubernetesProvider, ctx, cancel, kubernetes.FrontServiceName, configStructs.ProxyHubPortLabel, config.Config.Tap.Proxy.Front.SrcPort, config.Config.Tap.Proxy.Front.DstPort, "")
|
||||
startProxyReportErrorIfAny(
|
||||
kubernetesProvider,
|
||||
ctx,
|
||||
kubernetes.FrontServiceName,
|
||||
kubernetes.FrontPodName,
|
||||
configStructs.ProxyFrontPortLabel,
|
||||
config.Config.Tap.Proxy.Front.Port,
|
||||
configStructs.ContainerPort,
|
||||
"",
|
||||
)
|
||||
|
||||
url := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Front.SrcPort)
|
||||
url := kubernetes.GetLocalhostOnPort(config.Config.Tap.Proxy.Front.Port)
|
||||
log.Info().Str("url", url).Msg(fmt.Sprintf(utils.Green, fmt.Sprintf("%s is available at:", misc.Software)))
|
||||
|
||||
if !config.Config.HeadlessMode {
|
||||
utils.OpenBrowser(url)
|
||||
}
|
||||
}
|
||||
|
||||
func getNamespaces(kubernetesProvider *kubernetes.Provider) []string {
|
||||
if config.Config.Tap.AllNamespaces {
|
||||
return []string{kubernetes.K8sAllNamespaces}
|
||||
} else if len(config.Config.Tap.Namespaces) > 0 {
|
||||
return utils.Unique(config.Config.Tap.Namespaces)
|
||||
} else {
|
||||
currentNamespace, err := kubernetesProvider.CurrentNamespace()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Error getting current namespace!")
|
||||
}
|
||||
return []string{currentNamespace}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
"github.com/kubeshark/kubeshark/misc/version"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/rs/zerolog"
|
||||
@@ -28,9 +31,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
Config ConfigStruct
|
||||
DebugMode bool
|
||||
cmdName string
|
||||
Config ConfigStruct
|
||||
DebugMode bool
|
||||
cmdName string
|
||||
ConfigFilePath string
|
||||
)
|
||||
|
||||
func InitConfig(cmd *cobra.Command) error {
|
||||
@@ -48,21 +52,37 @@ func InitConfig(cmd *cobra.Command) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
go version.CheckNewerVersion()
|
||||
if !utils.Contains([]string{
|
||||
"console",
|
||||
"pro",
|
||||
"manifests",
|
||||
}, cmd.Use) {
|
||||
go version.CheckNewerVersion()
|
||||
}
|
||||
|
||||
Config = CreateDefaultConfig()
|
||||
cmdName = cmd.Name()
|
||||
if utils.Contains([]string{
|
||||
"clean",
|
||||
"console",
|
||||
"pro",
|
||||
"proxy",
|
||||
"scripts",
|
||||
}, cmdName) {
|
||||
cmdName = "tap"
|
||||
}
|
||||
|
||||
if err := defaults.Set(&Config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configFilePathFlag := cmd.Flags().Lookup(ConfigFilePathCommandName)
|
||||
configFilePath := configFilePathFlag.Value.String()
|
||||
if err := loadConfigFile(configFilePath, &Config); err != nil {
|
||||
if configFilePathFlag.Changed || !os.IsNotExist(err) {
|
||||
ConfigFilePath = path.Join(misc.GetDotFolderPath(), "config.yaml")
|
||||
if err := loadConfigFile(&Config, utils.Contains([]string{
|
||||
"manifests",
|
||||
}, cmd.Use)); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return fmt.Errorf("invalid config, %w\n"+
|
||||
"you can regenerate the file by removing it (%v) and using `kubeshark config -r`", err, configFilePath)
|
||||
"you can regenerate the file by removing it (%v) and using `kubeshark config -r`", err, ConfigFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,29 +112,50 @@ func WriteConfig(config *ConfigStruct) error {
|
||||
}
|
||||
|
||||
data := []byte(template)
|
||||
if err := os.WriteFile(Config.ConfigFilePath, data, 0644); err != nil {
|
||||
|
||||
if _, err := os.Stat(ConfigFilePath); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(filepath.Dir(ConfigFilePath), 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed creating directories, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.WriteFile(ConfigFilePath, data, 0644); err != nil {
|
||||
return fmt.Errorf("failed writing config, err: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadConfigFile(configFilePath string, config *ConfigStruct) error {
|
||||
reader, openErr := os.Open(configFilePath)
|
||||
if openErr != nil {
|
||||
return openErr
|
||||
func loadConfigFile(config *ConfigStruct, silent bool) error {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf, readErr := io.ReadAll(reader)
|
||||
if readErr != nil {
|
||||
return readErr
|
||||
cwdConfig := filepath.Join(cwd, fmt.Sprintf("%s.yaml", misc.Program))
|
||||
reader, err := os.Open(cwdConfig)
|
||||
if err != nil {
|
||||
reader, err = os.Open(ConfigFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
ConfigFilePath = cwdConfig
|
||||
}
|
||||
|
||||
buf, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(buf, config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Str("path", configFilePath).Msg("Found config file!")
|
||||
if !silent {
|
||||
log.Info().Str("path", ConfigFilePath).Msg("Found config file!")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -123,9 +164,7 @@ func initFlag(f *pflag.Flag) {
|
||||
configElemValue := reflect.ValueOf(&Config).Elem()
|
||||
|
||||
var flagPath []string
|
||||
if !utils.Contains([]string{ConfigFilePathCommandName}, f.Name) {
|
||||
flagPath = append(flagPath, cmdName)
|
||||
}
|
||||
flagPath = append(flagPath, cmdName)
|
||||
|
||||
flagPath = append(flagPath, strings.Split(f.Name, "-")...)
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
@@ -12,9 +11,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
SelfNamespaceConfigName = "selfnamespace"
|
||||
ConfigFilePathCommandName = "configpath"
|
||||
KubeConfigPathConfigName = "kube-configpath"
|
||||
KubeConfigPathConfigName = "kube-configpath"
|
||||
)
|
||||
|
||||
func CreateDefaultConfig() ConfigStruct {
|
||||
@@ -26,27 +23,37 @@ type KubeConfig struct {
|
||||
Context string `yaml:"context"`
|
||||
}
|
||||
|
||||
type ConfigStruct struct {
|
||||
Tap configStructs.TapConfig `yaml:"tap"`
|
||||
Logs configStructs.LogsConfig `yaml:"logs"`
|
||||
Config configStructs.ConfigConfig `yaml:"config,omitempty"`
|
||||
Kube KubeConfig `yaml:"kube"`
|
||||
SelfNamespace string `yaml:"selfnamespace" default:"kubeshark"`
|
||||
DumpLogs bool `yaml:"dumplogs" default:"false"`
|
||||
ConfigFilePath string `yaml:"configpath,omitempty" readonly:""`
|
||||
HeadlessMode bool `yaml:"headless" default:"false"`
|
||||
type ManifestsConfig struct {
|
||||
Dump bool `yaml:"dump"`
|
||||
}
|
||||
|
||||
func (config *ConfigStruct) SetDefaults() {
|
||||
config.ConfigFilePath = path.Join(misc.GetDotFolderPath(), "config.yaml")
|
||||
type ConfigStruct struct {
|
||||
Tap configStructs.TapConfig `yaml:"tap"`
|
||||
Logs configStructs.LogsConfig `yaml:"logs"`
|
||||
Config configStructs.ConfigConfig `yaml:"config,omitempty"`
|
||||
Kube KubeConfig `yaml:"kube"`
|
||||
DumpLogs bool `yaml:"dumplogs" default:"false"`
|
||||
HeadlessMode bool `yaml:"headless" default:"false"`
|
||||
License string `yaml:"license" default:""`
|
||||
Scripting configStructs.ScriptingConfig `yaml:"scripting"`
|
||||
Manifests ManifestsConfig `yaml:"manifests,omitempty"`
|
||||
}
|
||||
|
||||
func (config *ConfigStruct) ImagePullPolicy() v1.PullPolicy {
|
||||
return v1.PullPolicy(config.Tap.Docker.ImagePullPolicy)
|
||||
}
|
||||
|
||||
func (config *ConfigStruct) ImagePullSecrets() []v1.LocalObjectReference {
|
||||
var ref []v1.LocalObjectReference
|
||||
for _, name := range config.Tap.Docker.ImagePullSecrets {
|
||||
ref = append(ref, v1.LocalObjectReference{Name: name})
|
||||
}
|
||||
|
||||
return ref
|
||||
}
|
||||
|
||||
func (config *ConfigStruct) IsNsRestrictedMode() bool {
|
||||
return config.SelfNamespace != misc.Program // Notice "kubeshark" string must match the default SelfNamespace
|
||||
return config.Tap.SelfNamespace != misc.Program // Notice "kubeshark" string must match the default SelfNamespace
|
||||
}
|
||||
|
||||
func (config *ConfigStruct) KubeConfigPath() string {
|
||||
|
||||
46
config/configStructs/scriptingConfig.go
Normal file
46
config/configStructs/scriptingConfig.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package configStructs
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type ScriptingConfig struct {
|
||||
Env map[string]interface{} `yaml:"env"`
|
||||
Source string `yaml:"source" default:""`
|
||||
WatchScripts bool `yaml:"watchScripts" default:"true"`
|
||||
}
|
||||
|
||||
func (config *ScriptingConfig) GetScripts() (scripts []*misc.Script, err error) {
|
||||
if config.Source == "" {
|
||||
return
|
||||
}
|
||||
|
||||
var files []fs.FileInfo
|
||||
files, err = ioutil.ReadDir(config.Source)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
var script *misc.Script
|
||||
path := filepath.Join(config.Source, f.Name())
|
||||
script, err = misc.ReadScriptFile(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
scripts = append(scripts, script)
|
||||
|
||||
log.Debug().Str("path", path).Msg("Found script:")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -4,40 +4,59 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
DockerRegistryLabel = "docker-registry"
|
||||
DockerTagLabel = "docker-tag"
|
||||
ProxyFrontPortLabel = "proxy-front-port"
|
||||
ProxyHubPortLabel = "proxy-hub-port"
|
||||
ProxyHostLabel = "proxy-host"
|
||||
NamespacesLabel = "namespaces"
|
||||
AllNamespacesLabel = "allnamespaces"
|
||||
StorageLimitLabel = "storagelimit"
|
||||
DryRunLabel = "dryrun"
|
||||
PcapLabel = "pcap"
|
||||
ServiceMeshLabel = "servicemesh"
|
||||
TlsLabel = "tls"
|
||||
DebugLabel = "debug"
|
||||
DockerRegistryLabel = "docker-registry"
|
||||
DockerTagLabel = "docker-tag"
|
||||
DockerImagePullPolicy = "docker-imagepullpolicy"
|
||||
DockerImagePullSecrets = "docker-imagepullsecrets"
|
||||
ProxyFrontPortLabel = "proxy-front-port"
|
||||
ProxyHubPortLabel = "proxy-hub-port"
|
||||
ProxyHostLabel = "proxy-host"
|
||||
NamespacesLabel = "namespaces"
|
||||
SelfNamespaceLabel = "selfnamespace"
|
||||
PersistentStorageLabel = "persistentstorage"
|
||||
StorageLimitLabel = "storagelimit"
|
||||
StorageClassLabel = "storageclass"
|
||||
DryRunLabel = "dryrun"
|
||||
PcapLabel = "pcap"
|
||||
ServiceMeshLabel = "servicemesh"
|
||||
TlsLabel = "tls"
|
||||
IgnoreTaintedLabel = "ignoreTainted"
|
||||
DebugLabel = "debug"
|
||||
ContainerPort = 80
|
||||
ContainerPortStr = "80"
|
||||
)
|
||||
|
||||
type ResourceLimits struct {
|
||||
CPU string `yaml:"cpu" default:"750m"`
|
||||
Memory string `yaml:"memory" default:"1Gi"`
|
||||
}
|
||||
|
||||
type ResourceRequests struct {
|
||||
CPU string `yaml:"cpu" default:"50m"`
|
||||
Memory string `yaml:"memory" default:"50Mi"`
|
||||
}
|
||||
|
||||
type ResourceRequirements struct {
|
||||
Limits ResourceLimits `json:"limits"`
|
||||
Requests ResourceRequests `json:"requests"`
|
||||
}
|
||||
|
||||
type WorkerConfig struct {
|
||||
SrcPort uint16 `yaml:"src-port" default:"8897"`
|
||||
DstPort uint16 `yaml:"dst-port" default:"8897"`
|
||||
SrvPort uint16 `yaml:"srvport" default:"8897"`
|
||||
}
|
||||
|
||||
type HubConfig struct {
|
||||
SrcPort uint16 `yaml:"src-port" default:"8898"`
|
||||
DstPort uint16 `yaml:"dst-port" default:"8898"`
|
||||
Port uint16 `yaml:"port" default:"8898"`
|
||||
SrvPort uint16 `yaml:"srvport" default:"8898"`
|
||||
}
|
||||
|
||||
type FrontConfig struct {
|
||||
SrcPort uint16 `yaml:"src-port" default:"8899"`
|
||||
DstPort uint16 `yaml:"dst-port" default:"80"`
|
||||
Port uint16 `yaml:"port" default:"8899"`
|
||||
SrvPort uint16 `yaml:"srvport" default:"8899"`
|
||||
}
|
||||
|
||||
type ProxyConfig struct {
|
||||
@@ -48,30 +67,36 @@ type ProxyConfig struct {
|
||||
}
|
||||
|
||||
type DockerConfig struct {
|
||||
Registry string `yaml:"registry" default:"docker.io/kubeshark"`
|
||||
Tag string `yaml:"tag" default:"latest"`
|
||||
ImagePullPolicy string `yaml:"imagepullpolicy" default:"Always"`
|
||||
Registry string `yaml:"registry" default:"docker.io/kubeshark"`
|
||||
Tag string `yaml:"tag" default:"latest"`
|
||||
ImagePullPolicy string `yaml:"imagepullpolicy" default:"Always"`
|
||||
ImagePullSecrets []string `yaml:"imagepullsecrets"`
|
||||
}
|
||||
|
||||
type ResourcesConfig struct {
|
||||
Worker kubernetes.Resources `yaml:"worker"`
|
||||
Hub kubernetes.Resources `yaml:"hub"`
|
||||
Worker ResourceRequirements `yaml:"worker"`
|
||||
Hub ResourceRequirements `yaml:"hub"`
|
||||
}
|
||||
|
||||
type TapConfig struct {
|
||||
Docker DockerConfig `yaml:"docker"`
|
||||
Proxy ProxyConfig `yaml:"proxy"`
|
||||
PodRegexStr string `yaml:"regex" default:".*"`
|
||||
Namespaces []string `yaml:"namespaces"`
|
||||
AllNamespaces bool `yaml:"allnamespaces" default:"false"`
|
||||
StorageLimit string `yaml:"storagelimit" default:"200MB"`
|
||||
DryRun bool `yaml:"dryrun" default:"false"`
|
||||
Pcap string `yaml:"pcap" default:""`
|
||||
Resources ResourcesConfig `yaml:"resources"`
|
||||
ServiceMesh bool `yaml:"servicemesh" default:"true"`
|
||||
Tls bool `yaml:"tls" default:"true"`
|
||||
PacketCapture string `yaml:"packetcapture" default:"libpcap"`
|
||||
Debug bool `yaml:"debug" default:"false"`
|
||||
Docker DockerConfig `yaml:"docker"`
|
||||
Proxy ProxyConfig `yaml:"proxy"`
|
||||
PodRegexStr string `yaml:"regex" default:".*"`
|
||||
Namespaces []string `yaml:"namespaces"`
|
||||
SelfNamespace string `yaml:"selfnamespace" default:"kubeshark"`
|
||||
PersistentStorage bool `yaml:"persistentstorage" default:"false"`
|
||||
StorageLimit string `yaml:"storagelimit" default:"200Mi"`
|
||||
StorageClass string `yaml:"storageclass" default:"standard"`
|
||||
DryRun bool `yaml:"dryrun" default:"false"`
|
||||
Pcap string `yaml:"pcap" default:""`
|
||||
Resources ResourcesConfig `yaml:"resources"`
|
||||
ServiceMesh bool `yaml:"servicemesh" default:"true"`
|
||||
Tls bool `yaml:"tls" default:"true"`
|
||||
PacketCapture string `yaml:"packetcapture" default:"libpcap"`
|
||||
IgnoreTainted bool `yaml:"ignoreTainted" default:"false"`
|
||||
ResourceLabels map[string]string `yaml:"resourceLabels" default:"{}"`
|
||||
NodeSelectorTerms []v1.NodeSelectorTerm `yaml:"nodeSelectorTerms" default:"[]"`
|
||||
Debug bool `yaml:"debug" default:"false"`
|
||||
}
|
||||
|
||||
func (config *TapConfig) PodRegex() *regexp.Regexp {
|
||||
@@ -79,24 +104,11 @@ func (config *TapConfig) PodRegex() *regexp.Regexp {
|
||||
return podRegex
|
||||
}
|
||||
|
||||
func (config *TapConfig) StorageLimitBytes() int64 {
|
||||
storageLimitBytes, err := utils.HumanReadableToBytes(config.StorageLimit)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Send()
|
||||
}
|
||||
return storageLimitBytes
|
||||
}
|
||||
|
||||
func (config *TapConfig) Validate() error {
|
||||
_, compileErr := regexp.Compile(config.PodRegexStr)
|
||||
if compileErr != nil {
|
||||
return fmt.Errorf("%s is not a valid regex %s", config.PodRegexStr, compileErr)
|
||||
}
|
||||
|
||||
_, parseHumanDataSizeErr := utils.HumanReadableToBytes(config.StorageLimit)
|
||||
if parseHumanDataSizeErr != nil {
|
||||
return fmt.Errorf("Could not parse --%s value %s", StorageLimitLabel, config.StorageLimit)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package docker
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
hub = "hub"
|
||||
@@ -9,7 +12,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
registry = "docker.io/kubeshark"
|
||||
registry = "docker.io/kubeshark/"
|
||||
tag = "latest"
|
||||
)
|
||||
|
||||
@@ -18,7 +21,11 @@ func GetRegistry() string {
|
||||
}
|
||||
|
||||
func SetRegistry(value string) {
|
||||
registry = value
|
||||
if strings.HasPrefix(value, "docker.io/kubeshark") {
|
||||
registry = "docker.io/kubeshark/"
|
||||
} else {
|
||||
registry = value
|
||||
}
|
||||
}
|
||||
|
||||
func GetTag() string {
|
||||
@@ -30,7 +37,7 @@ func SetTag(value string) {
|
||||
}
|
||||
|
||||
func getImage(image string) string {
|
||||
return fmt.Sprintf("%s/%s:%s", registry, image, tag)
|
||||
return fmt.Sprintf("%s%s:%s", registry, image, tag)
|
||||
}
|
||||
|
||||
func GetHubImage() string {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
regexpsyntax "regexp/syntax"
|
||||
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -18,12 +19,12 @@ func FormatError(err error) error {
|
||||
if k8serrors.IsForbidden(err) {
|
||||
errorNew = fmt.Errorf("insufficient permissions: %w. "+
|
||||
"supply the required permission or control %s's access to namespaces by setting %s "+
|
||||
"in the config file or setting the targetted namespace with --%s %s=<NAMEPSACE>",
|
||||
"in the config file or setting the targeted namespace with --%s %s=<NAMEPSACE>",
|
||||
err,
|
||||
misc.Software,
|
||||
config.SelfNamespaceConfigName,
|
||||
configStructs.SelfNamespaceLabel,
|
||||
config.SetCommandName,
|
||||
config.SelfNamespaceConfigName)
|
||||
configStructs.SelfNamespaceLabel)
|
||||
} else if syntaxError, isSyntaxError := asRegexSyntaxError(err); isSyntaxError {
|
||||
errorNew = fmt.Errorf("regex %s is invalid: %w", syntaxError.Expr, err)
|
||||
} else {
|
||||
|
||||
30
go.mod
30
go.mod
@@ -4,11 +4,15 @@ go 1.17
|
||||
|
||||
require (
|
||||
github.com/creasty/defaults v1.5.2
|
||||
github.com/docker/docker v20.10.22+incompatible
|
||||
github.com/docker/docker v20.10.24+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/gin-gonic/gin v1.7.7
|
||||
github.com/google/go-github/v37 v37.0.0
|
||||
github.com/kubeshark/base v0.5.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/ohler55/ojg v1.14.5
|
||||
github.com/otiai10/copy v1.10.0
|
||||
github.com/robertkrimen/otto v0.2.1
|
||||
github.com/rs/zerolog v1.28.0
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
@@ -34,15 +38,20 @@ require (
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/fvbommel/sortorder v1.0.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/go-playground/locales v0.13.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.17.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
@@ -58,6 +67,7 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/leodido/go-urn v1.2.0 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
@@ -78,20 +88,22 @@ require (
|
||||
github.com/russross/blackfriday v1.6.0 // indirect
|
||||
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||
github.com/stretchr/testify v1.8.1 // indirect
|
||||
github.com/ugorji/go/codec v1.1.7 // indirect
|
||||
github.com/xlab/treeprint v1.1.0 // indirect
|
||||
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab // indirect
|
||||
golang.org/x/crypto v0.1.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.2.0 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
golang.org/x/term v0.2.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/cli-runtime v0.23.3 // indirect
|
||||
k8s.io/component-base v0.23.3 // indirect
|
||||
|
||||
71
go.sum
71
go.sum
@@ -27,6 +27,7 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
|
||||
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
@@ -113,8 +114,10 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8=
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
@@ -149,10 +152,11 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.22+incompatible h1:6jX4yB+NtcbldT90k7vBSaWJDB3i+zkVJT9BEK8kQkk=
|
||||
github.com/docker/docker v20.10.22+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/distribution v2.8.0+incompatible h1:l9EaZDICImO1ngI+uTifW+ZYvvz7fKISBAKpg+MbWbY=
|
||||
github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE=
|
||||
github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
@@ -196,6 +200,10 @@ github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM4
|
||||
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
@@ -225,6 +233,14 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@@ -331,6 +347,7 @@ github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97Dwqy
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||
@@ -414,8 +431,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kubeshark/base v0.5.0 h1:ZQ/wNIdmLeDwy143korRZyPorcqBgf1y/tQIiIenAL0=
|
||||
github.com/kubeshark/base v0.5.0/go.mod h1:/ZzBY+5KLaC7J6QUVXtZ0HZALhMcEDrU6Waux5/bHQc=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||
@@ -488,6 +505,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/ohler55/ojg v1.14.5 h1:xCX2oyh/ZaoesbLH6fwVHStSJpk4o4eJs8ttXutzdg0=
|
||||
github.com/ohler55/ojg v1.14.5/go.mod h1:7Ghirupn8NC8hSSDpI0gcjorPxj+vSVIONDWfliHR1k=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@@ -503,6 +522,10 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
|
||||
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/otiai10/copy v1.10.0 h1:znyI7l134wNg/wDktoVQPxPkgvhDfGCYUasey+h0rDQ=
|
||||
github.com/otiai10/copy v1.10.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww=
|
||||
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
||||
github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
@@ -543,6 +566,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0=
|
||||
github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
@@ -610,6 +635,10 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
||||
@@ -621,6 +650,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
@@ -670,8 +700,8 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab h1:lnZ4LoV0UMdibeCUfIB2a4uFwRu491WX/VB2reB8xNc=
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -762,8 +792,10 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -794,6 +826,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -877,13 +910,19 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -893,8 +932,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1134,7 +1174,10 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
|
||||
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
|
||||
25
helm-chart/Chart.yaml
Normal file
25
helm-chart/Chart.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
apiVersion: v2
|
||||
appVersion: "40.1"
|
||||
description: The API Traffic Analyzer for Kubernetes
|
||||
home: https://kubeshark.co
|
||||
keywords:
|
||||
- kubeshark
|
||||
- packet capture
|
||||
- traffic capture
|
||||
- traffic analyzer
|
||||
- network sniffer
|
||||
- observability
|
||||
- devops
|
||||
- microservice
|
||||
- forensics
|
||||
- api
|
||||
kubeVersion: '>= 1.16.0-0'
|
||||
maintainers:
|
||||
- email: info@kubeshark.co
|
||||
name: Kubeshark
|
||||
url: https://kubeshark.co
|
||||
name: kubeshark
|
||||
sources:
|
||||
- https://github.com/kubeshark/kubeshark/tree/master/helm-chart
|
||||
type: application
|
||||
version: "40.1"
|
||||
191
helm-chart/LICENSE
Normal file
191
helm-chart/LICENSE
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2022 Kubeshark
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
53
helm-chart/README.md
Normal file
53
helm-chart/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Helm Chart of Kubeshark
|
||||
|
||||
## Officially
|
||||
|
||||
Add the Helm repo for Kubeshark:
|
||||
|
||||
```shell
|
||||
helm repo add kubeshark https://helm.kubeshark.co
|
||||
```
|
||||
|
||||
then install Kubeshark:
|
||||
|
||||
```shell
|
||||
helm install kubeshark kubeshark/kubeshark
|
||||
```
|
||||
|
||||
## Locally
|
||||
|
||||
Clone the repo:
|
||||
|
||||
```shell
|
||||
git clone git@github.com:kubeshark/kubeshark.git --depth 1
|
||||
cd kubeshark/helm-chart
|
||||
```
|
||||
|
||||
Render the templates
|
||||
|
||||
```shell
|
||||
helm template .
|
||||
```
|
||||
|
||||
Install Kubeshark:
|
||||
|
||||
```shell
|
||||
helm install kubeshark .
|
||||
```
|
||||
|
||||
Uninstall Kubeshark:
|
||||
|
||||
```shell
|
||||
helm uninstall kubeshark
|
||||
```
|
||||
|
||||
## Accesing
|
||||
|
||||
Do the port forwarding:
|
||||
|
||||
```shell
|
||||
kubectl port-forward -n kubeshark service/kubeshark-hub 8898:80 & \
|
||||
kubectl port-forward -n kubeshark service/kubeshark-front 8899:80
|
||||
```
|
||||
|
||||
Visit [localhost:8899](http://localhost:8899)
|
||||
12
helm-chart/templates/00-namespace.yaml
Normal file
12
helm-chart/templates/00-namespace.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: '{{ .Values.tap.selfnamespace }}'
|
||||
spec: {}
|
||||
status: {}
|
||||
12
helm-chart/templates/01-service-account.yaml
Normal file
12
helm-chart/templates/01-service-account.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-cli-version: v1
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-service-account
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
26
helm-chart/templates/02-cluster-role.yaml
Normal file
26
helm-chart/templates/02-cluster-role.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-cli-version: v1
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-cluster-role
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
- extensions
|
||||
- apps
|
||||
resources:
|
||||
- pods
|
||||
- services
|
||||
- endpoints
|
||||
- persistentvolumeclaims
|
||||
verbs:
|
||||
- list
|
||||
- get
|
||||
- watch
|
||||
20
helm-chart/templates/03-cluster-role-binding.yaml
Normal file
20
helm-chart/templates/03-cluster-role-binding.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-cli-version: v1
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-cluster-role-binding
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: kubeshark-cluster-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: kubeshark-service-account
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
49
helm-chart/templates/04-hub-pod.yaml
Normal file
49
helm-chart/templates/04-hub-pod.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: kubeshark-hub
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-hub
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- '{{ .Values.tap.debug | ternary "./hub -debug" "./hub" }}'
|
||||
env:
|
||||
- name: POD_REGEX
|
||||
value: '{{ .Values.tap.regex }}'
|
||||
- name: NAMESPACES
|
||||
value: '{{ gt (len .Values.tap.namespaces) 0 | ternary (join "," .Values.tap.namespaces) "" }}'
|
||||
- name: LICENSE
|
||||
value: '{{ .Values.license }}'
|
||||
- name: SCRIPTING_ENV
|
||||
value: '{}'
|
||||
- name: SCRIPTING_SCRIPTS
|
||||
value: '[]'
|
||||
image: '{{ .Values.tap.docker.registry }}/hub:{{ .Values.tap.docker.tag }}'
|
||||
imagePullPolicy: '{{ .Values.tap.docker.imagepullpolicy }}'
|
||||
name: kubeshark-hub
|
||||
ports:
|
||||
- containerPort: 80
|
||||
hostPort: {{ .Values.tap.proxy.hub.srvport }}
|
||||
resources:
|
||||
limits:
|
||||
cpu: '{{ .Values.tap.resources.hub.limits.cpu }}'
|
||||
memory: '{{ .Values.tap.resources.hub.limits.memory }}'
|
||||
requests:
|
||||
cpu: '{{ .Values.tap.resources.hub.requests.cpu }}'
|
||||
memory: '{{ .Values.tap.resources.hub.requests.memory }}'
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
serviceAccountName: kubeshark-service-account
|
||||
terminationGracePeriodSeconds: 0
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
operator: Exists
|
||||
- effect: NoSchedule
|
||||
operator: Exists
|
||||
status: {}
|
||||
21
helm-chart/templates/05-hub-service.yaml
Normal file
21
helm-chart/templates/05-hub-service.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-hub
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
spec:
|
||||
ports:
|
||||
- name: kubeshark-hub
|
||||
port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: kubeshark-hub
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
50
helm-chart/templates/06-front-pod.yaml
Normal file
50
helm-chart/templates/06-front-pod.yaml
Normal file
@@ -0,0 +1,50 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: kubeshark-front
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-front
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: REACT_APP_DEFAULT_FILTER
|
||||
value: ' '
|
||||
- name: REACT_APP_HUB_HOST
|
||||
value: ' '
|
||||
- name: REACT_APP_HUB_PORT
|
||||
value: "8898"
|
||||
image: '{{ .Values.tap.docker.registry }}/front:{{ .Values.tap.docker.tag }}'
|
||||
imagePullPolicy: '{{ .Values.tap.docker.imagepullpolicy }}'
|
||||
name: kubeshark-front
|
||||
ports:
|
||||
- containerPort: 80
|
||||
hostPort: {{ .Values.tap.proxy.front.srvport }}
|
||||
readinessProbe:
|
||||
failureThreshold: 3
|
||||
periodSeconds: 1
|
||||
successThreshold: 1
|
||||
tcpSocket:
|
||||
port: 80
|
||||
timeoutSeconds: 1
|
||||
resources:
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 50Mi
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
serviceAccountName: kubeshark-service-account
|
||||
terminationGracePeriodSeconds: 0
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
operator: Exists
|
||||
- effect: NoSchedule
|
||||
operator: Exists
|
||||
status: {}
|
||||
21
helm-chart/templates/07-front-service.yaml
Normal file
21
helm-chart/templates/07-front-service.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-front
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
spec:
|
||||
ports:
|
||||
- name: kubeshark-front
|
||||
port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: kubeshark-front
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
22
helm-chart/templates/08-persistent-volume-claim.yaml
Normal file
22
helm-chart/templates/08-persistent-volume-claim.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
{{- if .Values.tap.persistentstorage }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-cli-version: v1
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-persistent-volume-claim
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: '{{ .Values.tap.storagelimit }}'
|
||||
storageClassName: '{{ .Values.tap.storageclass }}'
|
||||
status: {}
|
||||
{{- end }}
|
||||
97
helm-chart/templates/09-worker-daemon-set.yaml
Normal file
97
helm-chart/templates/09-worker-daemon-set.yaml
Normal file
@@ -0,0 +1,97 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: kubeshark-worker-daemon-set
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-worker-daemon-set
|
||||
namespace: '{{ .Values.tap.selfnamespace }}'
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kubeshark-worker-daemon-set
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: kubeshark-worker-daemon-set
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-worker-daemon-set
|
||||
namespace: kubeshark
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- '{{ .Values.tap.debug | ternary "./worker -debug" "./worker" }}'
|
||||
- -i
|
||||
- any
|
||||
- -port
|
||||
- '{{ .Values.tap.proxy.worker.srvport }}'
|
||||
- -packet-capture
|
||||
- '{{ .Values.tap.packetcapture }}'
|
||||
- -servicemesh
|
||||
- -tls
|
||||
- -procfs
|
||||
- /hostproc
|
||||
image: '{{ .Values.tap.docker.registry }}/worker:{{ .Values.tap.docker.tag }}'
|
||||
imagePullPolicy: '{{ .Values.tap.docker.imagepullpolicy }}'
|
||||
name: kubeshark-worker-daemon-set
|
||||
ports:
|
||||
- containerPort: {{ .Values.tap.proxy.worker.srvport }}
|
||||
hostPort: {{ .Values.tap.proxy.worker.srvport }}
|
||||
resources:
|
||||
limits:
|
||||
cpu: '{{ .Values.tap.resources.worker.limits.cpu }}'
|
||||
memory: '{{ .Values.tap.resources.worker.limits.memory }}'
|
||||
requests:
|
||||
cpu: '{{ .Values.tap.resources.worker.requests.cpu }}'
|
||||
memory: '{{ .Values.tap.resources.worker.requests.memory }}'
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- NET_RAW
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
- SYS_PTRACE
|
||||
- DAC_OVERRIDE
|
||||
- SYS_RESOURCE
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- mountPath: /hostproc
|
||||
name: proc
|
||||
readOnly: true
|
||||
- mountPath: /sys
|
||||
name: sys
|
||||
readOnly: true
|
||||
{{- if .Values.tap.persistentstorage }}
|
||||
- mountPath: /app/data
|
||||
name: kubeshark-persistent-volume
|
||||
{{- end }}
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
hostNetwork: true
|
||||
serviceAccountName: kubeshark-service-account
|
||||
terminationGracePeriodSeconds: 0
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
operator: Exists
|
||||
- effect: NoSchedule
|
||||
operator: Exists
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /proc
|
||||
name: proc
|
||||
- hostPath:
|
||||
path: /sys
|
||||
name: sys
|
||||
{{- if .Values.tap.persistentstorage }}
|
||||
- name: kubeshark-persistent-volume
|
||||
persistentVolumeClaim:
|
||||
claimName: kubeshark-persistent-volume-claim
|
||||
{{- end }}
|
||||
58
helm-chart/values.yaml
Normal file
58
helm-chart/values.yaml
Normal file
@@ -0,0 +1,58 @@
|
||||
tap:
|
||||
docker:
|
||||
registry: docker.io/kubeshark
|
||||
tag: latest
|
||||
imagepullpolicy: Always
|
||||
imagepullsecrets: []
|
||||
proxy:
|
||||
worker:
|
||||
srvport: 8897
|
||||
hub:
|
||||
port: 8898
|
||||
srvport: 8898
|
||||
front:
|
||||
port: 8899
|
||||
srvport: 8899
|
||||
host: 127.0.0.1
|
||||
regex: .*
|
||||
namespaces: []
|
||||
selfnamespace: kubeshark
|
||||
persistentstorage: false
|
||||
storagelimit: 200Mi
|
||||
storageclass: standard
|
||||
dryrun: false
|
||||
pcap: ""
|
||||
resources:
|
||||
worker:
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 50Mi
|
||||
hub:
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 50Mi
|
||||
servicemesh: true
|
||||
tls: true
|
||||
packetcapture: libpcap
|
||||
ignoreTainted: false
|
||||
resourceLabels: {}
|
||||
nodeSelectorTerms: []
|
||||
debug: false
|
||||
logs:
|
||||
file: ""
|
||||
kube:
|
||||
configpath: ""
|
||||
context: ""
|
||||
dumplogs: false
|
||||
headless: false
|
||||
license: ""
|
||||
scripting:
|
||||
env: {}
|
||||
source: ""
|
||||
watchScripts: true
|
||||
@@ -3,16 +3,16 @@ package connect
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
core "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
@@ -24,6 +24,7 @@ type Connector struct {
|
||||
|
||||
const DefaultRetries = 3
|
||||
const DefaultTimeout = 2 * time.Second
|
||||
const DefaultSleep = 1 * time.Second
|
||||
|
||||
func NewConnector(url string, retries int, timeout time.Duration) *Connector {
|
||||
return &Connector{
|
||||
@@ -45,7 +46,7 @@ func (connector *Connector) TestConnection(path string) error {
|
||||
break
|
||||
}
|
||||
retriesLeft -= 1
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(5 * DefaultSleep)
|
||||
}
|
||||
|
||||
if retriesLeft == 0 {
|
||||
@@ -64,7 +65,6 @@ func (connector *Connector) isReachable(path string) (bool, error) {
|
||||
}
|
||||
|
||||
func (connector *Connector) PostWorkerPodToHub(pod *v1.Pod) {
|
||||
// TODO: This request is responsible for proxy_server.go:147] Error while proxying request: context canceled log
|
||||
postWorkerUrl := fmt.Sprintf("%s/pods/worker", connector.url)
|
||||
|
||||
if podMarshalled, err := json.Marshal(pod); err != nil {
|
||||
@@ -72,68 +72,268 @@ func (connector *Connector) PostWorkerPodToHub(pod *v1.Pod) {
|
||||
} else {
|
||||
ok := false
|
||||
for !ok {
|
||||
if _, err = utils.Post(postWorkerUrl, "application/json", bytes.NewBuffer(podMarshalled), connector.client); err != nil {
|
||||
var resp *http.Response
|
||||
if resp, err = utils.Post(postWorkerUrl, "application/json", bytes.NewBuffer(podMarshalled), connector.client); err != nil || resp.StatusCode != http.StatusOK {
|
||||
if _, ok := err.(*url.Error); ok {
|
||||
break
|
||||
}
|
||||
log.Debug().Err(err).Msg("Failed sending the Worker pod to Hub:")
|
||||
log.Warn().Err(err).Msg("Failed sending the Worker pod to Hub. Retrying...")
|
||||
} else {
|
||||
ok = true
|
||||
log.Debug().Interface("worker-pod", pod).Msg("Reported worker pod to Hub:")
|
||||
connector.PostStorageLimitToHub(config.Config.Tap.StorageLimitBytes())
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(DefaultSleep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type postStorageLimit struct {
|
||||
Limit int64 `json:"limit"`
|
||||
type postRegexRequest struct {
|
||||
Regex string `json:"regex"`
|
||||
Namespaces []string `json:"namespaces"`
|
||||
}
|
||||
|
||||
func (connector *Connector) PostStorageLimitToHub(limit int64) {
|
||||
payload := &postStorageLimit{
|
||||
Limit: limit,
|
||||
func (connector *Connector) PostRegexToHub(regex string, namespaces []string) {
|
||||
postRegexUrl := fmt.Sprintf("%s/pods/regex", connector.url)
|
||||
|
||||
payload := postRegexRequest{
|
||||
Regex: regex,
|
||||
Namespaces: namespaces,
|
||||
}
|
||||
postStorageLimitUrl := fmt.Sprintf("%s/pcaps/set-storage-limit", connector.url)
|
||||
|
||||
if payloadMarshalled, err := json.Marshal(payload); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal the storage limit:")
|
||||
log.Error().Err(err).Msg("Failed to marshal the pod regex:")
|
||||
} else {
|
||||
ok := false
|
||||
for !ok {
|
||||
if _, err = utils.Post(postStorageLimitUrl, "application/json", bytes.NewBuffer(payloadMarshalled), connector.client); err != nil {
|
||||
var resp *http.Response
|
||||
if resp, err = utils.Post(postRegexUrl, "application/json", bytes.NewBuffer(payloadMarshalled), connector.client); err != nil || resp.StatusCode != http.StatusOK {
|
||||
if _, ok := err.(*url.Error); ok {
|
||||
break
|
||||
}
|
||||
log.Debug().Err(err).Msg("Failed sending the storage limit to Hub:")
|
||||
log.Warn().Err(err).Msg("Failed sending the pod regex to Hub. Retrying...")
|
||||
} else {
|
||||
ok = true
|
||||
log.Debug().Int("limit", int(limit)).Msg("Reported storage limit to Hub:")
|
||||
log.Debug().Str("regex", regex).Strs("namespaces", namespaces).Msg("Reported pod regex to Hub:")
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(DefaultSleep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (connector *Connector) PostTargettedPodsToHub(pods []core.Pod) {
|
||||
postTargettedUrl := fmt.Sprintf("%s/pods/targetted", connector.url)
|
||||
type postLicenseRequest struct {
|
||||
License string `json:"license"`
|
||||
}
|
||||
|
||||
if podsMarshalled, err := json.Marshal(pods); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal the targetted pods:")
|
||||
func (connector *Connector) PostLicense(license string) {
|
||||
postLicenseUrl := fmt.Sprintf("%s/license", connector.url)
|
||||
|
||||
payload := postLicenseRequest{
|
||||
License: license,
|
||||
}
|
||||
|
||||
if payloadMarshalled, err := json.Marshal(payload); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal the payload:")
|
||||
} else {
|
||||
ok := false
|
||||
for !ok {
|
||||
if _, err = utils.Post(postTargettedUrl, "application/json", bytes.NewBuffer(podsMarshalled), connector.client); err != nil {
|
||||
var resp *http.Response
|
||||
if resp, err = utils.Post(postLicenseUrl, "application/json", bytes.NewBuffer(payloadMarshalled), connector.client); err != nil || resp.StatusCode != http.StatusOK {
|
||||
if _, ok := err.(*url.Error); ok {
|
||||
break
|
||||
}
|
||||
log.Debug().Err(err).Msg("Failed sending the targetted pods to Hub:")
|
||||
log.Warn().Err(err).Msg("Failed sending the license to Hub. Retrying...")
|
||||
} else {
|
||||
ok = true
|
||||
log.Debug().Int("pod-count", len(pods)).Msg("Reported targetted pods to Hub:")
|
||||
log.Debug().Str("license", license).Msg("Reported license to Hub:")
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(DefaultSleep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (connector *Connector) PostLicenseSingle(license string) {
|
||||
postLicenseUrl := fmt.Sprintf("%s/license", connector.url)
|
||||
|
||||
payload := postLicenseRequest{
|
||||
License: license,
|
||||
}
|
||||
|
||||
if payloadMarshalled, err := json.Marshal(payload); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal the payload:")
|
||||
} else {
|
||||
var resp *http.Response
|
||||
if resp, err = utils.Post(postLicenseUrl, "application/json", bytes.NewBuffer(payloadMarshalled), connector.client); err != nil || resp.StatusCode != http.StatusOK {
|
||||
log.Warn().Err(err).Msg("Failed sending the license to Hub.")
|
||||
} else {
|
||||
log.Debug().Str("license", license).Msg("Reported license to Hub:")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (connector *Connector) PostEnv(env map[string]interface{}) {
|
||||
if len(env) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
postEnvUrl := fmt.Sprintf("%s/scripts/env", connector.url)
|
||||
|
||||
if envMarshalled, err := json.Marshal(env); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal the env:")
|
||||
} else {
|
||||
ok := false
|
||||
for !ok {
|
||||
var resp *http.Response
|
||||
if resp, err = utils.Post(postEnvUrl, "application/json", bytes.NewBuffer(envMarshalled), connector.client); err != nil || resp.StatusCode != http.StatusOK {
|
||||
if _, ok := err.(*url.Error); ok {
|
||||
break
|
||||
}
|
||||
log.Warn().Err(err).Msg("Failed sending the scripting environment variables to Hub. Retrying...")
|
||||
} else {
|
||||
log.Debug().Interface("env", env).Msg("Reported scripting environment variables to Hub:")
|
||||
return
|
||||
}
|
||||
time.Sleep(DefaultSleep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (connector *Connector) PostScript(script *misc.Script) (index int64, err error) {
|
||||
postScriptUrl := fmt.Sprintf("%s/scripts", connector.url)
|
||||
|
||||
var scriptMarshalled []byte
|
||||
if scriptMarshalled, err = json.Marshal(script); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal the script:")
|
||||
} else {
|
||||
ok := false
|
||||
for !ok {
|
||||
var resp *http.Response
|
||||
if resp, err = utils.Post(postScriptUrl, "application/json", bytes.NewBuffer(scriptMarshalled), connector.client); err != nil || resp.StatusCode != http.StatusOK {
|
||||
if _, ok := err.(*url.Error); ok {
|
||||
break
|
||||
}
|
||||
log.Warn().Err(err).Msg("Failed creating script Hub:")
|
||||
} else {
|
||||
|
||||
var j map[string]interface{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&j)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
val, ok := j["index"]
|
||||
if !ok {
|
||||
err = errors.New("Response does not contain `key` field!")
|
||||
return
|
||||
}
|
||||
|
||||
index = int64(val.(float64))
|
||||
|
||||
log.Debug().Int("index", int(index)).Interface("script", script).Msg("Created script on Hub:")
|
||||
return
|
||||
}
|
||||
time.Sleep(DefaultSleep)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (connector *Connector) PutScript(script *misc.Script, index int64) (err error) {
|
||||
putScriptUrl := fmt.Sprintf("%s/scripts/%d", connector.url, index)
|
||||
|
||||
var scriptMarshalled []byte
|
||||
if scriptMarshalled, err = json.Marshal(script); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal the script:")
|
||||
} else {
|
||||
ok := false
|
||||
for !ok {
|
||||
client := &http.Client{}
|
||||
|
||||
var req *http.Request
|
||||
req, err = http.NewRequest(http.MethodPut, putScriptUrl, bytes.NewBuffer(scriptMarshalled))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
var resp *http.Response
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if _, ok := err.(*url.Error); ok {
|
||||
break
|
||||
}
|
||||
log.Warn().Err(err).Msg("Failed updating script on Hub:")
|
||||
} else {
|
||||
log.Debug().Int("index", int(index)).Interface("script", script).Msg("Updated script on Hub:")
|
||||
return
|
||||
}
|
||||
time.Sleep(DefaultSleep)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (connector *Connector) DeleteScript(index int64) (err error) {
|
||||
deleteScriptUrl := fmt.Sprintf("%s/scripts/%d", connector.url, index)
|
||||
|
||||
ok := false
|
||||
for !ok {
|
||||
client := &http.Client{}
|
||||
|
||||
var req *http.Request
|
||||
req, err = http.NewRequest(http.MethodDelete, deleteScriptUrl, nil)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
var resp *http.Response
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if _, ok := err.(*url.Error); ok {
|
||||
break
|
||||
}
|
||||
log.Warn().Err(err).Msg("Failed deleting script on Hub:")
|
||||
} else {
|
||||
log.Debug().Int("index", int(index)).Msg("Deleted script on Hub:")
|
||||
return
|
||||
}
|
||||
time.Sleep(DefaultSleep)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (connector *Connector) PostScriptDone() {
|
||||
postScripDonetUrl := fmt.Sprintf("%s/scripts/done", connector.url)
|
||||
|
||||
ok := false
|
||||
var err error
|
||||
for !ok {
|
||||
var resp *http.Response
|
||||
if resp, err = utils.Post(postScripDonetUrl, "application/json", nil, connector.client); err != nil || resp.StatusCode != http.StatusOK {
|
||||
if _, ok := err.(*url.Error); ok {
|
||||
break
|
||||
}
|
||||
log.Warn().Err(err).Msg("Failed sending the POST scripts done to Hub. Retrying...")
|
||||
} else {
|
||||
log.Debug().Msg("Reported POST scripts done to Hub.")
|
||||
return
|
||||
}
|
||||
time.Sleep(DefaultSleep)
|
||||
}
|
||||
}
|
||||
|
||||
13
kubectl.sh
Executable file
13
kubectl.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Useful kubectl commands for Kubeshark development
|
||||
|
||||
# This command outputs all Kubernetes resources using YAML format and pipes it to VS Code
|
||||
if [ $1 = "view-all-resources" ] ; then
|
||||
kubectl get $(kubectl api-resources | awk '{print $1}' | tail -n +2 | tr '\n' ',' | sed s/,\$//) -o yaml | code -
|
||||
fi
|
||||
|
||||
# This command outputs all Kubernetes resources in "kubeshark" namespace using YAML format and pipes it to VS Code
|
||||
if [[ $1 = "view-kubeshark-resources" ]] ; then
|
||||
kubectl get $(kubectl api-resources | awk '{print $1}' | tail -n +2 | tr '\n' ',' | sed s/,\$//) -n kubeshark -o yaml | code -
|
||||
fi
|
||||
@@ -14,12 +14,13 @@ const (
|
||||
ServiceAccountName = SelfResourcesPrefix + "service-account"
|
||||
WorkerDaemonSetName = SelfResourcesPrefix + "worker-daemon-set"
|
||||
WorkerPodName = SelfResourcesPrefix + "worker"
|
||||
ConfigMapName = SelfResourcesPrefix + "config"
|
||||
PersistentVolumeName = SelfResourcesPrefix + "persistent-volume"
|
||||
PersistentVolumeClaimName = SelfResourcesPrefix + "persistent-volume-claim"
|
||||
PersistentVolumeHostPath = "/app/data"
|
||||
MinKubernetesServerVersion = "1.16.0"
|
||||
)
|
||||
|
||||
const (
|
||||
LabelPrefixApp = "app.kubernetes.io/"
|
||||
LabelManagedBy = LabelPrefixApp + "managed-by"
|
||||
LabelCreatedBy = LabelPrefixApp + "created-by"
|
||||
LabelManagedBy = SelfResourcesPrefix + "managed-by"
|
||||
LabelCreatedBy = SelfResourcesPrefix + "created-by"
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ import (
|
||||
const k8sProxyApiPrefix = "/"
|
||||
const selfServicePort = 80
|
||||
|
||||
func StartProxy(kubernetesProvider *Provider, proxyHost string, srcPort uint16, selfNamespace string, selfServiceName string, cancel context.CancelFunc) (*http.Server, error) {
|
||||
func StartProxy(kubernetesProvider *Provider, proxyHost string, srcPort uint16, selfNamespace string, selfServiceName string) (*http.Server, error) {
|
||||
log.Info().
|
||||
Str("namespace", selfNamespace).
|
||||
Str("service", selfServiceName).
|
||||
@@ -55,7 +55,7 @@ func StartProxy(kubernetesProvider *Provider, proxyHost string, srcPort uint16,
|
||||
go func() {
|
||||
if err := server.Serve(l); err != nil && err != http.ErrServerClosed {
|
||||
log.Error().Err(err).Msg("While creating proxy!")
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -99,7 +99,7 @@ func getRerouteHttpHandlerSelfStatic(proxyHandler http.Handler, selfNamespace st
|
||||
})
|
||||
}
|
||||
|
||||
func NewPortForward(kubernetesProvider *Provider, namespace string, podRegex *regexp.Regexp, srcPort uint16, dstPort uint16, ctx context.Context, cancel context.CancelFunc) (*portforward.PortForwarder, error) {
|
||||
func NewPortForward(kubernetesProvider *Provider, namespace string, podRegex *regexp.Regexp, srcPort uint16, dstPort uint16, ctx context.Context) (*portforward.PortForwarder, error) {
|
||||
pods, err := kubernetesProvider.ListAllRunningPodsMatchingRegex(ctx, podRegex, []string{namespace})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -132,7 +132,7 @@ func NewPortForward(kubernetesProvider *Provider, namespace string, podRegex *re
|
||||
go func() {
|
||||
if err = forwarder.ForwardPorts(); err != nil {
|
||||
log.Error().Err(err).Msg("While Kubernetes port-forwarding!")
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
type Resources struct {
|
||||
CpuLimit string `yaml:"cpu-limit" default:"750m"`
|
||||
MemoryLimit string `yaml:"memory-limit" default:"1Gi"`
|
||||
CpuRequests string `yaml:"cpu-requests" default:"50m"`
|
||||
MemoryRequests string `yaml:"memory-requests" default:"50Mi"`
|
||||
}
|
||||
147
kubernetes/types.go
Normal file
147
kubernetes/types.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
core "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
applyconfapp "k8s.io/client-go/applyconfigurations/apps/v1"
|
||||
applyconfcore "k8s.io/client-go/applyconfigurations/core/v1"
|
||||
v1 "k8s.io/client-go/applyconfigurations/core/v1"
|
||||
applyconfmeta "k8s.io/client-go/applyconfigurations/meta/v1"
|
||||
)
|
||||
|
||||
type DaemonSetPod struct {
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
Spec core.PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
|
||||
}
|
||||
|
||||
type DaemonSetSpec struct {
|
||||
Selector metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,1,opt,name=selector"`
|
||||
Template DaemonSetPod `json:"template,omitempty" protobuf:"bytes,2,opt,name=template"`
|
||||
}
|
||||
|
||||
type DaemonSet struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
Spec DaemonSetSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
|
||||
}
|
||||
|
||||
func (d *DaemonSet) GenerateApplyConfiguration(name string, namespace string, podName string, provider *Provider) *applyconfapp.DaemonSetApplyConfiguration {
|
||||
// Pod
|
||||
p := d.Spec.Template.Spec
|
||||
podSpec := applyconfcore.PodSpec()
|
||||
podSpec.WithHostNetwork(p.HostNetwork)
|
||||
podSpec.WithDNSPolicy(p.DNSPolicy)
|
||||
podSpec.WithTerminationGracePeriodSeconds(*p.TerminationGracePeriodSeconds)
|
||||
podSpec.WithServiceAccountName(p.ServiceAccountName)
|
||||
|
||||
// Containers
|
||||
for _, c := range d.Spec.Template.Spec.Containers {
|
||||
// Common
|
||||
container := applyconfcore.Container()
|
||||
container.WithName(c.Name)
|
||||
container.WithImage(c.Image)
|
||||
container.WithImagePullPolicy(c.ImagePullPolicy)
|
||||
container.WithCommand(c.Command...)
|
||||
|
||||
// Linux capabilities
|
||||
caps := applyconfcore.Capabilities().WithAdd(c.SecurityContext.Capabilities.Add...).WithDrop(c.SecurityContext.Capabilities.Drop...)
|
||||
container.WithSecurityContext(applyconfcore.SecurityContext().WithCapabilities(caps))
|
||||
|
||||
// Environment variables
|
||||
var envvars []*v1.EnvVarApplyConfiguration
|
||||
for _, e := range c.Env {
|
||||
envvars = append(envvars, applyconfcore.EnvVar().WithName(e.Name).WithValue(e.Value))
|
||||
}
|
||||
container.WithEnv(envvars...)
|
||||
|
||||
// Resource limits
|
||||
resources := applyconfcore.ResourceRequirements().WithRequests(c.Resources.Requests).WithLimits(c.Resources.Limits)
|
||||
container.WithResources(resources)
|
||||
|
||||
// Volume mounts
|
||||
for _, m := range c.VolumeMounts {
|
||||
volumeMount := applyconfcore.VolumeMount().WithName(m.Name).WithMountPath(m.MountPath).WithReadOnly(m.ReadOnly)
|
||||
container.WithVolumeMounts(volumeMount)
|
||||
}
|
||||
|
||||
podSpec.WithContainers(container)
|
||||
}
|
||||
|
||||
// Node affinity (RequiredDuringSchedulingIgnoredDuringExecution only)
|
||||
if p.Affinity != nil {
|
||||
nodeSelector := applyconfcore.NodeSelector()
|
||||
for _, term := range p.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms {
|
||||
nodeSelectorTerm := applyconfcore.NodeSelectorTerm()
|
||||
for _, selector := range term.MatchExpressions {
|
||||
nodeSelectorRequirement := applyconfcore.NodeSelectorRequirement()
|
||||
nodeSelectorRequirement.WithKey(selector.Key)
|
||||
nodeSelectorRequirement.WithOperator(selector.Operator)
|
||||
nodeSelectorRequirement.WithValues(selector.Values...)
|
||||
nodeSelectorTerm.WithMatchExpressions(nodeSelectorRequirement)
|
||||
}
|
||||
for _, selector := range term.MatchFields {
|
||||
nodeSelectorRequirement := applyconfcore.NodeSelectorRequirement()
|
||||
nodeSelectorRequirement.WithKey(selector.Key)
|
||||
nodeSelectorRequirement.WithOperator(selector.Operator)
|
||||
nodeSelectorRequirement.WithValues(selector.Values...)
|
||||
nodeSelectorTerm.WithMatchFields(nodeSelectorRequirement)
|
||||
}
|
||||
nodeSelector.WithNodeSelectorTerms(nodeSelectorTerm)
|
||||
}
|
||||
nodeAffinity := applyconfcore.NodeAffinity()
|
||||
nodeAffinity.WithRequiredDuringSchedulingIgnoredDuringExecution(nodeSelector)
|
||||
affinity := applyconfcore.Affinity()
|
||||
affinity.WithNodeAffinity(nodeAffinity)
|
||||
podSpec.WithAffinity(affinity)
|
||||
}
|
||||
|
||||
// Tolerations
|
||||
for _, t := range p.Tolerations {
|
||||
toleration := applyconfcore.Toleration()
|
||||
toleration.WithKey(t.Key)
|
||||
toleration.WithOperator(t.Operator)
|
||||
toleration.WithValue(t.Value)
|
||||
toleration.WithEffect(t.Effect)
|
||||
if t.TolerationSeconds != nil {
|
||||
toleration.WithTolerationSeconds(*t.TolerationSeconds)
|
||||
}
|
||||
podSpec.WithTolerations(toleration)
|
||||
}
|
||||
|
||||
// Volumes
|
||||
for _, v := range p.Volumes {
|
||||
volume := applyconfcore.Volume()
|
||||
if v.HostPath != nil {
|
||||
volume.WithName(v.Name).WithHostPath(applyconfcore.HostPathVolumeSource().WithPath(v.HostPath.Path))
|
||||
}
|
||||
if v.PersistentVolumeClaim != nil {
|
||||
volume.WithName(v.Name).WithPersistentVolumeClaim(applyconfcore.PersistentVolumeClaimVolumeSource().WithClaimName(v.PersistentVolumeClaim.ClaimName))
|
||||
}
|
||||
podSpec.WithVolumes(volume)
|
||||
}
|
||||
|
||||
// Image pull secrets
|
||||
if len(p.ImagePullSecrets) > 0 {
|
||||
localObjectReference := applyconfcore.LocalObjectReference()
|
||||
for _, o := range p.ImagePullSecrets {
|
||||
localObjectReference.WithName(o.Name)
|
||||
}
|
||||
podSpec.WithImagePullSecrets(localObjectReference)
|
||||
}
|
||||
|
||||
podTemplate := applyconfcore.PodTemplateSpec()
|
||||
podTemplate.WithLabels(buildWithDefaultLabels(map[string]string{
|
||||
"app": podName,
|
||||
}, provider))
|
||||
podTemplate.WithSpec(podSpec)
|
||||
|
||||
labelSelector := applyconfmeta.LabelSelector()
|
||||
labelSelector.WithMatchLabels(map[string]string{"app": podName})
|
||||
|
||||
daemonSet := applyconfapp.DaemonSet(name, namespace)
|
||||
daemonSet.
|
||||
WithLabels(buildWithDefaultLabels(map[string]string{}, provider)).
|
||||
WithSpec(applyconfapp.DaemonSetSpec().WithSelector(labelSelector).WithTemplate(podTemplate))
|
||||
|
||||
return daemonSet
|
||||
}
|
||||
@@ -1,95 +1,16 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/kubeshark/base/pkg/models"
|
||||
core "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
)
|
||||
|
||||
func GetNodeHostToTargettedPodsMap(targettedPods []core.Pod) models.NodeToPodsMap {
|
||||
nodeToTargettedPodsMap := make(models.NodeToPodsMap)
|
||||
for _, pod := range targettedPods {
|
||||
minimizedPod := getMinimizedPod(pod)
|
||||
func buildWithDefaultLabels(labels map[string]string, provider *Provider) map[string]string {
|
||||
labels[LabelManagedBy] = provider.managedBy
|
||||
labels[LabelCreatedBy] = provider.createdBy
|
||||
|
||||
existingList := nodeToTargettedPodsMap[pod.Spec.NodeName]
|
||||
if existingList == nil {
|
||||
nodeToTargettedPodsMap[pod.Spec.NodeName] = []core.Pod{minimizedPod}
|
||||
} else {
|
||||
nodeToTargettedPodsMap[pod.Spec.NodeName] = append(nodeToTargettedPodsMap[pod.Spec.NodeName], minimizedPod)
|
||||
}
|
||||
}
|
||||
return nodeToTargettedPodsMap
|
||||
}
|
||||
|
||||
func getMinimizedPod(fullPod core.Pod) core.Pod {
|
||||
return core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fullPod.Name,
|
||||
Namespace: fullPod.Namespace,
|
||||
},
|
||||
Status: core.PodStatus{
|
||||
PodIP: fullPod.Status.PodIP,
|
||||
ContainerStatuses: getMinimizedContainerStatuses(fullPod),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getMinimizedContainerStatuses(fullPod core.Pod) []core.ContainerStatus {
|
||||
result := make([]core.ContainerStatus, len(fullPod.Status.ContainerStatuses))
|
||||
|
||||
for i, container := range fullPod.Status.ContainerStatuses {
|
||||
result[i] = core.ContainerStatus{
|
||||
ContainerID: container.ContainerID,
|
||||
}
|
||||
for k, v := range config.Config.Tap.ResourceLabels {
|
||||
labels[k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func excludeSelfPods(pods []core.Pod) []core.Pod {
|
||||
selfPrefixRegex := regexp.MustCompile("^" + SelfResourcesPrefix)
|
||||
|
||||
nonSelfPods := make([]core.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if !selfPrefixRegex.MatchString(pod.Name) {
|
||||
nonSelfPods = append(nonSelfPods, pod)
|
||||
}
|
||||
}
|
||||
|
||||
return nonSelfPods
|
||||
}
|
||||
|
||||
func getPodArrayDiff(oldPods []core.Pod, newPods []core.Pod) (added []core.Pod, removed []core.Pod) {
|
||||
added = getMissingPods(newPods, oldPods)
|
||||
removed = getMissingPods(oldPods, newPods)
|
||||
|
||||
return added, removed
|
||||
}
|
||||
|
||||
//returns pods present in pods1 array and missing in pods2 array
|
||||
func getMissingPods(pods1 []core.Pod, pods2 []core.Pod) []core.Pod {
|
||||
missingPods := make([]core.Pod, 0)
|
||||
for _, pod1 := range pods1 {
|
||||
var found = false
|
||||
for _, pod2 := range pods2 {
|
||||
if pod1.UID == pod2.UID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
missingPods = append(missingPods, pod1)
|
||||
}
|
||||
}
|
||||
return missingPods
|
||||
}
|
||||
|
||||
func GetPodInfosForPods(pods []core.Pod) []*models.PodInfo {
|
||||
podInfos := make([]*models.PodInfo, 0)
|
||||
for _, pod := range pods {
|
||||
podInfos = append(podInfos, &models.PodInfo{Name: pod.Name, Namespace: pod.Namespace, NodeName: pod.Spec.NodeName})
|
||||
}
|
||||
return podInfos
|
||||
return labels
|
||||
}
|
||||
|
||||
@@ -1,389 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/kubeshark/base/pkg/models"
|
||||
"github.com/kubeshark/kubeshark/debounce"
|
||||
"github.com/kubeshark/kubeshark/docker"
|
||||
"github.com/kubeshark/kubeshark/misc"
|
||||
"github.com/kubeshark/kubeshark/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
const updateWorkersDelay = 5 * time.Second
|
||||
|
||||
type TargettedPodChangeEvent struct {
|
||||
Added []v1.Pod
|
||||
Removed []v1.Pod
|
||||
}
|
||||
|
||||
// WorkerSyncer uses a k8s pod watch to update Worker daemonsets when targeted pods are removed or created
|
||||
type WorkerSyncer struct {
|
||||
startTime time.Time
|
||||
context context.Context
|
||||
CurrentlyTargettedPods []v1.Pod
|
||||
config WorkerSyncerConfig
|
||||
kubernetesProvider *Provider
|
||||
TapPodChangesOut chan TargettedPodChangeEvent
|
||||
WorkerPodsChanges chan *v1.Pod
|
||||
ErrorOut chan K8sTapManagerError
|
||||
nodeToTargettedPodMap models.NodeToPodsMap
|
||||
targettedNodes []string
|
||||
}
|
||||
|
||||
type WorkerSyncerConfig struct {
|
||||
TargetNamespaces []string
|
||||
PodFilterRegex regexp.Regexp
|
||||
SelfNamespace string
|
||||
WorkerResources Resources
|
||||
ImagePullPolicy v1.PullPolicy
|
||||
SelfServiceAccountExists bool
|
||||
ServiceMesh bool
|
||||
Tls bool
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func CreateAndStartWorkerSyncer(ctx context.Context, kubernetesProvider *Provider, config WorkerSyncerConfig, startTime time.Time) (*WorkerSyncer, error) {
|
||||
syncer := &WorkerSyncer{
|
||||
startTime: startTime.Truncate(time.Second), // Round down because k8s CreationTimestamp is given in 1 sec resolution.
|
||||
context: ctx,
|
||||
CurrentlyTargettedPods: make([]v1.Pod, 0),
|
||||
config: config,
|
||||
kubernetesProvider: kubernetesProvider,
|
||||
TapPodChangesOut: make(chan TargettedPodChangeEvent, 100),
|
||||
WorkerPodsChanges: make(chan *v1.Pod, 100),
|
||||
ErrorOut: make(chan K8sTapManagerError, 100),
|
||||
}
|
||||
|
||||
if err, _ := syncer.updateCurrentlyTargettedPods(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := syncer.updateWorkers(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go syncer.watchPodsForTargetting()
|
||||
go syncer.watchWorkerEvents()
|
||||
go syncer.watchWorkerPods()
|
||||
return syncer, nil
|
||||
}
|
||||
|
||||
func (workerSyncer *WorkerSyncer) watchWorkerPods() {
|
||||
selfResourceRegex := regexp.MustCompile(fmt.Sprintf("^%s.*", WorkerPodName))
|
||||
podWatchHelper := NewPodWatchHelper(workerSyncer.kubernetesProvider, selfResourceRegex)
|
||||
eventChan, errorChan := FilteredWatch(workerSyncer.context, podWatchHelper, []string{workerSyncer.config.SelfNamespace}, podWatchHelper)
|
||||
|
||||
for {
|
||||
select {
|
||||
case wEvent, ok := <-eventChan:
|
||||
if !ok {
|
||||
eventChan = nil
|
||||
continue
|
||||
}
|
||||
|
||||
pod, err := wEvent.ToPod()
|
||||
if err != nil {
|
||||
log.Error().Str("pod", WorkerPodName).Err(err).Msg(fmt.Sprintf("While parsing %s resource!", misc.Software))
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug().
|
||||
Str("pod", pod.Name).
|
||||
Str("node", pod.Spec.NodeName).
|
||||
Interface("phase", pod.Status.Phase).
|
||||
Msg("Watching pod events...")
|
||||
if pod.Spec.NodeName != "" {
|
||||
workerSyncer.WorkerPodsChanges <- pod
|
||||
}
|
||||
|
||||
case err, ok := <-errorChan:
|
||||
if !ok {
|
||||
errorChan = nil
|
||||
continue
|
||||
}
|
||||
log.Error().Str("pod", WorkerPodName).Err(err).Msg("While watching pod!")
|
||||
|
||||
case <-workerSyncer.context.Done():
|
||||
log.Debug().
|
||||
Str("pod", WorkerPodName).
|
||||
Msg("Watching pod, context done.")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (workerSyncer *WorkerSyncer) watchWorkerEvents() {
|
||||
selfResourceRegex := regexp.MustCompile(fmt.Sprintf("^%s.*", WorkerPodName))
|
||||
eventWatchHelper := NewEventWatchHelper(workerSyncer.kubernetesProvider, selfResourceRegex, "pod")
|
||||
eventChan, errorChan := FilteredWatch(workerSyncer.context, eventWatchHelper, []string{workerSyncer.config.SelfNamespace}, eventWatchHelper)
|
||||
|
||||
for {
|
||||
select {
|
||||
case wEvent, ok := <-eventChan:
|
||||
if !ok {
|
||||
eventChan = nil
|
||||
continue
|
||||
}
|
||||
|
||||
event, err := wEvent.ToEvent()
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Str("pod", WorkerPodName).
|
||||
Err(err).
|
||||
Msg("Parsing resource event.")
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug().
|
||||
Str("pod", WorkerPodName).
|
||||
Str("event", event.Name).
|
||||
Time("time", event.CreationTimestamp.Time).
|
||||
Str("name", event.Regarding.Name).
|
||||
Str("kind", event.Regarding.Kind).
|
||||
Str("reason", event.Reason).
|
||||
Str("note", event.Note).
|
||||
Msg("Watching events.")
|
||||
|
||||
pod, err1 := workerSyncer.kubernetesProvider.GetPod(workerSyncer.context, workerSyncer.config.SelfNamespace, event.Regarding.Name)
|
||||
if err1 != nil {
|
||||
log.Error().Str("name", event.Regarding.Name).Msg("Couldn't get pod")
|
||||
continue
|
||||
}
|
||||
|
||||
workerSyncer.WorkerPodsChanges <- pod
|
||||
|
||||
case err, ok := <-errorChan:
|
||||
if !ok {
|
||||
errorChan = nil
|
||||
continue
|
||||
}
|
||||
|
||||
log.Error().
|
||||
Str("pod", WorkerPodName).
|
||||
Err(err).
|
||||
Msg("While watching events.")
|
||||
|
||||
case <-workerSyncer.context.Done():
|
||||
log.Debug().
|
||||
Str("pod", WorkerPodName).
|
||||
Msg("Watching pod events, context done.")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (workerSyncer *WorkerSyncer) watchPodsForTargetting() {
|
||||
podWatchHelper := NewPodWatchHelper(workerSyncer.kubernetesProvider, &workerSyncer.config.PodFilterRegex)
|
||||
eventChan, errorChan := FilteredWatch(workerSyncer.context, podWatchHelper, workerSyncer.config.TargetNamespaces, podWatchHelper)
|
||||
|
||||
handleChangeInPods := func() {
|
||||
err, changeFound := workerSyncer.updateCurrentlyTargettedPods()
|
||||
if err != nil {
|
||||
workerSyncer.ErrorOut <- K8sTapManagerError{
|
||||
OriginalError: err,
|
||||
TapManagerReason: TapManagerPodListError,
|
||||
}
|
||||
}
|
||||
|
||||
if !changeFound {
|
||||
log.Debug().Msg("Nothing changed. Updating workers is not needed.")
|
||||
return
|
||||
}
|
||||
if err := workerSyncer.updateWorkers(); err != nil {
|
||||
workerSyncer.ErrorOut <- K8sTapManagerError{
|
||||
OriginalError: err,
|
||||
TapManagerReason: TapManagerWorkerUpdateError,
|
||||
}
|
||||
}
|
||||
}
|
||||
restartWorkersDebouncer := debounce.NewDebouncer(updateWorkersDelay, handleChangeInPods)
|
||||
|
||||
for {
|
||||
select {
|
||||
case wEvent, ok := <-eventChan:
|
||||
if !ok {
|
||||
eventChan = nil
|
||||
continue
|
||||
}
|
||||
|
||||
pod, err := wEvent.ToPod()
|
||||
if err != nil {
|
||||
workerSyncer.handleErrorInWatchLoop(err, restartWorkersDebouncer)
|
||||
continue
|
||||
}
|
||||
|
||||
switch wEvent.Type {
|
||||
case EventAdded:
|
||||
log.Debug().
|
||||
Str("pod", pod.Name).
|
||||
Str("namespace", pod.Namespace).
|
||||
Msg("Added matching pod.")
|
||||
if err := restartWorkersDebouncer.SetOn(); err != nil {
|
||||
log.Error().
|
||||
Str("pod", pod.Name).
|
||||
Str("namespace", pod.Namespace).
|
||||
Err(err).
|
||||
Msg("While restarting workers!")
|
||||
}
|
||||
case EventDeleted:
|
||||
log.Debug().
|
||||
Str("pod", pod.Name).
|
||||
Str("namespace", pod.Namespace).
|
||||
Msg("Removed matching pod.")
|
||||
if err := restartWorkersDebouncer.SetOn(); err != nil {
|
||||
log.Error().
|
||||
Str("pod", pod.Name).
|
||||
Str("namespace", pod.Namespace).
|
||||
Err(err).
|
||||
Msg("While restarting workers!")
|
||||
}
|
||||
case EventModified:
|
||||
log.Debug().
|
||||
Str("pod", pod.Name).
|
||||
Str("namespace", pod.Namespace).
|
||||
Str("ip", pod.Status.PodIP).
|
||||
Interface("phase", pod.Status.Phase).
|
||||
Msg("Modified matching pod.")
|
||||
|
||||
// Act only if the modified pod has already obtained an IP address.
|
||||
// After filtering for IPs, on a normal pod restart this includes the following events:
|
||||
// - Pod deletion
|
||||
// - Pod reaches start state
|
||||
// - Pod reaches ready state
|
||||
// Ready/unready transitions might also trigger this event.
|
||||
if pod.Status.PodIP != "" {
|
||||
if err := restartWorkersDebouncer.SetOn(); err != nil {
|
||||
log.Error().
|
||||
Str("pod", pod.Name).
|
||||
Str("namespace", pod.Namespace).
|
||||
Err(err).
|
||||
Msg("While restarting workers!")
|
||||
}
|
||||
}
|
||||
case EventBookmark:
|
||||
break
|
||||
case EventError:
|
||||
break
|
||||
}
|
||||
case err, ok := <-errorChan:
|
||||
if !ok {
|
||||
errorChan = nil
|
||||
continue
|
||||
}
|
||||
|
||||
workerSyncer.handleErrorInWatchLoop(err, restartWorkersDebouncer)
|
||||
continue
|
||||
|
||||
case <-workerSyncer.context.Done():
|
||||
log.Debug().Msg("Watching pods, context done. Stopping \"restart workers debouncer\"")
|
||||
restartWorkersDebouncer.Cancel()
|
||||
// TODO: Does this also perform cleanup?
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (workerSyncer *WorkerSyncer) handleErrorInWatchLoop(err error, restartWorkersDebouncer *debounce.Debouncer) {
|
||||
log.Error().Err(err).Msg("While watching pods, got an error! Stopping \"restart workers debouncer\"")
|
||||
restartWorkersDebouncer.Cancel()
|
||||
workerSyncer.ErrorOut <- K8sTapManagerError{
|
||||
OriginalError: err,
|
||||
TapManagerReason: TapManagerPodWatchError,
|
||||
}
|
||||
}
|
||||
|
||||
func (workerSyncer *WorkerSyncer) updateCurrentlyTargettedPods() (err error, changesFound bool) {
|
||||
if matchingPods, err := workerSyncer.kubernetesProvider.ListAllRunningPodsMatchingRegex(workerSyncer.context, &workerSyncer.config.PodFilterRegex, workerSyncer.config.TargetNamespaces); err != nil {
|
||||
return err, false
|
||||
} else {
|
||||
podsToTarget := excludeSelfPods(matchingPods)
|
||||
addedPods, removedPods := getPodArrayDiff(workerSyncer.CurrentlyTargettedPods, podsToTarget)
|
||||
for _, addedPod := range addedPods {
|
||||
log.Info().Str("pod", addedPod.Name).Msg("Currently targetting:")
|
||||
}
|
||||
for _, removedPod := range removedPods {
|
||||
log.Info().Str("pod", removedPod.Name).Msg("Pod is no longer running. Targetting is stopped.")
|
||||
}
|
||||
if len(addedPods) > 0 || len(removedPods) > 0 {
|
||||
workerSyncer.CurrentlyTargettedPods = podsToTarget
|
||||
workerSyncer.nodeToTargettedPodMap = GetNodeHostToTargettedPodsMap(workerSyncer.CurrentlyTargettedPods)
|
||||
workerSyncer.TapPodChangesOut <- TargettedPodChangeEvent{
|
||||
Added: addedPods,
|
||||
Removed: removedPods,
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func (workerSyncer *WorkerSyncer) updateWorkers() error {
|
||||
nodesToTarget := make([]string, len(workerSyncer.nodeToTargettedPodMap))
|
||||
i := 0
|
||||
for node := range workerSyncer.nodeToTargettedPodMap {
|
||||
nodesToTarget[i] = node
|
||||
i++
|
||||
}
|
||||
|
||||
if utils.EqualStringSlices(nodesToTarget, workerSyncer.targettedNodes) {
|
||||
log.Debug().Msg("Skipping apply, DaemonSet is up to date")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug().Strs("nodes", nodesToTarget).Msg("Updating DaemonSet to run on nodes.")
|
||||
|
||||
image := docker.GetWorkerImage()
|
||||
|
||||
if len(workerSyncer.nodeToTargettedPodMap) > 0 {
|
||||
var serviceAccountName string
|
||||
if workerSyncer.config.SelfServiceAccountExists {
|
||||
serviceAccountName = ServiceAccountName
|
||||
} else {
|
||||
serviceAccountName = ""
|
||||
}
|
||||
|
||||
nodeNames := make([]string, 0, len(workerSyncer.nodeToTargettedPodMap))
|
||||
for nodeName := range workerSyncer.nodeToTargettedPodMap {
|
||||
nodeNames = append(nodeNames, nodeName)
|
||||
}
|
||||
|
||||
if err := workerSyncer.kubernetesProvider.ApplyWorkerDaemonSet(
|
||||
workerSyncer.context,
|
||||
workerSyncer.config.SelfNamespace,
|
||||
WorkerDaemonSetName,
|
||||
image,
|
||||
WorkerPodName,
|
||||
nodeNames,
|
||||
serviceAccountName,
|
||||
workerSyncer.config.WorkerResources,
|
||||
workerSyncer.config.ImagePullPolicy,
|
||||
workerSyncer.config.ServiceMesh,
|
||||
workerSyncer.config.Tls,
|
||||
workerSyncer.config.Debug); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug().Int("worker-count", len(workerSyncer.nodeToTargettedPodMap)).Msg("Successfully created workers.")
|
||||
} else {
|
||||
if err := workerSyncer.kubernetesProvider.ResetWorkerDaemonSet(
|
||||
workerSyncer.context,
|
||||
workerSyncer.config.SelfNamespace,
|
||||
WorkerDaemonSetName,
|
||||
image,
|
||||
WorkerPodName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug().Msg("Successfully resetted Worker DaemonSet")
|
||||
}
|
||||
|
||||
workerSyncer.targettedNodes = nodesToTarget
|
||||
|
||||
return nil
|
||||
}
|
||||
71
kubernetes/workers.go
Normal file
71
kubernetes/workers.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
"github.com/kubeshark/kubeshark/docker"
|
||||
"github.com/rs/zerolog/log"
|
||||
core "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func CreateWorkers(
|
||||
kubernetesProvider *Provider,
|
||||
selfServiceAccountExists bool,
|
||||
ctx context.Context,
|
||||
namespace string,
|
||||
resources configStructs.ResourceRequirements,
|
||||
imagePullPolicy core.PullPolicy,
|
||||
imagePullSecrets []core.LocalObjectReference,
|
||||
serviceMesh bool,
|
||||
tls bool,
|
||||
debug bool,
|
||||
) error {
|
||||
if config.Config.Tap.PersistentStorage {
|
||||
persistentVolumeClaim, err := kubernetesProvider.BuildPersistentVolumeClaim()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = kubernetesProvider.CreatePersistentVolumeClaim(
|
||||
ctx,
|
||||
namespace,
|
||||
persistentVolumeClaim,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
image := docker.GetWorkerImage()
|
||||
|
||||
var serviceAccountName string
|
||||
if selfServiceAccountExists {
|
||||
serviceAccountName = ServiceAccountName
|
||||
} else {
|
||||
serviceAccountName = ""
|
||||
}
|
||||
|
||||
log.Info().Msg("Creating the worker DaemonSet...")
|
||||
|
||||
if err := kubernetesProvider.ApplyWorkerDaemonSet(
|
||||
ctx,
|
||||
namespace,
|
||||
WorkerDaemonSetName,
|
||||
image,
|
||||
WorkerPodName,
|
||||
serviceAccountName,
|
||||
resources,
|
||||
imagePullPolicy,
|
||||
imagePullSecrets,
|
||||
serviceMesh,
|
||||
tls,
|
||||
debug,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msg("Successfully created the worker DaemonSet.")
|
||||
|
||||
return nil
|
||||
}
|
||||
15
kubeshark.go
15
kubeshark.go
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/kubeshark/kubeshark/cmd"
|
||||
@@ -11,6 +12,20 @@ import (
|
||||
|
||||
func main() {
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
|
||||
// Short caller (file:line)
|
||||
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
|
||||
short := file
|
||||
for i := len(file) - 1; i > 0; i-- {
|
||||
if file[i] == '/' {
|
||||
short = file[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
file = short
|
||||
return file + ":" + strconv.Itoa(line)
|
||||
}
|
||||
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger()
|
||||
cmd.Execute()
|
||||
}
|
||||
|
||||
12
manifests/00-namespace.yaml
Normal file
12
manifests/00-namespace.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark
|
||||
spec: {}
|
||||
status: {}
|
||||
12
manifests/01-service-account.yaml
Normal file
12
manifests/01-service-account.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-cli-version: v1
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-service-account
|
||||
namespace: kubeshark
|
||||
26
manifests/02-cluster-role.yaml
Normal file
26
manifests/02-cluster-role.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-cli-version: v1
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-cluster-role
|
||||
namespace: kubeshark
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
- extensions
|
||||
- apps
|
||||
resources:
|
||||
- pods
|
||||
- services
|
||||
- endpoints
|
||||
- persistentvolumeclaims
|
||||
verbs:
|
||||
- list
|
||||
- get
|
||||
- watch
|
||||
20
manifests/03-cluster-role-binding.yaml
Normal file
20
manifests/03-cluster-role-binding.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-cli-version: v1
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-cluster-role-binding
|
||||
namespace: kubeshark
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: kubeshark-cluster-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: kubeshark-service-account
|
||||
namespace: kubeshark
|
||||
47
manifests/04-hub-pod.yaml
Normal file
47
manifests/04-hub-pod.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: kubeshark-hub
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-hub
|
||||
namespace: kubeshark
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- ./hub
|
||||
env:
|
||||
- name: POD_REGEX
|
||||
value: .*
|
||||
- name: NAMESPACES
|
||||
- name: LICENSE
|
||||
- name: SCRIPTING_ENV
|
||||
value: '{}'
|
||||
- name: SCRIPTING_SCRIPTS
|
||||
value: '[]'
|
||||
image: docker.io/kubeshark/hub:latest
|
||||
imagePullPolicy: Always
|
||||
name: kubeshark-hub
|
||||
ports:
|
||||
- containerPort: 80
|
||||
hostPort: 8898
|
||||
resources:
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 50Mi
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
serviceAccountName: kubeshark-service-account
|
||||
terminationGracePeriodSeconds: 0
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
operator: Exists
|
||||
- effect: NoSchedule
|
||||
operator: Exists
|
||||
status: {}
|
||||
21
manifests/05-hub-service.yaml
Normal file
21
manifests/05-hub-service.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-hub
|
||||
namespace: kubeshark
|
||||
spec:
|
||||
ports:
|
||||
- name: kubeshark-hub
|
||||
port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: kubeshark-hub
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
50
manifests/06-front-pod.yaml
Normal file
50
manifests/06-front-pod.yaml
Normal file
@@ -0,0 +1,50 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: kubeshark-front
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-front
|
||||
namespace: kubeshark
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: REACT_APP_DEFAULT_FILTER
|
||||
value: ' '
|
||||
- name: REACT_APP_HUB_HOST
|
||||
value: ' '
|
||||
- name: REACT_APP_HUB_PORT
|
||||
value: "8898"
|
||||
image: docker.io/kubeshark/front:latest
|
||||
imagePullPolicy: Always
|
||||
name: kubeshark-front
|
||||
ports:
|
||||
- containerPort: 80
|
||||
hostPort: 8899
|
||||
readinessProbe:
|
||||
failureThreshold: 3
|
||||
periodSeconds: 1
|
||||
successThreshold: 1
|
||||
tcpSocket:
|
||||
port: 80
|
||||
timeoutSeconds: 1
|
||||
resources:
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 50Mi
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
serviceAccountName: kubeshark-service-account
|
||||
terminationGracePeriodSeconds: 0
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
operator: Exists
|
||||
- effect: NoSchedule
|
||||
operator: Exists
|
||||
status: {}
|
||||
21
manifests/07-front-service.yaml
Normal file
21
manifests/07-front-service.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-front
|
||||
namespace: kubeshark
|
||||
spec:
|
||||
ports:
|
||||
- name: kubeshark-front
|
||||
port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: kubeshark-front
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
20
manifests/08-persistent-volume-claim.yaml
Normal file
20
manifests/08-persistent-volume-claim.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubeshark-cli-version: v1
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-persistent-volume-claim
|
||||
namespace: kubeshark
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 200Mi
|
||||
storageClassName: standard
|
||||
status: {}
|
||||
93
manifests/09-worker-daemon-set.yaml
Normal file
93
manifests/09-worker-daemon-set.yaml
Normal file
@@ -0,0 +1,93 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY KUBESHARK CLI. DO NOT EDIT!
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: kubeshark-worker-daemon-set
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-worker-daemon-set
|
||||
namespace: kubeshark
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kubeshark-worker-daemon-set
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: kubeshark-worker-daemon-set
|
||||
kubeshark-created-by: kubeshark
|
||||
kubeshark-managed-by: kubeshark
|
||||
name: kubeshark-worker-daemon-set
|
||||
namespace: kubeshark
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- ./worker
|
||||
- -i
|
||||
- any
|
||||
- -port
|
||||
- "8897"
|
||||
- -packet-capture
|
||||
- libpcap
|
||||
- -servicemesh
|
||||
- -tls
|
||||
- -procfs
|
||||
- /hostproc
|
||||
image: docker.io/kubeshark/worker:latest
|
||||
imagePullPolicy: Always
|
||||
name: kubeshark-worker-daemon-set
|
||||
ports:
|
||||
- containerPort: 8897
|
||||
hostPort: 8897
|
||||
resources:
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 50Mi
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- NET_RAW
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
- SYS_PTRACE
|
||||
- DAC_OVERRIDE
|
||||
- SYS_RESOURCE
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- mountPath: /hostproc
|
||||
name: proc
|
||||
readOnly: true
|
||||
- mountPath: /sys
|
||||
name: sys
|
||||
readOnly: true
|
||||
- mountPath: /app/data
|
||||
name: kubeshark-persistent-volume
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
hostNetwork: true
|
||||
serviceAccountName: kubeshark-service-account
|
||||
terminationGracePeriodSeconds: 0
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
operator: Exists
|
||||
- effect: NoSchedule
|
||||
operator: Exists
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /proc
|
||||
name: proc
|
||||
- hostPath:
|
||||
path: /sys
|
||||
name: sys
|
||||
- name: kubeshark-persistent-volume
|
||||
persistentVolumeClaim:
|
||||
claimName: kubeshark-persistent-volume-claim
|
||||
35
manifests/README.md
Normal file
35
manifests/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Manifests
|
||||
|
||||
## Apply
|
||||
|
||||
Clone the repo:
|
||||
|
||||
```shell
|
||||
git clone git@github.com:kubeshark/kubeshark.git --depth 1
|
||||
cd kubeshark/manifests
|
||||
```
|
||||
|
||||
To apply the manifests, run:
|
||||
|
||||
```shell
|
||||
kubectl apply -f .
|
||||
```
|
||||
|
||||
To clean up:
|
||||
|
||||
```shell
|
||||
kubectl delete namespace kubeshark
|
||||
kubectl delete clusterrolebinding kubeshark-cluster-role-binding
|
||||
kubectl delete clusterrole kubeshark-cluster-role
|
||||
```
|
||||
|
||||
## Accesing
|
||||
|
||||
Do the port forwarding:
|
||||
|
||||
```shell
|
||||
kubectl port-forward -n kubeshark service/kubeshark-hub 8898:80 & \
|
||||
kubectl port-forward -n kubeshark service/kubeshark-front 8899:80
|
||||
```
|
||||
|
||||
Visit [localhost:8899](http://localhost:8899)
|
||||
@@ -9,7 +9,9 @@ import (
|
||||
var (
|
||||
Software = "Kubeshark"
|
||||
Program = "kubeshark"
|
||||
Description = "The API Traffic Analyzer for Kubernetes"
|
||||
Website = "https://kubeshark.co"
|
||||
Email = "info@kubeshark.co"
|
||||
Ver = "0.0"
|
||||
Branch = "develop"
|
||||
GitCommitHash = "" // this var is overridden using ldflags in makefile when building
|
||||
|
||||
22
misc/fsUtils/globUtils.go
Normal file
22
misc/fsUtils/globUtils.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package fsUtils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func RemoveFilesByExtension(dirPath string, ext string) error {
|
||||
files, err := filepath.Glob(filepath.Join(dirPath, fmt.Sprintf("/*.%s", ext)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if err := os.Remove(f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -15,13 +15,13 @@ import (
|
||||
|
||||
func DumpLogs(ctx context.Context, provider *kubernetes.Provider, filePath string) error {
|
||||
podExactRegex := regexp.MustCompile("^" + kubernetes.SelfResourcesPrefix)
|
||||
pods, err := provider.ListAllPodsMatchingRegex(ctx, podExactRegex, []string{config.Config.SelfNamespace})
|
||||
pods, err := provider.ListAllPodsMatchingRegex(ctx, podExactRegex, []string{config.Config.Tap.SelfNamespace})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(pods) == 0 {
|
||||
return fmt.Errorf("No %s pods found in namespace %s", misc.Software, config.Config.SelfNamespace)
|
||||
return fmt.Errorf("No %s pods found in namespace %s", misc.Software, config.Config.Tap.SelfNamespace)
|
||||
}
|
||||
|
||||
newZipFile, err := os.Create(filePath)
|
||||
@@ -60,23 +60,23 @@ func DumpLogs(ctx context.Context, provider *kubernetes.Provider, filePath strin
|
||||
}
|
||||
}
|
||||
|
||||
events, err := provider.GetNamespaceEvents(ctx, config.Config.SelfNamespace)
|
||||
events, err := provider.GetNamespaceEvents(ctx, config.Config.Tap.SelfNamespace)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get k8b events!")
|
||||
} else {
|
||||
log.Debug().Str("namespace", config.Config.SelfNamespace).Msg("Successfully read events.")
|
||||
log.Debug().Str("namespace", config.Config.Tap.SelfNamespace).Msg("Successfully read events.")
|
||||
}
|
||||
|
||||
if err := AddStrToZip(zipWriter, events, fmt.Sprintf("%s_events.log", config.Config.SelfNamespace)); err != nil {
|
||||
if err := AddStrToZip(zipWriter, events, fmt.Sprintf("%s_events.log", config.Config.Tap.SelfNamespace)); err != nil {
|
||||
log.Error().Err(err).Msg("Failed write logs!")
|
||||
} else {
|
||||
log.Debug().Str("namespace", config.Config.SelfNamespace).Msg("Successfully added events.")
|
||||
log.Debug().Str("namespace", config.Config.Tap.SelfNamespace).Msg("Successfully added events.")
|
||||
}
|
||||
|
||||
if err := AddFileToZip(zipWriter, config.Config.ConfigFilePath); err != nil {
|
||||
if err := AddFileToZip(zipWriter, config.ConfigFilePath); err != nil {
|
||||
log.Error().Err(err).Msg("Failed write file!")
|
||||
} else {
|
||||
log.Debug().Str("file-path", config.Config.ConfigFilePath).Msg("Successfully added file.")
|
||||
log.Debug().Str("file-path", config.ConfigFilePath).Msg("Successfully added file.")
|
||||
}
|
||||
|
||||
log.Info().Str("path", filePath).Msg("You can find the ZIP file with all logs at:")
|
||||
|
||||
55
misc/scripting.go
Normal file
55
misc/scripting.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/robertkrimen/otto/ast"
|
||||
"github.com/robertkrimen/otto/file"
|
||||
"github.com/robertkrimen/otto/parser"
|
||||
)
|
||||
|
||||
type Script struct {
|
||||
Path string `json:"path"`
|
||||
Title string `json:"title"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
func ReadScriptFile(path string) (script *Script, err error) {
|
||||
filename := filepath.Base(path)
|
||||
var body []byte
|
||||
body, err = os.ReadFile(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
content := string(body)
|
||||
|
||||
var program *ast.Program
|
||||
program, err = parser.ParseFile(nil, filename, content, parser.StoreComments)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var title string
|
||||
var titleIsSet bool
|
||||
code := content
|
||||
|
||||
var idx0 file.Idx
|
||||
for node, comments := range program.Comments {
|
||||
if (titleIsSet && node.Idx0() > idx0) || len(comments) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
idx0 = node.Idx0()
|
||||
title = comments[0].Text
|
||||
titleIsSet = true
|
||||
}
|
||||
|
||||
script = &Script{
|
||||
Path: path,
|
||||
Title: title,
|
||||
Code: code,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -108,13 +108,13 @@ func cleanUpRestrictedMode(ctx context.Context, kubernetesProvider *kubernetes.P
|
||||
handleDeletionError(err, resourceDesc, &leftoverResources)
|
||||
}
|
||||
|
||||
if err := kubernetesProvider.RemoveDaemonSet(ctx, selfResourcesNamespace, kubernetes.WorkerDaemonSetName); err != nil {
|
||||
resourceDesc := fmt.Sprintf("DaemonSet %s in namespace %s", kubernetes.WorkerDaemonSetName, selfResourcesNamespace)
|
||||
if err := kubernetesProvider.RemovePersistentVolumeClaim(ctx, selfResourcesNamespace, kubernetes.PersistentVolumeClaimName); err != nil {
|
||||
resourceDesc := fmt.Sprintf("Persistent Volume %s in namespace %s", kubernetes.PersistentVolumeClaimName, selfResourcesNamespace)
|
||||
handleDeletionError(err, resourceDesc, &leftoverResources)
|
||||
}
|
||||
|
||||
if err := kubernetesProvider.RemoveConfigMap(ctx, selfResourcesNamespace, kubernetes.ConfigMapName); err != nil {
|
||||
resourceDesc := fmt.Sprintf("ConfigMap %s in namespace %s", kubernetes.ConfigMapName, selfResourcesNamespace)
|
||||
if err := kubernetesProvider.RemoveDaemonSet(ctx, selfResourcesNamespace, kubernetes.WorkerDaemonSetName); err != nil {
|
||||
resourceDesc := fmt.Sprintf("DaemonSet %s in namespace %s", kubernetes.WorkerDaemonSetName, selfResourcesNamespace)
|
||||
handleDeletionError(err, resourceDesc, &leftoverResources)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kubeshark/kubeshark/config"
|
||||
"github.com/kubeshark/kubeshark/config/configStructs"
|
||||
"github.com/kubeshark/kubeshark/docker"
|
||||
"github.com/kubeshark/kubeshark/errormessage"
|
||||
"github.com/kubeshark/kubeshark/kubernetes"
|
||||
@@ -13,32 +14,28 @@ import (
|
||||
core "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func CreateHubResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, isNsRestrictedMode bool, selfNamespace string, hubResources kubernetes.Resources, imagePullPolicy core.PullPolicy, debug bool) (bool, error) {
|
||||
func CreateHubResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, isNsRestrictedMode bool, selfNamespace string, hubResources configStructs.ResourceRequirements, imagePullPolicy core.PullPolicy, imagePullSecrets []core.LocalObjectReference, debug bool) (bool, error) {
|
||||
if !isNsRestrictedMode {
|
||||
if err := createSelfNamespace(ctx, kubernetesProvider, selfNamespace); err != nil {
|
||||
return false, err
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
selfServiceAccountExists, err := createRBACIfNecessary(ctx, kubernetesProvider, isNsRestrictedMode, selfNamespace, []string{"pods", "services", "endpoints"})
|
||||
err := kubernetesProvider.CreateSelfRBAC(ctx, selfNamespace)
|
||||
var selfServiceAccountExists bool
|
||||
if err != nil {
|
||||
selfServiceAccountExists = true
|
||||
log.Warn().Err(errormessage.FormatError(err)).Msg(fmt.Sprintf("Failed to ensure the resources required for IP resolving. %s will not resolve target IPs to names.", misc.Software))
|
||||
}
|
||||
|
||||
var serviceAccountName string
|
||||
if selfServiceAccountExists {
|
||||
serviceAccountName = kubernetes.ServiceAccountName
|
||||
} else {
|
||||
serviceAccountName = ""
|
||||
}
|
||||
|
||||
opts := &kubernetes.PodOptions{
|
||||
hubOpts := &kubernetes.PodOptions{
|
||||
Namespace: selfNamespace,
|
||||
PodName: kubernetes.HubPodName,
|
||||
PodImage: docker.GetHubImage(),
|
||||
ServiceAccountName: serviceAccountName,
|
||||
ServiceAccountName: kubernetes.ServiceAccountName,
|
||||
Resources: hubResources,
|
||||
ImagePullPolicy: imagePullPolicy,
|
||||
ImagePullSecrets: imagePullSecrets,
|
||||
Debug: debug,
|
||||
}
|
||||
|
||||
@@ -46,13 +43,14 @@ func CreateHubResources(ctx context.Context, kubernetesProvider *kubernetes.Prov
|
||||
Namespace: selfNamespace,
|
||||
PodName: kubernetes.FrontPodName,
|
||||
PodImage: docker.GetWorkerImage(),
|
||||
ServiceAccountName: serviceAccountName,
|
||||
ServiceAccountName: kubernetes.ServiceAccountName,
|
||||
Resources: hubResources,
|
||||
ImagePullPolicy: imagePullPolicy,
|
||||
ImagePullSecrets: imagePullSecrets,
|
||||
Debug: debug,
|
||||
}
|
||||
|
||||
if err := createSelfHubPod(ctx, kubernetesProvider, opts); err != nil {
|
||||
if err := createSelfHubPod(ctx, kubernetesProvider, hubOpts); err != nil {
|
||||
return selfServiceAccountExists, err
|
||||
}
|
||||
|
||||
@@ -61,14 +59,14 @@ func CreateHubResources(ctx context.Context, kubernetesProvider *kubernetes.Prov
|
||||
}
|
||||
|
||||
// TODO: Why the port values need to be 80?
|
||||
_, err = kubernetesProvider.CreateService(ctx, selfNamespace, kubernetes.HubServiceName, kubernetes.HubServiceName, 80, 80)
|
||||
_, err = kubernetesProvider.CreateService(ctx, selfNamespace, kubernetesProvider.BuildHubService(selfNamespace))
|
||||
if err != nil {
|
||||
return selfServiceAccountExists, err
|
||||
}
|
||||
|
||||
log.Info().Str("service", kubernetes.HubServiceName).Msg("Successfully created a service.")
|
||||
|
||||
_, err = kubernetesProvider.CreateService(ctx, selfNamespace, kubernetes.FrontServiceName, kubernetes.FrontServiceName, 80, int32(config.Config.Tap.Proxy.Front.DstPort))
|
||||
_, err = kubernetesProvider.CreateService(ctx, selfNamespace, kubernetesProvider.BuildFrontService(selfNamespace))
|
||||
if err != nil {
|
||||
return selfServiceAccountExists, err
|
||||
}
|
||||
@@ -79,24 +77,10 @@ func CreateHubResources(ctx context.Context, kubernetesProvider *kubernetes.Prov
|
||||
}
|
||||
|
||||
func createSelfNamespace(ctx context.Context, kubernetesProvider *kubernetes.Provider, selfNamespace string) error {
|
||||
_, err := kubernetesProvider.CreateNamespace(ctx, selfNamespace)
|
||||
_, err := kubernetesProvider.CreateNamespace(ctx, kubernetesProvider.BuildNamespace(selfNamespace))
|
||||
return err
|
||||
}
|
||||
|
||||
func createRBACIfNecessary(ctx context.Context, kubernetesProvider *kubernetes.Provider, isNsRestrictedMode bool, selfNamespace string, resources []string) (bool, error) {
|
||||
if !isNsRestrictedMode {
|
||||
if err := kubernetesProvider.CreateSelfRBAC(ctx, selfNamespace, kubernetes.ServiceAccountName, kubernetes.ClusterRoleName, kubernetes.ClusterRoleBindingName, misc.RBACVersion, resources); err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
if err := kubernetesProvider.CreateSelfRBACNamespaceRestricted(ctx, selfNamespace, kubernetes.ServiceAccountName, kubernetes.RoleName, kubernetes.RoleBindingName, misc.RBACVersion); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func createSelfHubPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, opts *kubernetes.PodOptions) error {
|
||||
pod, err := kubernetesProvider.BuildHubPod(opts)
|
||||
if err != nil {
|
||||
@@ -110,7 +94,7 @@ func createSelfHubPod(ctx context.Context, kubernetesProvider *kubernetes.Provid
|
||||
}
|
||||
|
||||
func createFrontPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, opts *kubernetes.PodOptions) error {
|
||||
pod, err := kubernetesProvider.BuildFrontPod(opts, config.Config.Tap.Proxy.Host, fmt.Sprintf("%d", config.Config.Tap.Proxy.Hub.SrcPort))
|
||||
pod, err := kubernetesProvider.BuildFrontPod(opts, config.Config.Tap.Proxy.Host, fmt.Sprintf("%d", config.Config.Tap.Proxy.Hub.Port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ const (
|
||||
Red = "\033[1;31m%s\033[0m"
|
||||
Green = "\033[1;32m%s\033[0m"
|
||||
Yellow = "\033[1;33m%s\033[0m"
|
||||
Purple = "\033[1;34m%s\033[0m"
|
||||
Blue = "\033[1;34m%s\033[0m"
|
||||
Magenta = "\033[1;35m%s\033[0m"
|
||||
Teal = "\033[1;36m%s\033[0m"
|
||||
Cyan = "\033[1;36m%s\033[0m"
|
||||
White = "\033[1;37m%s\033[0m"
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@ func PrettyJson(data interface{}) (string, error) {
|
||||
func PrettyYaml(data interface{}) (string, error) {
|
||||
buffer := new(bytes.Buffer)
|
||||
encoder := yaml.NewEncoder(buffer)
|
||||
encoder.SetIndent(0)
|
||||
encoder.SetIndent(2)
|
||||
|
||||
err := encoder.Encode(data)
|
||||
if err != nil {
|
||||
@@ -35,3 +35,18 @@ func PrettyYaml(data interface{}) (string, error) {
|
||||
}
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
func PrettyYamlOmitEmpty(data interface{}) (string, error) {
|
||||
d, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return empty, err
|
||||
}
|
||||
|
||||
var cleanData map[string]interface{}
|
||||
err = json.Unmarshal(d, &cleanData)
|
||||
if err != nil {
|
||||
return empty, err
|
||||
}
|
||||
|
||||
return PrettyYaml(cleanData)
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package utils
|
||||
|
||||
import "github.com/docker/go-units"
|
||||
|
||||
func HumanReadableToBytes(humanReadableSize string) (int64, error) {
|
||||
return units.FromHumanSize(humanReadableSize)
|
||||
}
|
||||
Reference in New Issue
Block a user