mirror of
https://github.com/sablierapp/sablier.git
synced 2025-12-21 21:33:06 +01:00
test(kubernetes): increase test coverage (#546)
This commit is contained in:
@@ -18,6 +18,10 @@ func (p *KubernetesProvider) watchDeployents(instance chan<- string) cache.Share
|
||||
return
|
||||
}
|
||||
|
||||
if *oldDeployment.Spec.Replicas == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if *newDeployment.Spec.Replicas == 0 {
|
||||
parsed := DeploymentName(newDeployment, ParseOptions{Delimiter: p.delimiter})
|
||||
instance <- parsed.Original
|
||||
|
||||
@@ -4,18 +4,20 @@ import (
|
||||
"context"
|
||||
"github.com/sablierapp/sablier/app/discovery"
|
||||
"github.com/sablierapp/sablier/app/types"
|
||||
"github.com/sablierapp/sablier/pkg/provider"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
core_v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (p *KubernetesProvider) DeploymentList(ctx context.Context, options provider.InstanceListOptions) ([]types.Instance, error) {
|
||||
func (p *KubernetesProvider) DeploymentList(ctx context.Context) ([]types.Instance, error) {
|
||||
labelSelector := metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
discovery.LabelEnable: "true",
|
||||
},
|
||||
}
|
||||
deployments, err := p.Client.AppsV1().Deployments(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
|
||||
LabelSelector: strings.Join(options.Labels, ","),
|
||||
LabelSelector: metav1.FormatLabelSelector(&labelSelector),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -47,3 +49,33 @@ func (p *KubernetesProvider) deploymentToInstance(d *v1.Deployment) types.Instan
|
||||
Group: group,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *KubernetesProvider) DeploymentGroups(ctx context.Context) (map[string][]string, error) {
|
||||
labelSelector := metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
discovery.LabelEnable: "true",
|
||||
},
|
||||
}
|
||||
deployments, err := p.Client.AppsV1().Deployments(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
|
||||
LabelSelector: metav1.FormatLabelSelector(&labelSelector),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groups := make(map[string][]string)
|
||||
for _, deployment := range deployments.Items {
|
||||
groupName := deployment.Labels[discovery.LabelGroup]
|
||||
if len(groupName) == 0 {
|
||||
groupName = discovery.LabelGroupDefaultValue
|
||||
}
|
||||
|
||||
group := groups[groupName]
|
||||
parsed := DeploymentName(&deployment, ParseOptions{Delimiter: p.delimiter})
|
||||
group = append(group, parsed.Original)
|
||||
groups[groupName] = group
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
95
pkg/provider/kubernetes/instance_events_test.go
Normal file
95
pkg/provider/kubernetes/instance_events_test.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package kubernetes_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/neilotoole/slogt"
|
||||
"github.com/sablierapp/sablier/config"
|
||||
"github.com/sablierapp/sablier/pkg/provider/kubernetes"
|
||||
"gotest.tools/v3/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestKubernetesProvider_NotifyInstanceStopped(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(t.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
kind := setupKinD(t, ctx)
|
||||
p, err := kubernetes.NewKubernetesProvider(ctx, kind.client, slogt.New(t), config.NewProviderConfig().Kubernetes)
|
||||
assert.NilError(t, err)
|
||||
|
||||
waitC := make(chan string)
|
||||
go p.NotifyInstanceStopped(ctx, waitC)
|
||||
|
||||
t.Run("deployment is scaled to 0 replicas", func(t *testing.T) {
|
||||
d, err := kind.CreateMimicDeployment(ctx, MimicOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = WaitForDeploymentReady(ctx, kind.client, d.Namespace, d.Name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
s, err := p.Client.AppsV1().Deployments(d.Namespace).GetScale(ctx, d.Name, metav1.GetOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
s.Spec.Replicas = 0
|
||||
_, err = p.Client.AppsV1().Deployments(d.Namespace).UpdateScale(ctx, d.Name, s, metav1.UpdateOptions{})
|
||||
|
||||
name := <-waitC
|
||||
|
||||
// Docker container name is prefixed with a slash, but we don't use it
|
||||
assert.Equal(t, name, kubernetes.DeploymentName(d, kubernetes.ParseOptions{Delimiter: "_"}).Original)
|
||||
})
|
||||
t.Run("deployment is removed", func(t *testing.T) {
|
||||
d, err := kind.CreateMimicDeployment(ctx, MimicOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = WaitForDeploymentReady(ctx, kind.client, d.Namespace, d.Name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = p.Client.AppsV1().Deployments(d.Namespace).Delete(ctx, d.Name, metav1.DeleteOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
name := <-waitC
|
||||
|
||||
// Docker container name is prefixed with a slash, but we don't use it
|
||||
assert.Equal(t, name, kubernetes.DeploymentName(d, kubernetes.ParseOptions{Delimiter: "_"}).Original)
|
||||
})
|
||||
t.Run("statefulSet is scaled to 0 replicas", func(t *testing.T) {
|
||||
ss, err := kind.CreateMimicStatefulSet(ctx, MimicOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = WaitForStatefulSetReady(ctx, kind.client, ss.Namespace, ss.Name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
s, err := p.Client.AppsV1().StatefulSets(ss.Namespace).GetScale(ctx, ss.Name, metav1.GetOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
s.Spec.Replicas = 0
|
||||
_, err = p.Client.AppsV1().StatefulSets(ss.Namespace).UpdateScale(ctx, ss.Name, s, metav1.UpdateOptions{})
|
||||
|
||||
name := <-waitC
|
||||
|
||||
// Docker container name is prefixed with a slash, but we don't use it
|
||||
assert.Equal(t, name, kubernetes.StatefulSetName(ss, kubernetes.ParseOptions{Delimiter: "_"}).Original)
|
||||
})
|
||||
|
||||
t.Run("statefulSet is removed", func(t *testing.T) {
|
||||
ss, err := kind.CreateMimicStatefulSet(ctx, MimicOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = WaitForStatefulSetReady(ctx, kind.client, ss.Namespace, ss.Name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = p.Client.AppsV1().StatefulSets(ss.Namespace).Delete(ctx, ss.Name, metav1.DeleteOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
name := <-waitC
|
||||
|
||||
// Docker container name is prefixed with a slash, but we don't use it
|
||||
assert.Equal(t, name, kubernetes.StatefulSetName(ss, kubernetes.ParseOptions{Delimiter: "_"}).Original)
|
||||
})
|
||||
}
|
||||
@@ -7,15 +7,38 @@ import (
|
||||
)
|
||||
|
||||
func (p *KubernetesProvider) InstanceList(ctx context.Context, options provider.InstanceListOptions) ([]types.Instance, error) {
|
||||
deployments, err := p.DeploymentList(ctx, options)
|
||||
deployments, err := p.DeploymentList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
statefulSets, err := p.StatefulSetList(ctx, options)
|
||||
statefulSets, err := p.StatefulSetList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return append(deployments, statefulSets...), nil
|
||||
}
|
||||
|
||||
func (p *KubernetesProvider) InstanceGroups(ctx context.Context) (map[string][]string, error) {
|
||||
deployments, err := p.DeploymentGroups(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
statefulSets, err := p.StatefulSetGroups(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groups := make(map[string][]string)
|
||||
for group, instances := range deployments {
|
||||
groups[group] = instances
|
||||
}
|
||||
|
||||
for group, instances := range statefulSets {
|
||||
groups[group] = append(groups[group], instances...)
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
145
pkg/provider/kubernetes/instance_list_test.go
Normal file
145
pkg/provider/kubernetes/instance_list_test.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package kubernetes_test
|
||||
|
||||
import (
|
||||
"github.com/neilotoole/slogt"
|
||||
"github.com/sablierapp/sablier/app/types"
|
||||
"github.com/sablierapp/sablier/config"
|
||||
"github.com/sablierapp/sablier/pkg/provider"
|
||||
"github.com/sablierapp/sablier/pkg/provider/kubernetes"
|
||||
"gotest.tools/v3/assert"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKubernetesProvider_InstanceList(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
ctx := t.Context()
|
||||
kind := setupKinD(t, ctx)
|
||||
p, err := kubernetes.NewKubernetesProvider(ctx, kind.client, slogt.New(t), config.NewProviderConfig().Kubernetes)
|
||||
assert.NilError(t, err)
|
||||
|
||||
d1, err := kind.CreateMimicDeployment(ctx, MimicOptions{
|
||||
Labels: map[string]string{
|
||||
"sablier.enable": "true",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
d2, err := kind.CreateMimicDeployment(ctx, MimicOptions{
|
||||
Labels: map[string]string{
|
||||
"sablier.enable": "true",
|
||||
"sablier.group": "my-group",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
ss1, err := kind.CreateMimicStatefulSet(ctx, MimicOptions{
|
||||
Labels: map[string]string{
|
||||
"sablier.enable": "true",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
ss2, err := kind.CreateMimicStatefulSet(ctx, MimicOptions{
|
||||
Labels: map[string]string{
|
||||
"sablier.enable": "true",
|
||||
"sablier.group": "my-group",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
got, err := p.InstanceList(ctx, provider.InstanceListOptions{
|
||||
All: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
want := []types.Instance{
|
||||
{
|
||||
Name: kubernetes.DeploymentName(d1, kubernetes.ParseOptions{Delimiter: "_"}).Original,
|
||||
Group: "default",
|
||||
},
|
||||
{
|
||||
Name: kubernetes.DeploymentName(d2, kubernetes.ParseOptions{Delimiter: "_"}).Original,
|
||||
Group: "my-group",
|
||||
},
|
||||
{
|
||||
Name: kubernetes.StatefulSetName(ss1, kubernetes.ParseOptions{Delimiter: "_"}).Original,
|
||||
Group: "default",
|
||||
},
|
||||
{
|
||||
Name: kubernetes.StatefulSetName(ss2, kubernetes.ParseOptions{Delimiter: "_"}).Original,
|
||||
Group: "my-group",
|
||||
},
|
||||
}
|
||||
// Assert go is equal to want
|
||||
// Sort both array to ensure they are equal
|
||||
sort.Slice(got, func(i, j int) bool {
|
||||
return strings.Compare(got[i].Name, got[j].Name) < 0
|
||||
})
|
||||
sort.Slice(want, func(i, j int) bool {
|
||||
return strings.Compare(want[i].Name, want[j].Name) < 0
|
||||
})
|
||||
assert.DeepEqual(t, got, want)
|
||||
}
|
||||
|
||||
func TestKubernetesProvider_InstanceGroups(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
ctx := t.Context()
|
||||
kind := setupKinD(t, ctx)
|
||||
p, err := kubernetes.NewKubernetesProvider(ctx, kind.client, slogt.New(t), config.NewProviderConfig().Kubernetes)
|
||||
assert.NilError(t, err)
|
||||
|
||||
d1, err := kind.CreateMimicDeployment(ctx, MimicOptions{
|
||||
Labels: map[string]string{
|
||||
"sablier.enable": "true",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
d2, err := kind.CreateMimicDeployment(ctx, MimicOptions{
|
||||
Labels: map[string]string{
|
||||
"sablier.enable": "true",
|
||||
"sablier.group": "my-group-1",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
ss1, err := kind.CreateMimicStatefulSet(ctx, MimicOptions{
|
||||
Labels: map[string]string{
|
||||
"sablier.enable": "true",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
ss2, err := kind.CreateMimicStatefulSet(ctx, MimicOptions{
|
||||
Labels: map[string]string{
|
||||
"sablier.enable": "true",
|
||||
"sablier.group": "my-group-2",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
got, err := p.InstanceGroups(ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
want := map[string][]string{
|
||||
"default": {
|
||||
kubernetes.DeploymentName(d1, kubernetes.ParseOptions{Delimiter: "_"}).Original,
|
||||
kubernetes.StatefulSetName(ss1, kubernetes.ParseOptions{Delimiter: "_"}).Original,
|
||||
},
|
||||
"my-group-1": {
|
||||
kubernetes.DeploymentName(d2, kubernetes.ParseOptions{Delimiter: "_"}).Original,
|
||||
},
|
||||
"my-group-2": {
|
||||
kubernetes.StatefulSetName(ss2, kubernetes.ParseOptions{Delimiter: "_"}).Original,
|
||||
},
|
||||
}
|
||||
assert.DeepEqual(t, got, want)
|
||||
}
|
||||
12
pkg/provider/kubernetes/instance_start.go
Normal file
12
pkg/provider/kubernetes/instance_start.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package kubernetes
|
||||
|
||||
import "context"
|
||||
|
||||
func (p *KubernetesProvider) InstanceStart(ctx context.Context, name string) error {
|
||||
parsed, err := ParseName(name, ParseOptions{Delimiter: p.delimiter})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.scale(ctx, parsed, parsed.Replicas)
|
||||
}
|
||||
114
pkg/provider/kubernetes/instance_start_test.go
Normal file
114
pkg/provider/kubernetes/instance_start_test.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package kubernetes_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/neilotoole/slogt"
|
||||
"github.com/sablierapp/sablier/config"
|
||||
"github.com/sablierapp/sablier/pkg/provider/kubernetes"
|
||||
"gotest.tools/v3/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKubernetesProvider_InstanceStart(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
type args struct {
|
||||
do func(kind *kindContainer) (string, error)
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "invalid name",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
return "invalid-name", nil
|
||||
},
|
||||
},
|
||||
err: fmt.Errorf("invalid name [invalid-name] should be: kind_namespace_name_replicas"),
|
||||
},
|
||||
{
|
||||
name: "non existing deployment start",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
return "deployment_default_my-deployment_1", nil
|
||||
},
|
||||
},
|
||||
err: fmt.Errorf("deployments/scale.apps \"my-deployment\" not found"),
|
||||
},
|
||||
{
|
||||
name: "deployment start as expected",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
d, err := kind.CreateMimicDeployment(ctx, MimicOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err = WaitForDeploymentReady(ctx, kind.client, d.Namespace, d.Name); err != nil {
|
||||
return "", fmt.Errorf("error waiting for deployment: %w", err)
|
||||
}
|
||||
|
||||
return kubernetes.DeploymentName(d, kubernetes.ParseOptions{Delimiter: "_"}).Original, nil
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "non existing statefulSet start",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
return "statefulset_default_my-statefulset_1", nil
|
||||
},
|
||||
},
|
||||
err: fmt.Errorf("statefulsets.apps \"my-statefulset\" not found"),
|
||||
},
|
||||
{
|
||||
name: "statefulSet start as expected",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
ss, err := kind.CreateMimicStatefulSet(ctx, MimicOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err = WaitForStatefulSetReady(ctx, kind.client, ss.Namespace, ss.Name); err != nil {
|
||||
return "", fmt.Errorf("error waiting for statefulSet: %w", err)
|
||||
}
|
||||
|
||||
return kubernetes.StatefulSetName(ss, kubernetes.ParseOptions{Delimiter: "_"}).Original, nil
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
kind := setupKinD(t, ctx)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
p, err := kubernetes.NewKubernetesProvider(ctx, kind.client, slogt.New(t), config.NewProviderConfig().Kubernetes)
|
||||
assert.NilError(t, err)
|
||||
|
||||
name, err := tt.args.do(kind)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = p.InstanceStart(t.Context(), name)
|
||||
if tt.err != nil {
|
||||
assert.Error(t, err, tt.err.Error())
|
||||
} else {
|
||||
assert.NilError(t, err)
|
||||
|
||||
status, err := p.InstanceInspect(t.Context(), name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, status.IsReady(), true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
12
pkg/provider/kubernetes/instance_stop.go
Normal file
12
pkg/provider/kubernetes/instance_stop.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package kubernetes
|
||||
|
||||
import "context"
|
||||
|
||||
func (p *KubernetesProvider) InstanceStop(ctx context.Context, name string) error {
|
||||
parsed, err := ParseName(name, ParseOptions{Delimiter: p.delimiter})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.scale(ctx, parsed, 0)
|
||||
}
|
||||
114
pkg/provider/kubernetes/instance_stop_test.go
Normal file
114
pkg/provider/kubernetes/instance_stop_test.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package kubernetes_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/neilotoole/slogt"
|
||||
"github.com/sablierapp/sablier/config"
|
||||
"github.com/sablierapp/sablier/pkg/provider/kubernetes"
|
||||
"gotest.tools/v3/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKubernetesProvider_InstanceStop(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
type args struct {
|
||||
do func(kind *kindContainer) (string, error)
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "invalid name",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
return "invalid-name", nil
|
||||
},
|
||||
},
|
||||
err: fmt.Errorf("invalid name [invalid-name] should be: kind_namespace_name_replicas"),
|
||||
},
|
||||
{
|
||||
name: "non existing deployment stop",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
return "deployment_default_my-deployment_1", nil
|
||||
},
|
||||
},
|
||||
err: fmt.Errorf("deployments/scale.apps \"my-deployment\" not found"),
|
||||
},
|
||||
{
|
||||
name: "deployment stop as expected",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
d, err := kind.CreateMimicDeployment(ctx, MimicOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err = WaitForDeploymentReady(ctx, kind.client, d.Namespace, d.Name); err != nil {
|
||||
return "", fmt.Errorf("error waiting for deployment: %w", err)
|
||||
}
|
||||
|
||||
return kubernetes.DeploymentName(d, kubernetes.ParseOptions{Delimiter: "_"}).Original, nil
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "non existing statefulSet stop",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
return "statefulset_default_my-statefulset_1", nil
|
||||
},
|
||||
},
|
||||
err: fmt.Errorf("statefulsets.apps \"my-statefulset\" not found"),
|
||||
},
|
||||
{
|
||||
name: "statefulSet stop as expected",
|
||||
args: args{
|
||||
do: func(kind *kindContainer) (string, error) {
|
||||
ss, err := kind.CreateMimicStatefulSet(ctx, MimicOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err = WaitForStatefulSetReady(ctx, kind.client, ss.Namespace, ss.Name); err != nil {
|
||||
return "", fmt.Errorf("error waiting for statefulSet: %w", err)
|
||||
}
|
||||
|
||||
return kubernetes.StatefulSetName(ss, kubernetes.ParseOptions{Delimiter: "_"}).Original, nil
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
kind := setupKinD(t, ctx)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
p, err := kubernetes.NewKubernetesProvider(ctx, kind.client, slogt.New(t), config.NewProviderConfig().Kubernetes)
|
||||
assert.NilError(t, err)
|
||||
|
||||
name, err := tt.args.do(kind)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = p.InstanceStop(t.Context(), name)
|
||||
if tt.err != nil {
|
||||
assert.Error(t, err, tt.err.Error())
|
||||
} else {
|
||||
assert.NilError(t, err)
|
||||
|
||||
status, err := p.InstanceInspect(t.Context(), name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, status.IsReady(), false)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,10 @@ package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/sablierapp/sablier/app/discovery"
|
||||
"github.com/sablierapp/sablier/pkg/provider"
|
||||
core_v1 "k8s.io/api/core/v1"
|
||||
"log/slog"
|
||||
|
||||
providerConfig "github.com/sablierapp/sablier/config"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
@@ -42,66 +39,3 @@ func NewKubernetesProvider(ctx context.Context, client *kubernetes.Clientset, lo
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (p *KubernetesProvider) InstanceStart(ctx context.Context, name string) error {
|
||||
parsed, err := ParseName(name, ParseOptions{Delimiter: p.delimiter})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.scale(ctx, parsed, parsed.Replicas)
|
||||
}
|
||||
|
||||
func (p *KubernetesProvider) InstanceStop(ctx context.Context, name string) error {
|
||||
parsed, err := ParseName(name, ParseOptions{Delimiter: p.delimiter})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.scale(ctx, parsed, 0)
|
||||
}
|
||||
|
||||
func (p *KubernetesProvider) InstanceGroups(ctx context.Context) (map[string][]string, error) {
|
||||
deployments, err := p.Client.AppsV1().Deployments(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
|
||||
LabelSelector: discovery.LabelEnable,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groups := make(map[string][]string)
|
||||
for _, deployment := range deployments.Items {
|
||||
groupName := deployment.Labels[discovery.LabelGroup]
|
||||
if len(groupName) == 0 {
|
||||
groupName = discovery.LabelGroupDefaultValue
|
||||
}
|
||||
|
||||
group := groups[groupName]
|
||||
parsed := DeploymentName(&deployment, ParseOptions{Delimiter: p.delimiter})
|
||||
group = append(group, parsed.Original)
|
||||
groups[groupName] = group
|
||||
}
|
||||
|
||||
statefulSets, err := p.Client.AppsV1().StatefulSets(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
|
||||
LabelSelector: discovery.LabelEnable,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, statefulSet := range statefulSets.Items {
|
||||
groupName := statefulSet.Labels[discovery.LabelGroup]
|
||||
if len(groupName) == 0 {
|
||||
groupName = discovery.LabelGroupDefaultValue
|
||||
}
|
||||
|
||||
group := groups[groupName]
|
||||
parsed := StatefulSetName(&statefulSet, ParseOptions{Delimiter: p.delimiter})
|
||||
group = append(group, parsed.Original)
|
||||
groups[groupName] = group
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ func (p *KubernetesProvider) watchStatefulSets(instance chan<- string) cache.Sha
|
||||
return
|
||||
}
|
||||
|
||||
if *oldStatefulSet.Spec.Replicas == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if *newStatefulSet.Spec.Replicas == 0 {
|
||||
parsed := StatefulSetName(newStatefulSet, ParseOptions{Delimiter: p.delimiter})
|
||||
instance <- parsed.Original
|
||||
|
||||
@@ -4,18 +4,20 @@ import (
|
||||
"context"
|
||||
"github.com/sablierapp/sablier/app/discovery"
|
||||
"github.com/sablierapp/sablier/app/types"
|
||||
"github.com/sablierapp/sablier/pkg/provider"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
core_v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (p *KubernetesProvider) StatefulSetList(ctx context.Context, options provider.InstanceListOptions) ([]types.Instance, error) {
|
||||
func (p *KubernetesProvider) StatefulSetList(ctx context.Context) ([]types.Instance, error) {
|
||||
labelSelector := metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
discovery.LabelEnable: "true",
|
||||
},
|
||||
}
|
||||
statefulSets, err := p.Client.AppsV1().StatefulSets(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
|
||||
LabelSelector: strings.Join(options.Labels, ","),
|
||||
LabelSelector: metav1.FormatLabelSelector(&labelSelector),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -47,3 +49,32 @@ func (p *KubernetesProvider) statefulSetToInstance(ss *v1.StatefulSet) types.Ins
|
||||
Group: group,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *KubernetesProvider) StatefulSetGroups(ctx context.Context) (map[string][]string, error) {
|
||||
labelSelector := metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
discovery.LabelEnable: "true",
|
||||
},
|
||||
}
|
||||
statefulSets, err := p.Client.AppsV1().StatefulSets(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
|
||||
LabelSelector: metav1.FormatLabelSelector(&labelSelector),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groups := make(map[string][]string)
|
||||
for _, ss := range statefulSets.Items {
|
||||
groupName := ss.Labels[discovery.LabelGroup]
|
||||
if len(groupName) == 0 {
|
||||
groupName = discovery.LabelGroupDefaultValue
|
||||
}
|
||||
|
||||
group := groups[groupName]
|
||||
parsed := StatefulSetName(&ss, ParseOptions{Delimiter: p.delimiter})
|
||||
group = append(group, parsed.Original)
|
||||
groups[groupName] = group
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package kubernetes_test
|
||||
@@ -42,12 +42,12 @@ func (d *kindContainer) CreateMimicDeployment(ctx context.Context, opts MimicOpt
|
||||
if opts.Labels == nil {
|
||||
opts.Labels = make(map[string]string)
|
||||
}
|
||||
opts.Labels["app"] = name
|
||||
d.t.Log("Creating mimic deployment with options", opts)
|
||||
d.t.Log("Creating mimic deployment with options", name, opts)
|
||||
replicas := int32(1)
|
||||
return d.client.AppsV1().Deployments("default").Create(ctx, &v1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: opts.Labels,
|
||||
},
|
||||
Spec: v1.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
@@ -68,7 +68,9 @@ func (d *kindContainer) CreateMimicDeployment(ctx context.Context, opts MimicOpt
|
||||
},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: opts.Labels,
|
||||
Labels: map[string]string{
|
||||
"app": name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -85,12 +87,12 @@ func (d *kindContainer) CreateMimicStatefulSet(ctx context.Context, opts MimicOp
|
||||
if opts.Labels == nil {
|
||||
opts.Labels = make(map[string]string)
|
||||
}
|
||||
opts.Labels["app"] = name
|
||||
d.t.Log("Creating mimic deployment with options", opts)
|
||||
d.t.Log("Creating mimic deployment with options", name, opts)
|
||||
replicas := int32(1)
|
||||
return d.client.AppsV1().StatefulSets("default").Create(ctx, &v1.StatefulSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: opts.Labels,
|
||||
},
|
||||
Spec: v1.StatefulSetSpec{
|
||||
Replicas: &replicas,
|
||||
@@ -111,7 +113,9 @@ func (d *kindContainer) CreateMimicStatefulSet(ctx context.Context, opts MimicOp
|
||||
},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: opts.Labels,
|
||||
Labels: map[string]string{
|
||||
"app": name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -121,7 +125,7 @@ func (d *kindContainer) CreateMimicStatefulSet(ctx context.Context, opts MimicOp
|
||||
func setupKinD(t *testing.T, ctx context.Context) *kindContainer {
|
||||
t.Helper()
|
||||
|
||||
kind, err := k3s.Run(ctx, "rancher/k3s:v1.27.1-k3s1")
|
||||
kind, err := k3s.Run(ctx, "rancher/k3s:v1.32.2-k3s1")
|
||||
testcontainers.CleanupContainer(t, kind)
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -162,7 +166,7 @@ func generateRandomName() string {
|
||||
}
|
||||
|
||||
func WaitForDeploymentReady(ctx context.Context, client kubernetes.Interface, namespace, name string) error {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
@@ -183,7 +187,7 @@ func WaitForDeploymentReady(ctx context.Context, client kubernetes.Interface, na
|
||||
}
|
||||
|
||||
func WaitForStatefulSetReady(ctx context.Context, client kubernetes.Interface, namespace, name string) error {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
@@ -204,7 +208,7 @@ func WaitForStatefulSetReady(ctx context.Context, client kubernetes.Interface, n
|
||||
}
|
||||
|
||||
func WaitForDeploymentScale(ctx context.Context, client kubernetes.Interface, namespace, name string, replicas int32) error {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
@@ -225,7 +229,7 @@ func WaitForDeploymentScale(ctx context.Context, client kubernetes.Interface, na
|
||||
}
|
||||
|
||||
func WaitForStatefulSetScale(ctx context.Context, client kubernetes.Interface, namespace, name string, replicas int32) error {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
|
||||
Reference in New Issue
Block a user