Skip to content

Commit

Permalink
chore: add ut and docs for sidecar injector (#1035)
Browse files Browse the repository at this point in the history
* chore: add ut and docs for sidecar injector

Signed-off-by: seeflood <zhou.qunli@foxmail.com>

* chore: add ut and docs for sidecar injector

Signed-off-by: seeflood <zhou.qunli@foxmail.com>

* chore: add ut and docs for sidecar injector

Signed-off-by: seeflood <zhou.qunli@foxmail.com>

* chore: add ut and docs for sidecar injector

Signed-off-by: seeflood <zhou.qunli@foxmail.com>

* chore: add ut and docs for sidecar injector

Signed-off-by: seeflood <zhou.qunli@foxmail.com>

* chore: add ut and docs for sidecar injector

Signed-off-by: seeflood <zhou.qunli@foxmail.com>

* fix: CI errors

* fix: CI errors

---------

Signed-off-by: seeflood <zhou.qunli@foxmail.com>
  • Loading branch information
seeflood authored Apr 28, 2024
1 parent 94fc2ed commit 80cf3c3
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .github/dead_link_check_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
{
"pattern":"^https://techhenzy.com/proxy-webassembly-architecture/"
},
{
"pattern":"^https://www.sofastack.tech/blog/the-next-five-years-of-cloud-native-runtime/"
},
{
"pattern": "^#"
}
Expand Down
1 change: 1 addition & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
- [Snowflake](en/component_specs/sequencer/snowflake.md)
- [Secret Store](en/component_specs/secret/common.md)
- [How to deploy and upgrade Layotto](en/operation/)
- [Layotto sidecar injector](en/operation/sidecar_injector.md)
- Design documents
- [Actuator design doc](en/design/actuator/actuator-design-doc.md)
- [Configuration API with Apollo](en/design/configuration/configuration-api-with-apollo.md)
Expand Down
66 changes: 66 additions & 0 deletions docs/en/operation/sidecar_injector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Layotto sidecar injector
Sidecar injector can inject the Layotto sidecar to your pods automatically.

## Prerequisites
This Layotto state SDK client demo requires you to have the following installed on your machine:

- [kubectl](https://kubernetes.io/docs/tasks/tools/)
- A Kubernetes cluster, such as [Minikube](https://minikube.sigs.k8s.io/docs/start/), [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
- [Helm v3](https://helm.sh/docs/intro/install/)

Remember to change your current directory to `${project_path}/demo/state/k8s`.

## Step 1 - Setup Layotto sidecar injector on your Kubernetes cluster
1. Use Kind to quickly build a local Kubernetes cluster

```
kind create cluster --name layotto-cluster
kubectl config use-context kind-layotto-cluster
```

2. Install the layotto sidecar injector chart on your cluster in the layotto-system namespace

```
helm install injector oci://docker.io/layotto/injector-helm --version v0.5.0 -n layotto-system --create-namespace --wait
```

## Step 2 - Use Helm to deploy Redis on your Kubernetes cluster
`Redis` is an open source, advanced key-value store. It is often referred to as a data structure server since keys
can contain strings, hashes, lists, sets and sorted sets.

Here we use `Redis` to persist and retrieve state.

```
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install redis bitnami/redis --set image.tag=6.2 --set auth.enabled=false
```

## Step 3 - Deploy the layotto state client with the Layotto sidecar
1. Create a ConfigMap named `layotto-config` and populate its data from the `config.json` file

```
kubectl create configmap layotto-config --from-file=./config.json
```

2. Deploy Layotto state SDK client App

```
kubectl apply -f ./state-sdk-demo.yaml
```

Let's take a look at the important annotations in state-sdk-demo.yaml
- `layotto/sidecar-inject: "true"` - this tells the Layotto sidecar injector to inject a sidecar to this deployment.
- `layotto/config-volume: "layotto-config-vol` - this tells the Layotto sidecar injector which config Volume resource to
mount into layout container.

The `layotto-config` ConfigMap is mounted as a volume, and all contents stored in its `config.json` entry are mounted into
the layotto sidecar container at path `/runtime/configs`. The successfully mounted `config.json` file will be used as the configuration
file when Layotto starts.

## View program running results
If the following information is printed, the demo succeeded:

![pods.jpg](https://raw.githubusercontent.com/mosn/layotto/6e0fa2c49dde40ba9a3400f193ef35ff2c670754/demo/state/k8s/images/pods.jpg)

![log.jpg](https://raw.githubusercontent.com/mosn/layotto/6e0fa2c49dde40ba9a3400f193ef35ff2c670754/demo/state/k8s/images/log.jpg)
1 change: 1 addition & 0 deletions docs/zh/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
- [Secret Store](zh/component_specs/secret/common.md)
- [自定义组件](zh/component_specs/custom/common.md)
- [如何部署、升级 Layotto](zh/operation/)
- [Layotto sidecar injector](zh/operation/sidecar_injector.md)
- [如何本地开发、本地调试](zh/operation/local.md)
- 设计文档
- [动态配置下发、组件热重载](zh/design/lifecycle/apply_configuration.md)
Expand Down
66 changes: 66 additions & 0 deletions docs/zh/operation/sidecar_injector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Layotto sidecar injector
Sidecar injector can inject the Layotto sidecar to your pods automatically.

## Prerequisites
This Layotto state SDK client demo requires you to have the following installed on your machine:

- [kubectl](https://kubernetes.io/docs/tasks/tools/)
- A Kubernetes cluster, such as [Minikube](https://minikube.sigs.k8s.io/docs/start/), [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
- [Helm v3](https://helm.sh/docs/intro/install/)

Remember to change your current directory to `${project_path}/demo/state/k8s`.

## Step 1 - Setup Layotto sidecar injector on your Kubernetes cluster
1. Use Kind to quickly build a local Kubernetes cluster

```
kind create cluster --name layotto-cluster
kubectl config use-context kind-layotto-cluster
```

2. Install the layotto sidecar injector chart on your cluster in the layotto-system namespace

```
helm install injector oci://docker.io/layotto/injector-helm --version v0.5.0 -n layotto-system --create-namespace --wait
```

## Step 2 - Use Helm to deploy Redis on your Kubernetes cluster
`Redis` is an open source, advanced key-value store. It is often referred to as a data structure server since keys
can contain strings, hashes, lists, sets and sorted sets.

Here we use `Redis` to persist and retrieve state.

```
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install redis bitnami/redis --set image.tag=6.2 --set auth.enabled=false
```

## Step 3 - Deploy the layotto state client with the Layotto sidecar
1. Create a ConfigMap named `layotto-config` and populate its data from the `config.json` file

```
kubectl create configmap layotto-config --from-file=./config.json
```

2. Deploy Layotto state SDK client App

```
kubectl apply -f ./state-sdk-demo.yaml
```

Let's take a look at the important annotations in state-sdk-demo.yaml
- `layotto/sidecar-inject: "true"` - this tells the Layotto sidecar injector to inject a sidecar to this deployment.
- `layotto/config-volume: "layotto-config-vol` - this tells the Layotto sidecar injector which config Volume resource to
mount into layout container.

The `layotto-config` ConfigMap is mounted as a volume, and all contents stored in its `config.json` entry are mounted into
the layotto sidecar container at path `/runtime/configs`. The successfully mounted `config.json` file will be used as the configuration
file when Layotto starts.

## View program running results
If the following information is printed, the demo succeeded:

![pods.jpg](https://raw.githubusercontent.com/mosn/layotto/6e0fa2c49dde40ba9a3400f193ef35ff2c670754/demo/state/k8s/images/pods.jpg)

![log.jpg](https://raw.githubusercontent.com/mosn/layotto/6e0fa2c49dde40ba9a3400f193ef35ff2c670754/demo/state/k8s/images/log.jpg)
4 changes: 2 additions & 2 deletions pkg/grpc/default_api/api_lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func TestTryLock(t *testing.T) {

t.Run("normal", func(t *testing.T) {
mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t))
mockLockStore.EXPECT().TryLock(context.TODO(), gomock.Any()).DoAndReturn(func(ctx context.Context, req *lock.TryLockRequest) (*lock.TryLockResponse, error) {
mockLockStore.EXPECT().TryLock(context.Background(), gomock.Any()).DoAndReturn(func(ctx context.Context, req *lock.TryLockRequest) (*lock.TryLockResponse, error) {
assert.Equal(t, "lock|||resource", req.ResourceId)
assert.Equal(t, "owner", req.LockOwner)
assert.Equal(t, int32(1), req.Expire)
Expand Down Expand Up @@ -195,7 +195,7 @@ func TestUnlock(t *testing.T) {

t.Run("normal", func(t *testing.T) {
mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t))
mockLockStore.EXPECT().Unlock(context.TODO(), gomock.Any()).DoAndReturn(func(ctx context.Context, req *lock.UnlockRequest) (*lock.UnlockResponse, error) {
mockLockStore.EXPECT().Unlock(context.Background(), gomock.Any()).DoAndReturn(func(ctx context.Context, req *lock.UnlockRequest) (*lock.UnlockResponse, error) {
assert.Equal(t, "lock|||resource", req.ResourceId)
assert.Equal(t, "owner", req.LockOwner)
return &lock.UnlockResponse{
Expand Down
139 changes: 139 additions & 0 deletions pkg/injector/patcher/sidecar_patcher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright 2021 Layotto Authors
// 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
//
// http://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.

package patcher

import (
"testing"

corev1 "k8s.io/api/core/v1"

injectorConsts "mosn.io/layotto/pkg/injector/consts"
)

func TestInjectRequired(t *testing.T) {
t.Run("returns true when sidecar injection is enabled and pod does not contain sidecar", func(t *testing.T) {
config := &SidecarConfig{
SidecarInject: true,
pod: &corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: "not-sidecar"},
},
},
},
}

if !config.injectRequired() {
t.Errorf("Expected true, got false")
}
})

t.Run("returns false when sidecar injection is disabled", func(t *testing.T) {
config := &SidecarConfig{
SidecarInject: false,
}

if config.injectRequired() {
t.Errorf("Expected false, got true")
}
})

t.Run("returns false when pod already contains sidecar", func(t *testing.T) {
config := &SidecarConfig{
SidecarInject: true,
pod: &corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: injectorConsts.SidecarContainerName},
},
},
},
}

if config.injectRequired() {
t.Errorf("Expected false, got true")
}
})
}

func TestGetPatch(t *testing.T) {
t.Run("returns nil when sidecar injection is not required", func(t *testing.T) {
config := &SidecarConfig{
SidecarInject: false,
}

patch, err := config.GetPatch()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if patch != nil {
t.Errorf("Expected nil, got %v", patch)
}
})

t.Run("returns patch when sidecar injection is required", func(t *testing.T) {
config := &SidecarConfig{
SidecarInject: true,
pod: &corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: "not-sidecar"},
},
},
},
}

patch, err := config.GetPatch()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if len(patch) == 0 {
t.Errorf("Expected patch, got nil or empty")
}
})
}

func TestPodContainsSidecarContainer(t *testing.T) {
t.Run("returns true when pod contains sidecar container", func(t *testing.T) {
config := &SidecarConfig{
pod: &corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: injectorConsts.SidecarContainerName},
},
},
},
}

if !config.podContainsSidecarContainer() {
t.Errorf("Expected true, got false")
}
})

t.Run("returns false when pod does not contain sidecar container", func(t *testing.T) {
config := &SidecarConfig{
pod: &corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: "not-sidecar"},
},
},
},
}

if config.podContainsSidecarContainer() {
t.Errorf("Expected false, got true")
}
})
}
Loading

0 comments on commit 80cf3c3

Please sign in to comment.