Skip to content

Commit

Permalink
Predefined ConfigurableInterpreter
Browse files Browse the repository at this point in the history
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
  • Loading branch information
chaunceyjiang committed Nov 9, 2022
1 parent 31f97ac commit b639f25
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package predefinedconfigurableinterpreter

import (
"fmt"
"os"
"path/filepath"
"sync"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"

configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
"github.com/karmada-io/karmada/resourcecustomizations"
)

const configurableInterpreterFile = "customizations.lua"

// PredefinedConfigurableInterpreter interprets resources with build-in resource interpreter.
type PredefinedConfigurableInterpreter struct {
interpreters map[schema.GroupVersionKind]map[configv1alpha1.InterpreterOperation]string
lock sync.RWMutex
}

// HookEnabled tells if any hook exist for specific resource type and operation.
func (p *PredefinedConfigurableInterpreter) HookEnabled(objGVK schema.GroupVersionKind, operation configv1alpha1.InterpreterOperation) bool {
_, enabled := p.getInterpreter(objGVK, operation)
return enabled
}

// GetReplicas returns the desired replicas of the object as well as the requirements of each replica.
func (p *PredefinedConfigurableInterpreter) GetReplicas(object *unstructured.Unstructured) (replica int32, replicaRequires *workv1alpha2.ReplicaRequirements, err error) {
luaScript, exist := p.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretReplica)
if !exist {
return 0, &workv1alpha2.ReplicaRequirements{}, fmt.Errorf("predefined configurable %s interpreter for %q not found", configv1alpha1.InterpreterOperationInterpretReplica, object.GroupVersionKind())
}

_ = luaScript
// TODO
return 0, nil, nil
}

// ReviseReplica revises the replica of the given object.
func (p *PredefinedConfigurableInterpreter) ReviseReplica(object *unstructured.Unstructured, replica int64) (*unstructured.Unstructured, error) {
luaScript, exist := p.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationReviseReplica)
if !exist {
return nil, fmt.Errorf("predefined configurable %s interpreter for %q not found", configv1alpha1.InterpreterOperationReviseReplica, object.GroupVersionKind())
}

_ = luaScript
// TODO
return nil, nil
}

// Retain returns the objects that based on the "desired" object but with values retained from the "observed" object.
func (p *PredefinedConfigurableInterpreter) Retain(desired *unstructured.Unstructured, observed *unstructured.Unstructured) (retained *unstructured.Unstructured, err error) {
luaScript, exist := p.getInterpreter(desired.GroupVersionKind(), configv1alpha1.InterpreterOperationRetain)
if !exist {
return nil, fmt.Errorf("predefined configurable %s interpreter for %q not found", configv1alpha1.InterpreterOperationRetain, desired.GroupVersionKind())
}

_ = luaScript
// TODO
return nil, nil
}

// AggregateStatus returns the objects that based on the 'object' but with status aggregated.
func (p *PredefinedConfigurableInterpreter) AggregateStatus(object *unstructured.Unstructured, aggregatedStatusItems []workv1alpha2.AggregatedStatusItem) (*unstructured.Unstructured, error) {
luaScript, exist := p.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationAggregateStatus)
if !exist {
return nil, fmt.Errorf("predefined configurable %s interpreter for %q not found", configv1alpha1.InterpreterOperationAggregateStatus, object.GroupVersionKind())
}

_ = luaScript
// TODO
return nil, nil
}

// GetDependencies returns the dependent resources of the given object.
func (p *PredefinedConfigurableInterpreter) GetDependencies(object *unstructured.Unstructured) (dependencies []configv1alpha1.DependentObjectReference, err error) {
luaScript, exist := p.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretDependency)
if !exist {
return nil, fmt.Errorf("predefined configurable %s interpreter for operation %s not found", configv1alpha1.InterpreterOperationInterpretDependency, object.GroupVersionKind())
}

_ = luaScript
// TODO
return nil, nil
}

// ReflectStatus returns the status of the object.
func (p *PredefinedConfigurableInterpreter) ReflectStatus(object *unstructured.Unstructured) (status *runtime.RawExtension, err error) {
luaScript, exist := p.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretStatus)
if !exist {
return nil, fmt.Errorf("predefined configurable %s interpreter for operation %s not found", configv1alpha1.InterpreterOperationInterpretStatus, object.GroupVersionKind())
}

_ = luaScript
// TODO
return nil, nil
}

// InterpretHealth returns the health state of the object.
func (p *PredefinedConfigurableInterpreter) InterpretHealth(object *unstructured.Unstructured) (healthy bool, err error) {
luaScript, exist := p.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretHealth)
if !exist {
return false, fmt.Errorf("predefined configurable %s interpreter for %q not found", configv1alpha1.InterpreterOperationInterpretHealth, object.GroupVersionKind())
}

_ = luaScript
// TODO
return false, nil
}

/* directory structure
resource_customizations
├── embed.go
├── webapp.my.domain # Group
│ └── v1 # Version
│ └── Guestbook # Kind
│ ├── customizations.lua # Fixed name
│ ├── customizations_test.yaml
│ └── testdata
└── webapp2.my.domain
└── v1
└── Guestbook
├── customizations.lua
├── customizations_test.yaml
└── testdata
*/
func (p *PredefinedConfigurableInterpreter) getPredefinedLuaScripts(objKey string, scriptFile string) (string, error) {
data, err := resourcecustomizations.Embedded.ReadFile(filepath.Join(objKey, scriptFile))
if err != nil {
if os.IsNotExist(err) {
return "", nil
}
return "", err
}
return string(data), nil
}
func (p *PredefinedConfigurableInterpreter) getConfigMapKey(gvk schema.GroupVersionKind) string {
if gvk.Group == "" {
return gvk.Kind
}
return fmt.Sprintf("%s/%s/%s", gvk.Group, gvk.Version, gvk.Kind)
}

// getInterpreter returns interpreter for specific resource kind and operation.
func (p *PredefinedConfigurableInterpreter) getInterpreter(kind schema.GroupVersionKind, operation configv1alpha1.InterpreterOperation) (string, bool) {
p.lock.RLock()
interpreter, ok := p.interpreters[kind][operation]
p.lock.RUnlock()
if !ok {
luaScript, err := p.updateConfiguration(kind, operation)
if err != nil || luaScript == "" {
return "", false
}
interpreter, ok = luaScript, true
}
return interpreter, ok
}

func (p *PredefinedConfigurableInterpreter) updateConfiguration(kind schema.GroupVersionKind, operation configv1alpha1.InterpreterOperation) (string, error) {
key := p.getConfigMapKey(kind)
luaScript, err := p.getPredefinedLuaScripts(key, configurableInterpreterFile)
if err != nil {
return "", err
}
if luaScript == "" {
return "", nil
}
p.lock.Lock()
defer p.lock.Unlock()
p.interpreters[kind][operation] = luaScript

return luaScript, nil
}

// NewPredefinedConfigurableInterpreter return a new PredefinedConfigurableInterpreter.
func NewPredefinedConfigurableInterpreter() *PredefinedConfigurableInterpreter {
return &PredefinedConfigurableInterpreter{
interpreters: map[schema.GroupVersionKind]map[configv1alpha1.InterpreterOperation]string{},
}
}
9 changes: 9 additions & 0 deletions resourcecustomizations/embed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package resourcecustomizations

import (
"embed"
)

// Embedded contains embedded resource customization
//go:embed *
var Embedded embed.FS

0 comments on commit b639f25

Please sign in to comment.