generated from layer5io/layer5-repo-template
-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #258 from KiptoonKipkurui/feat/kiptoonkipkurui/mes…
…hsync_crd Meshync Dynamic Configuration from Meshsync
- Loading branch information
Showing
8 changed files
with
358 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
package config | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
|
||
"github.com/layer5io/meshkit/utils" | ||
"golang.org/x/exp/slices" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/client-go/dynamic" | ||
) | ||
|
||
var ( | ||
namespace = "meshery" // Namespace for the Custom Resource | ||
crName = "meshery-meshsync" // Name of the custom resource | ||
version = "v1alpha1" // Version of the Custom Resource | ||
group = "meshery.layer5.io" //Group for the Custom Resource | ||
resource = "meshsyncs" //Name of the Resource | ||
) | ||
|
||
func GetMeshsyncCRDConfigs(dyClient dynamic.Interface) (*MeshsyncConfig, error) { | ||
// initialize the group version resource to access the custom resource | ||
gvr := schema.GroupVersionResource{Version: version, Group: group, Resource: resource} | ||
|
||
// make a call to get the custom resource | ||
crd, err := dyClient.Resource(gvr).Namespace(namespace).Get(context.TODO(), crName, metav1.GetOptions{}) | ||
|
||
if err != nil { | ||
return nil, ErrInitConfig(err) | ||
} | ||
|
||
if crd == nil { | ||
return nil, ErrInitConfig(errors.New("Custom Resource is nil")) | ||
} | ||
|
||
spec := crd.Object["spec"] | ||
specMap, ok := spec.(map[string]interface{}) | ||
if !ok { | ||
return nil, ErrInitConfig(errors.New("Unable to convert spec to map")) | ||
} | ||
configObj := specMap["watch-list"] | ||
if configObj == nil { | ||
return nil, ErrInitConfig(errors.New("Custom Resource does not have Meshsync Configs")) | ||
} | ||
configStr, err := utils.Marshal(configObj) | ||
if err != nil { | ||
return nil, ErrInitConfig(err) | ||
} | ||
|
||
configMap := corev1.ConfigMap{} | ||
err = utils.Unmarshal(string(configStr), &configMap) | ||
|
||
if err != nil { | ||
return nil, ErrInitConfig(err) | ||
} | ||
|
||
// populate the required configs | ||
meshsyncConfig, err := PopulateConfigs(configMap) | ||
|
||
if err != nil { | ||
return nil, ErrInitConfig(err) | ||
} | ||
return meshsyncConfig, nil | ||
} | ||
|
||
// PopulateConfigs compares the default configs and the whitelist and blacklist | ||
func PopulateConfigs(configMap corev1.ConfigMap) (*MeshsyncConfig, error) { | ||
meshsyncConfig := &MeshsyncConfig{} | ||
|
||
if _, ok := configMap.Data["blacklist"]; ok { | ||
if len(configMap.Data["blacklist"]) > 0 { | ||
err := utils.Unmarshal(configMap.Data["blacklist"], &meshsyncConfig.BlackList) | ||
if err != nil { | ||
return nil, ErrInitConfig(err) | ||
} | ||
} | ||
} | ||
|
||
if _, ok := configMap.Data["whitelist"]; ok { | ||
if len(configMap.Data["whitelist"]) > 0 { | ||
err := utils.Unmarshal(configMap.Data["whitelist"], &meshsyncConfig.WhiteList) | ||
if err != nil { | ||
return nil, ErrInitConfig(err) | ||
} | ||
} | ||
} | ||
|
||
// ensure that atleast one of whitelist or blacklist has been supplied | ||
if len(meshsyncConfig.BlackList) == 0 && len(meshsyncConfig.WhiteList) == 0 { | ||
return nil, ErrInitConfig(errors.New("Both whitelisted and blacklisted resources missing")) | ||
} | ||
|
||
// ensure that only one of whitelist or blacklist has been supplied | ||
if len(meshsyncConfig.BlackList) != 0 && len(meshsyncConfig.WhiteList) != 0 { | ||
return nil, ErrInitConfig(errors.New("Both whitelisted and blacklisted resources not currently supported")) | ||
} | ||
|
||
// Handle global resources | ||
globalPipelines := make(PipelineConfigs, 0) | ||
localPipelines := make(PipelineConfigs, 0) | ||
|
||
if len(meshsyncConfig.WhiteList) != 0 { | ||
for _, v := range Pipelines[GlobalResourceKey] { | ||
if idx := slices.IndexFunc(meshsyncConfig.WhiteList, func(c ResourceConfig) bool { return c.Resource == v.Name }); idx != -1 { | ||
config := meshsyncConfig.WhiteList[idx] | ||
v.Events = config.Events | ||
globalPipelines = append(globalPipelines, v) | ||
} | ||
} | ||
if len(globalPipelines) > 0 { | ||
meshsyncConfig.Pipelines = map[string]PipelineConfigs{} | ||
meshsyncConfig.Pipelines[GlobalResourceKey] = globalPipelines | ||
} | ||
|
||
// Handle local resources | ||
for _, v := range Pipelines[LocalResourceKey] { | ||
if idx := slices.IndexFunc(meshsyncConfig.WhiteList, func(c ResourceConfig) bool { return c.Resource == v.Name }); idx != -1 { | ||
config := meshsyncConfig.WhiteList[idx] | ||
v.Events = config.Events | ||
localPipelines = append(localPipelines, v) | ||
} | ||
} | ||
|
||
if len(localPipelines) > 0 { | ||
if meshsyncConfig.Pipelines == nil { | ||
meshsyncConfig.Pipelines = make(map[string]PipelineConfigs) | ||
} | ||
meshsyncConfig.Pipelines[LocalResourceKey] = localPipelines | ||
} | ||
|
||
} else { | ||
|
||
for _, v := range Pipelines[GlobalResourceKey] { | ||
if idx := slices.IndexFunc(meshsyncConfig.BlackList, func(c string) bool { return c == v.Name }); idx == -1 { | ||
v.Events = DefaultEvents | ||
globalPipelines = append(globalPipelines, v) | ||
} | ||
} | ||
if len(globalPipelines) > 0 { | ||
meshsyncConfig.Pipelines = map[string]PipelineConfigs{} | ||
meshsyncConfig.Pipelines[GlobalResourceKey] = globalPipelines | ||
} | ||
|
||
// Handle local resources | ||
for _, v := range Pipelines[LocalResourceKey] { | ||
if idx := slices.IndexFunc(meshsyncConfig.BlackList, func(c string) bool { return c == v.Name }); idx == -1 { | ||
v.Events = DefaultEvents | ||
localPipelines = append(localPipelines, v) | ||
} | ||
} | ||
|
||
if len(localPipelines) > 0 { | ||
if meshsyncConfig.Pipelines == nil { | ||
meshsyncConfig.Pipelines = make(map[string]PipelineConfigs) | ||
} | ||
meshsyncConfig.Pipelines[LocalResourceKey] = localPipelines | ||
} | ||
} | ||
|
||
return meshsyncConfig, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package config | ||
|
||
// test for empty blacklist/whitelist | ||
import ( | ||
"context" | ||
"reflect" | ||
"testing" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/dynamic/fake" | ||
) | ||
|
||
var ( | ||
Kind string = "MeshSync" | ||
APIVersion string = "meshery.layer5.io/v1alpha1" | ||
URL string = "https://layer5.io" | ||
fakeDyClient *fake.FakeDynamicClient | ||
ctx = context.Background() | ||
) | ||
|
||
func TestWhiteListResources(t *testing.T) { | ||
|
||
// Create an instance of the custom resource. | ||
watchList := corev1.ConfigMap{ | ||
TypeMeta: metav1.TypeMeta{ | ||
APIVersion: "v1apha1", | ||
Kind: "ConfigMap", | ||
}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "watch-list", | ||
Namespace: "default", | ||
}, | ||
Data: map[string]string{ | ||
"blacklist": "", | ||
"whitelist": "[{\"Resource\":\"namespaces.v1.\",\"Events\":[\"ADDED\",\"DELETE\"]},{\"Resource\":\"replicasets.v1.apps\",\"Events\":[\"ADDED\",\"DELETE\"]},{\"Resource\":\"pods.v1.\",\"Events\":[\"MODIFIED\"]}]", | ||
}, | ||
} | ||
|
||
meshsyncConfig, err := PopulateConfigs(watchList) | ||
|
||
if err != nil { | ||
t.Errorf("Meshsync config not well deserialized got %s", err.Error()) | ||
} | ||
|
||
if len(meshsyncConfig.WhiteList) == 0 { | ||
t.Errorf("WhiteListed resources not correctly deserialized") | ||
} | ||
expectedWhiteList := []ResourceConfig{ | ||
{Resource: "namespaces.v1.", Events: []string{"ADDED", "DELETE"}}, | ||
{Resource: "replicasets.v1.apps", Events: []string{"ADDED", "DELETE"}}, | ||
{Resource: "pods.v1.", Events: []string{"MODIFIED"}}, | ||
} | ||
|
||
if !reflect.DeepEqual(meshsyncConfig.WhiteList, expectedWhiteList) { | ||
t.Error("WhiteListed resources not equal") | ||
} | ||
|
||
// now we assertain the global and local pipelines have been correctly configured | ||
// global pipelines: namespaces | ||
// local pipelines: pods, replicasets | ||
|
||
if len(meshsyncConfig.Pipelines["global"]) != 1 { | ||
t.Error("global pipelines not well configured expected 1") | ||
} | ||
|
||
if len(meshsyncConfig.Pipelines["local"]) != 2 { | ||
t.Error("global pipelines not well configured expected 2") | ||
} | ||
} | ||
|
||
func TestBlackListResources(t *testing.T) { | ||
|
||
// Create an instance of the custom resource. | ||
watchList := corev1.ConfigMap{ | ||
TypeMeta: metav1.TypeMeta{ | ||
APIVersion: "v1apha1", | ||
Kind: "ConfigMap", | ||
}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "watch-list", | ||
Namespace: "default", | ||
}, | ||
Data: map[string]string{ | ||
"blacklist": "[\"namespaces.v1.\",\"pods.v1.\"]", | ||
"whitelist": "", | ||
}, | ||
} | ||
|
||
meshsyncConfig, err := PopulateConfigs(watchList) | ||
|
||
if err != nil { | ||
t.Errorf("Meshsync config not well deserialized got %s", err.Error()) | ||
} | ||
|
||
if len(meshsyncConfig.BlackList) == 0 { | ||
t.Errorf("WhiteListed resources") | ||
} | ||
|
||
expectedBlackList := []string{"namespaces.v1.", "pods.v1."} | ||
if !reflect.DeepEqual(meshsyncConfig.BlackList, expectedBlackList) { | ||
t.Error("WhiteListed resources not equal") | ||
} | ||
|
||
// now we assertain the global and local pipelines have been correctly configured | ||
// excempted global pipelines: namespaces | ||
// excempted local pipelines: pods, replicasets | ||
|
||
if len(meshsyncConfig.Pipelines["global"]) != 5 { | ||
t.Error("global pipelines not well configured expected 5") | ||
} | ||
|
||
if len(meshsyncConfig.Pipelines["local"]) != 14 { | ||
t.Error("global pipelines not well configured expected 15") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,4 +144,6 @@ var ( | |
SubscribeTo: "meshery.meshsync.request", | ||
}, | ||
} | ||
|
||
DefaultEvents = []string{"ADD", "UPDATE", "DELETE"} | ||
) |
Oops, something went wrong.