Last active
April 10, 2019 07:32
-
-
Save serbrech/2bf2fa7404069fce65d25cf26cb23cbe to your computer and use it in GitHub Desktop.
go plugins using a visitor pattern
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
package main | |
import ( | |
"fmt" | |
) | |
// These interface define how core components can be visited by plugins | |
type AcceptNetworkPlugin interface { | |
Accept(plugin NetworkPlugin) | |
} | |
type AcceptKubeletPlugin interface { | |
Accept(plugin KubeletPlugin) | |
} | |
//------------- | |
//these interface determine the type of plugins that we allow for our system | |
type NetworkPlugin interface { | |
Apply(network *Network) | |
} | |
type KubeletPlugin interface { | |
Apply(kubelet *Kubelet) | |
} | |
//-------------- | |
//Our dummy system implementation | |
type NetworkSpec struct { | |
CIDR string | |
} | |
type Network struct { | |
Spec NetworkSpec | |
} | |
func (n *Network) Accept(plugin NetworkPlugin) { | |
plugin.Apply(n) | |
} | |
type KubeletSpec struct { | |
AllowPrivileged bool | |
} | |
type Kubelet struct { | |
Spec KubeletSpec | |
} | |
func (n *Kubelet) Accept(plugin KubeletPlugin) { | |
plugin.Apply(n) | |
} | |
//Maybe some aggregate? | |
type Cluster struct { | |
Kubelet | |
Network | |
} | |
//------------ | |
//The plugins, They implement the plugin interfaces provided by the system | |
type SpecialNetwork struct { | |
CIDROverride string | |
} | |
// Implements the Network plugin interface | |
func (n SpecialNetwork) Apply(network *Network) { | |
network.Spec.CIDR = n.CIDROverride | |
} | |
type PrivilegedKubelet struct {} | |
// Implements the Kubelet plugin interface | |
func (n PrivilegedKubelet) Apply(kubelet *Kubelet) { | |
kubelet.Spec.AllowPrivileged = true | |
} | |
//A program putting it all together, applying plugins | |
func main() { | |
//Setting up the default system | |
network := &Network{ Spec: NetworkSpec{ CIDR: "" }} | |
kubelet := &Kubelet{ Spec: KubeletSpec { }} | |
fmt.Println("Default system : ") | |
fmt.Println(network) | |
fmt.Println(kubelet) | |
//We provide the plugins to our system through some configuration | |
networkPlugin := SpecialNetwork{CIDROverride: "overriden!"} | |
kubeletPlugin := PrivilegedKubelet{} | |
//this is code that our pipeline calls while putting the configuration together. | |
// foreach componenet, find applicable plugins, apply accept them in order. Maybe interface should be Accept(Plugin p...) | |
//Note: a single plugin can implement both NetworkPlugin and KubeletPlugin and be applied to both. | |
//that allows to encapsulate the logic for a plugin that needs to change several area of our system | |
//without exposing that to our internal system. | |
network.Accept(networkPlugin) | |
kubelet.Accept(kubeletPlugin) | |
fmt.Println("\nAfter plugins") | |
fmt.Println(network) | |
fmt.Println(kubelet) | |
//Unfortunately, cluster.Accept(...) won't work if all components use the same Accept(...) method name to take plugins | |
//Although the method parameter are of different types (KubeletPlugin/NetworkPlugin) | |
//golang sees this the Accept call ambiguous, because it is the same method name on both embedded types | |
//may be solved with some clever code, some reflection maybe, hum... | |
//cluster := &Cluster{ | |
// Kubelet: &Kubelet{ Spec: KubeletSpec{ }}, | |
// Network: &Network{ Spec: NetworkSpec{ CIDR: "" }}, | |
//} | |
//cluster.Accept(pk) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment