forked from ligato/vpp-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vpp_flavor.go
139 lines (115 loc) · 4.6 KB
/
vpp_flavor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Package vpp defines the standard flavor used for full-featured VPP agents.
package vpp
import (
"github.com/ligato/cn-infra/core"
"github.com/ligato/cn-infra/datasync"
"github.com/ligato/cn-infra/datasync/msgsync"
"github.com/ligato/cn-infra/flavors/connectors"
"github.com/ligato/cn-infra/flavors/local"
"github.com/ligato/cn-infra/flavors/rpc"
"github.com/ligato/vpp-agent/plugins/defaultplugins"
"github.com/ligato/vpp-agent/plugins/govppmux"
"github.com/ligato/vpp-agent/plugins/linuxplugin"
"github.com/ligato/vpp-agent/plugins/restplugin"
)
// kafkaIfStateTopic is the topic where interface state changes are published.
const kafkaIfStateTopic = "if_state"
// NewAgent returns a new instance of the Agent with plugins.
// It is an alias for core.NewAgent() to implicit use of the FlavorVppLocal
func NewAgent(opts ...core.Option) *core.Agent {
return core.NewAgent(&Flavor{}, opts...)
}
// WithPlugins for adding custom plugins to SFC Controller.
// <listPlugins> is a callback that uses flavor input to
// inject dependencies for custom plugins that are in output.
//
// Example:
//
// NewAgent(vppFlavor.WithPlugins(func(flavor) {
// return []*core.NamedPlugin{{"my-plugin", &MyPlugin{DependencyXY: &flavor.FlavorXY}}}
// }))
func WithPlugins(listPlugins func(local *Flavor) []*core.NamedPlugin) core.WithPluginsOpt {
return &withPluginsOpt{listPlugins}
}
// Flavor glues together multiple plugins to build a full-featured VPP agent.
type Flavor struct {
*local.FlavorLocal
*connectors.AllConnectorsFlavor // connectors have to be started before vpp flavor
*rpc.FlavorRPC
// This can be reused later even for the Linux plugin,
// it has its own configuration.
IfStatePub msgsync.PubPlugin
GoVPP govppmux.GOVPPPlugin
Linux linuxplugin.Plugin
VPP defaultplugins.Plugin
RESTAPIPlugin restplugin.RESTAPIPlugin
injected bool
}
// Inject sets inter-plugin references.
func (f *Flavor) Inject() bool {
if f.injected {
return false
}
f.injected = true
f.injectEmbedded()
f.GoVPP.Deps.PluginInfraDeps = *f.FlavorLocal.InfraDeps("govpp", local.WithConf())
f.VPP.Deps.PluginInfraDeps = *f.FlavorLocal.InfraDeps("default-plugins", local.WithConf())
f.VPP.Deps.Linux = &f.Linux
f.VPP.Deps.GoVppmux = &f.GoVPP
f.VPP.Deps.Publish = &f.AllConnectorsFlavor.ETCDDataSync
f.VPP.Deps.PublishStatistics = &datasync.CompositeKVProtoWriter{Adapters: []datasync.KeyProtoValWriter{
&f.AllConnectorsFlavor.ETCDDataSync, &f.AllConnectorsFlavor.RedisDataSync},
}
f.IfStatePub.Messaging = &f.Kafka
f.IfStatePub.PluginInfraDeps = *f.InfraDeps("ifstate-pub")
// If needed, provide configuration using ifstate-pub-config.
// Set default configuration; it is overridable using ifstate-pub-config.
// Intent of not putting this configuration into the vpp plugin is that
// this way it is reusable even for the Linux plugin.
f.IfStatePub.Cfg.Topic = kafkaIfStateTopic
f.VPP.Deps.IfStatePub = &f.IfStatePub
f.VPP.Deps.Watch = &f.AllConnectorsFlavor.ETCDDataSync
f.Linux.Deps.PluginInfraDeps = *f.FlavorLocal.InfraDeps("linuxplugin", local.WithConf())
f.Linux.Deps.Watcher = &f.AllConnectorsFlavor.ETCDDataSync
f.RESTAPIPlugin.Deps.PluginInfraDeps = *f.FlavorLocal.InfraDeps("restapiplugin")
f.RESTAPIPlugin.Deps.HTTPHandlers = &f.FlavorRPC.HTTP
f.RESTAPIPlugin.Deps.GoVppmux = &f.GoVPP
return true
}
func (f *Flavor) injectEmbedded() {
if f.FlavorLocal == nil {
f.FlavorLocal = &local.FlavorLocal{}
}
f.FlavorLocal.Inject()
if f.FlavorRPC == nil {
f.FlavorRPC = &rpc.FlavorRPC{FlavorLocal: f.FlavorLocal}
}
f.FlavorRPC.Inject()
if f.AllConnectorsFlavor == nil {
f.AllConnectorsFlavor = &connectors.AllConnectorsFlavor{FlavorLocal: f.FlavorLocal}
}
f.AllConnectorsFlavor.Inject()
}
// Plugins combine all Plugins in the flavor to a list.
func (f *Flavor) Plugins() []*core.NamedPlugin {
f.Inject()
return core.ListPluginsInFlavor(f)
}
// withPluginsOpt is return value of vppLocal.WithPlugins() utility
// to easily define new plugins for the agent based on Flavor.
type withPluginsOpt struct {
callback func(local *Flavor) []*core.NamedPlugin
}
// OptionMarkerCore is just for marking implementation that it implements this interface
func (opt *withPluginsOpt) OptionMarkerCore() {}
// Plugins methods is here to implement core.WithPluginsOpt go interface
// <flavor> is a callback that uses flavor input for dependency injection
// for custom plugins (returned as NamedPlugin)
func (opt *withPluginsOpt) Plugins(flavors ...core.Flavor) []*core.NamedPlugin {
for _, flavor := range flavors {
if f, ok := flavor.(*Flavor); ok {
return opt.callback(f)
}
}
panic("wrong usage of vpp.WithPlugin() for other than Flavor")
}