fix(kubernetes): support public labels

closes #449
This commit is contained in:
Alexis Couvreur
2024-11-16 23:13:14 -05:00
parent 2976392078
commit ad5d66e614
10 changed files with 83 additions and 74 deletions

View File

@@ -15,16 +15,13 @@ import (
func StopAllUnregisteredInstances(ctx context.Context, provider providers.Provider, registered []string) error {
log.Info("Stopping all unregistered running instances")
log.Tracef("Retrieving all instances with label [%v=true]", LabelEnable)
instances, err := provider.InstanceList(ctx, providers.InstanceListOptions{
All: false, // Only running containers
Labels: []string{LabelEnable},
})
log.Trace("Retrieving all registered instances")
instances, err := provider.List(ctx)
if err != nil {
return err
}
log.Tracef("Found %v instances with label [%v=true]", len(instances), LabelEnable)
log.Tracef("Found %v instances", len(instances))
names := make([]string, 0, len(instances))
for _, instance := range instances {
names = append(names, instance.Name)

View File

@@ -4,7 +4,6 @@ import (
"context"
"errors"
"github.com/sablierapp/sablier/app/discovery"
"github.com/sablierapp/sablier/app/providers"
"github.com/sablierapp/sablier/app/providers/mock"
"github.com/sablierapp/sablier/app/types"
"testing"
@@ -22,11 +21,8 @@ func TestStopAllUnregisteredInstances(t *testing.T) {
}
registered := []string{"instance1"}
// Set up expectations for InstanceList
mockProvider.On("InstanceList", ctx, providers.InstanceListOptions{
All: false,
Labels: []string{discovery.LabelEnable},
}).Return(instances, nil)
// Set up expectations for List
mockProvider.On("List", ctx).Return(instances, nil)
// Set up expectations for Stop
mockProvider.On("Stop", ctx, "instance2").Return(nil)
@@ -54,11 +50,8 @@ func TestStopAllUnregisteredInstances_WithError(t *testing.T) {
}
registered := []string{"instance1"}
// Set up expectations for InstanceList
mockProvider.On("InstanceList", ctx, providers.InstanceListOptions{
All: false,
Labels: []string{discovery.LabelEnable},
}).Return(instances, nil)
// Set up expectations for List
mockProvider.On("List", ctx).Return(instances, nil)
// Set up expectations for Stop with error
mockProvider.On("Stop", ctx, "instance2").Return(errors.New("stop error"))

View File

@@ -7,20 +7,16 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/sablierapp/sablier/app/discovery"
"github.com/sablierapp/sablier/app/providers"
"github.com/sablierapp/sablier/app/types"
"strings"
)
func (provider *DockerClassicProvider) InstanceList(ctx context.Context, options providers.InstanceListOptions) ([]types.Instance, error) {
func (provider *DockerClassicProvider) List(ctx context.Context) ([]types.Instance, error) {
args := filters.NewArgs()
for _, label := range options.Labels {
args.Add("label", label)
args.Add("label", fmt.Sprintf("%s=true", label))
}
args.Add("label", fmt.Sprintf("%s=true", discovery.LabelEnable))
containers, err := provider.Client.ContainerList(ctx, container.ListOptions{
All: options.All,
All: true,
Filters: args,
})

View File

@@ -7,18 +7,14 @@ import (
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"github.com/sablierapp/sablier/app/discovery"
"github.com/sablierapp/sablier/app/providers"
"github.com/sablierapp/sablier/app/types"
log "github.com/sirupsen/logrus"
"strconv"
)
func (provider *DockerSwarmProvider) InstanceList(ctx context.Context, options providers.InstanceListOptions) ([]types.Instance, error) {
func (provider *DockerSwarmProvider) List(ctx context.Context) ([]types.Instance, error) {
args := filters.NewArgs()
for _, label := range options.Labels {
args.Add("label", label)
args.Add("label", fmt.Sprintf("%s=true", label))
}
args.Add("label", fmt.Sprintf("%s=true", discovery.LabelEnable))
services, err := provider.Client.ServiceList(ctx, dockertypes.ServiceListOptions{
Filters: args,

View File

@@ -3,23 +3,31 @@ package kubernetes
import (
"context"
"github.com/sablierapp/sablier/app/discovery"
"github.com/sablierapp/sablier/app/providers"
"github.com/sablierapp/sablier/app/types"
log "github.com/sirupsen/logrus"
v1 "k8s.io/api/apps/v1"
core_v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"strconv"
"strings"
)
func (provider *KubernetesProvider) InstanceList(ctx context.Context, options providers.InstanceListOptions) ([]types.Instance, error) {
deployments, err := provider.deploymentList(ctx, options)
const (
LabelEnable = "sablierapp.dev/enable"
LabelGroup = "sablierapp.dev/group"
LabelGroupDefaultValue = "default"
LabelReplicas = "sablierapp.dev/replicas"
LabelReplicasDefaultValue uint64 = 1
)
func (provider *KubernetesProvider) List(ctx context.Context) ([]types.Instance, error) {
deployments, err := provider.deploymentList(ctx)
if err != nil {
return nil, err
}
statefulSets, err := provider.statefulSetList(ctx, options)
statefulSets, err := provider.statefulSetList(ctx)
if err != nil {
return nil, err
}
@@ -27,9 +35,19 @@ func (provider *KubernetesProvider) InstanceList(ctx context.Context, options pr
return append(deployments, statefulSets...), nil
}
func (provider *KubernetesProvider) deploymentList(ctx context.Context, options providers.InstanceListOptions) ([]types.Instance, error) {
func (provider *KubernetesProvider) deploymentList(ctx context.Context) ([]types.Instance, error) {
requirement, err := labels.NewRequirement(LabelEnable, selection.Equals, []string{"true"})
if err != nil {
return nil, err
}
requirementDeprecated, err := labels.NewRequirement(discovery.LabelEnable, selection.Equals, []string{"true"})
if err != nil {
return nil, err
}
selector := labels.NewSelector()
selector = selector.Add(*requirement, *requirementDeprecated)
deployments, err := provider.Client.AppsV1().Deployments(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
LabelSelector: strings.Join(options.Labels, ","),
LabelSelector: selector.String(),
})
if err != nil {
@@ -49,23 +67,23 @@ func (provider *KubernetesProvider) deploymentToInstance(d v1.Deployment) types.
var group string
var replicas uint64
if _, ok := d.Labels[discovery.LabelEnable]; ok {
if g, ok := d.Labels[discovery.LabelGroup]; ok {
if _, ok := d.Labels[LabelEnable]; ok {
if g, ok := d.Labels[LabelGroup]; ok {
group = g
} else {
group = discovery.LabelGroupDefaultValue
group = LabelGroupDefaultValue
}
if r, ok := d.Labels[discovery.LabelReplicas]; ok {
if r, ok := d.Labels[LabelReplicas]; ok {
atoi, err := strconv.Atoi(r)
if err != nil {
log.Warnf("Defaulting to default replicas value, could not convert value \"%v\" to int: %v", r, err)
replicas = discovery.LabelReplicasDefaultValue
replicas = LabelReplicasDefaultValue
} else {
replicas = uint64(atoi)
}
} else {
replicas = discovery.LabelReplicasDefaultValue
replicas = LabelReplicasDefaultValue
}
}
@@ -82,9 +100,19 @@ func (provider *KubernetesProvider) deploymentToInstance(d v1.Deployment) types.
}
}
func (provider *KubernetesProvider) statefulSetList(ctx context.Context, options providers.InstanceListOptions) ([]types.Instance, error) {
func (provider *KubernetesProvider) statefulSetList(ctx context.Context) ([]types.Instance, error) {
requirement, err := labels.NewRequirement(LabelEnable, selection.Equals, []string{"true"})
if err != nil {
return nil, err
}
requirementDeprecated, err := labels.NewRequirement(discovery.LabelEnable, selection.Equals, []string{"true"})
if err != nil {
return nil, err
}
selector := labels.NewSelector()
selector = selector.Add(*requirement, *requirementDeprecated)
statefulSets, err := provider.Client.AppsV1().StatefulSets(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
LabelSelector: strings.Join(options.Labels, ","),
LabelSelector: selector.String(),
})
if err != nil {
@@ -104,23 +132,23 @@ func (provider *KubernetesProvider) statefulSetToInstance(ss v1.StatefulSet) typ
var group string
var replicas uint64
if _, ok := ss.Labels[discovery.LabelEnable]; ok {
if g, ok := ss.Labels[discovery.LabelGroup]; ok {
if _, ok := ss.Labels[LabelEnable]; ok {
if g, ok := ss.Labels[LabelGroup]; ok {
group = g
} else {
group = discovery.LabelGroupDefaultValue
group = LabelGroupDefaultValue
}
if r, ok := ss.Labels[discovery.LabelReplicas]; ok {
if r, ok := ss.Labels[LabelReplicas]; ok {
atoi, err := strconv.Atoi(r)
if err != nil {
log.Warnf("Defaulting to default replicas value, could not convert value \"%v\" to int: %v", r, err)
replicas = discovery.LabelReplicasDefaultValue
replicas = LabelReplicasDefaultValue
} else {
replicas = uint64(atoi)
}
} else {
replicas = discovery.LabelReplicasDefaultValue
replicas = LabelReplicasDefaultValue
}
}

View File

@@ -32,8 +32,8 @@ func (m *ProviderMock) GetGroups(ctx context.Context) (map[string][]string, erro
args := m.Called(ctx)
return args.Get(0).(map[string][]string), args.Error(1)
}
func (m *ProviderMock) InstanceList(ctx context.Context, options providers.InstanceListOptions) ([]types.Instance, error) {
args := m.Called(ctx, options)
func (m *ProviderMock) List(ctx context.Context) ([]types.Instance, error) {
args := m.Called(ctx)
return args.Get(0).([]types.Instance), args.Error(1)
}

View File

@@ -12,7 +12,7 @@ type Provider interface {
Stop(ctx context.Context, name string) error
GetState(ctx context.Context, name string) (instance.State, error)
GetGroups(ctx context.Context) (map[string][]string, error)
InstanceList(ctx context.Context, options InstanceListOptions) ([]types.Instance, error)
List(ctx context.Context) ([]types.Instance, error)
NotifyInstanceStopped(ctx context.Context, instance chan<- string)
}

View File

@@ -1,6 +1,5 @@
package providers
type InstanceListOptions struct {
All bool
Labels []string
All bool
}

View File

@@ -74,17 +74,17 @@ kind: Deployment
metadata:
name: whoami
labels:
app: whoami
sablier.enable: "true"
sablier.group: mygroup
app.kubernetes.io/name: whoami
sablierapp.dev/enable: "true"
sablierapp.dev/group: mygroup
spec:
selector:
matchLabels:
app: whoami
app.kubernetes.io/name: whoami
template:
metadata:
labels:
app: whoami
app.kubernetes.io/name: whoami
spec:
containers:
- name: whoami

View File

@@ -1,20 +1,20 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami-deployment
name: whoami
labels:
app: whoami
sablier.enable: "true"
sablier.group: "E2E"
app.kubernetes.io/name: whoami
sablierapp.dev/enable: "true"
sablierapp.dev/group: "E2E"
spec:
replicas: 0
selector:
matchLabels:
app: whoami
app.kubernetes.io/name: whoami
template:
metadata:
labels:
app: whoami
app.kubernetes.io/name: whoami
spec:
containers:
- name: whoami
@@ -36,7 +36,7 @@ spec:
targetPort: 80
port: 80
selector:
app: whoami
app.kubernetes.io/name: whoami
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
@@ -160,18 +160,18 @@ kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
sablier.enable: "true"
sablier.group: "E2E"
app.kubernetes.io/name: nginx
sablierapp.dev/enable: "true"
sablierapp.dev/group: "E2E"
spec:
replicas: 0
selector:
matchLabels:
app: nginx
app.kubernetes.io/name: nginx
template:
metadata:
labels:
app: nginx
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
@@ -195,7 +195,7 @@ spec:
targetPort: 80
port: 80
selector:
app: nginx
app.kubernetes.io/name: nginx
---
apiVersion: traefik.io/v1alpha1
kind: Middleware