12 "github.com/containernetworking/cni/pkg/types"
13 "github.com/containernetworking/cni/pkg/version"
14 "github.com/sirupsen/logrus"
15 "github.com/urfave/cli"
16 gcfg "gopkg.in/gcfg.v1"
18 "k8s.io/client-go/kubernetes"
19 "k8s.io/client-go/rest"
20 "k8s.io/client-go/tools/clientcmd"
23 // The following are global config parameters that other modules may access directly
26 // Default holds parsed config file parameters and command-line overrides
27 Default = DefaultConfig{
31 // Logging holds logging-related parsed config file parameters and command-line overrides
32 Logging = LoggingConfig{
33 File: "", // do not log to a file by default
37 // CNI holds CNI-related parsed config file parameters and command-line overrides
39 ConfDir: "/etc/cni/net.d",
40 Plugin: "ovn4nfvk8s-cni",
43 // Kubernetes holds Kubernetes-related parsed config file parameters
44 Kubernetes = KubernetesConfig{}
47 // DefaultConfig holds parsed config file parameters and command-line overrides
48 type DefaultConfig struct {
49 // MTU value used for the overlay networks.
53 // LoggingConfig holds logging-related parsed config file parameters and command-line overrides
54 type LoggingConfig struct {
55 // File is the path of the file to log to
56 File string `gcfg:"logfile"`
57 // Level is the logging verbosity level
58 Level int `gcfg:"loglevel"`
61 // CNIConfig holds CNI-related parsed config file parameters and command-line overrides
62 type CNIConfig struct {
63 // ConfDir specifies the CNI config directory in which to write the overlay CNI config file
64 ConfDir string `gcfg:"conf-dir"`
65 // Plugin specifies the name of the CNI plugin
66 Plugin string `gcfg:"plugin"`
69 // KubernetesConfig holds Kubernetes-related parsed config file parameters and command-line overrides
70 type KubernetesConfig struct {
71 Kubeconfig string `gcfg:"kubeconfig"`
74 // Config is used to read the structured config file and to cache config in testcases
79 Kubernetes KubernetesConfig
82 // copy members of struct 'src' into the corresponding field in struct 'dst'
83 // if the field in 'src' is a non-zero int or a non-zero-length string. This
84 // function should be called with pointers to structs.
85 func overrideFields(dst, src interface{}) {
86 dstStruct := reflect.ValueOf(dst).Elem()
87 srcStruct := reflect.ValueOf(src).Elem()
88 if dstStruct.Kind() != srcStruct.Kind() || dstStruct.Kind() != reflect.Struct {
89 panic("mismatched value types")
91 if dstStruct.NumField() != srcStruct.NumField() {
92 panic("mismatched struct types")
95 for i := 0; i < dstStruct.NumField(); i++ {
96 dstField := dstStruct.Field(i)
97 srcField := srcStruct.Field(i)
98 if dstField.Kind() != srcField.Kind() {
99 panic("mismatched struct fields")
101 switch srcField.Kind() {
103 if srcField.String() != "" {
104 dstField.Set(srcField)
107 if srcField.Int() != 0 {
108 dstField.Set(srcField)
111 panic(fmt.Sprintf("unhandled struct field type: %v", srcField.Kind()))
118 // Flags are general command-line flags. Apps should add these flags to their
119 // own urfave/cli flags and call InitConfig() early in the application.
120 var Flags = []cli.Flag{
123 Usage: "configuration file path (default: /etc/openvswitch/ovn4nfv_k8s.conf)",
129 Usage: "MTU value used for the overlay networks (default: 1400)",
130 Destination: &cliConfig.Default.MTU,
136 Usage: "log verbosity and level: 5=debug, 4=info, 3=warn, 2=error, 1=fatal (default: 4)",
137 Destination: &cliConfig.Logging.Level,
141 Usage: "path of a file to direct log output to",
142 Destination: &cliConfig.Logging.File,
147 Name: "cni-conf-dir",
148 Usage: "the CNI config directory in which to write the overlay CNI config file (default: /etc/cni/net.d)",
149 Destination: &cliConfig.CNI.ConfDir,
153 Usage: "the name of the CNI plugin (default: ovn4nfvk8s-cni)",
154 Destination: &cliConfig.CNI.Plugin,
157 // Kubernetes-related options
159 Name: "k8s-kubeconfig",
160 Usage: "absolute path to the Kubernetes kubeconfig file",
161 Destination: &cliConfig.Kubernetes.Kubeconfig,
165 func buildKubernetesConfig(cli, file *config) error {
167 // Copy config file values over default values
168 overrideFields(&Kubernetes, &file.Kubernetes)
169 // And CLI overrides over config file and default values
170 overrideFields(&Kubernetes, &cli.Kubernetes)
172 if Kubernetes.Kubeconfig == "" || !pathExists(Kubernetes.Kubeconfig) {
173 return fmt.Errorf("kubernetes kubeconfig file %q not found", Kubernetes.Kubeconfig)
178 // getConfigFilePath returns config file path and 'true' if the config file is
179 // the fallback path (eg not given by the user), 'false' if given explicitly
181 func getConfigFilePath(ctx *cli.Context) (string, bool) {
182 configFile := ctx.String("config-file")
183 if configFile != "" {
184 return configFile, false
188 return filepath.Join("/etc", "openvswitch", "ovn4nfv_k8s.conf"), true
192 // InitConfig reads the config file and common command-line options and
193 // constructs the global config object from them. It returns the config file
194 // path (if explicitly specified) or an error
195 func InitConfig(ctx *cli.Context) (string, error) {
196 return InitConfigWithPath(ctx, "")
199 // InitConfigWithPath reads the given config file (or if empty, reads the config file
200 // specified by command-line arguments, or empty, the default config file) and
201 // common command-line options and constructs the global config object from
202 // them. It returns the config file path (if explicitly specified) or an error
203 func InitConfigWithPath(ctx *cli.Context, configFile string) (string, error) {
205 var retConfigFile string
206 var configFileIsDefault bool
208 // If no specific config file was given, try to find one from command-line
209 // arguments, or the platform-specific default config file path
210 if configFile == "" {
211 configFile, configFileIsDefault = getConfigFilePath(ctx)
214 logrus.SetOutput(os.Stderr)
216 if !configFileIsDefault {
217 // Only return explicitly specified config file
218 retConfigFile = configFile
221 f, err := os.Open(configFile)
222 // Failure to find a default config file is not a hard error
223 if err != nil && !configFileIsDefault {
224 return "", fmt.Errorf("failed to open config file %s: %v", configFile, err)
229 // Parse ovn4nfvk8s config file.
230 if err = gcfg.ReadInto(&cfg, f); err != nil {
231 return "", fmt.Errorf("failed to parse config file %s: %v", f.Name(), err)
233 logrus.Infof("Parsed config file %s", f.Name())
234 logrus.Infof("Parsed config: %+v", cfg)
237 // Build config that needs no special processing
238 overrideFields(&Default, &cfg.Default)
239 overrideFields(&Default, &cliConfig.Default)
240 overrideFields(&CNI, &cfg.CNI)
241 overrideFields(&CNI, &cliConfig.CNI)
244 overrideFields(&Logging, &cfg.Logging)
245 overrideFields(&Logging, &cliConfig.Logging)
246 logrus.SetLevel(logrus.Level(Logging.Level))
247 if Logging.File != "" {
249 file, err = os.OpenFile(Logging.File, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0660)
251 logrus.Errorf("failed to open logfile %s (%v). Ignoring..", Logging.File, err)
253 logrus.SetOutput(file)
257 if err = buildKubernetesConfig(&cliConfig, &cfg); err != nil {
260 logrus.Debugf("Default config: %+v", Default)
261 logrus.Debugf("Logging config: %+v", Logging)
262 logrus.Debugf("CNI config: %+v", CNI)
263 logrus.Debugf("Kubernetes config: %+v", Kubernetes)
265 return retConfigFile, nil
268 func pathExists(path string) bool {
269 _, err := os.Stat(path)
270 if err != nil && os.IsNotExist(err) {
276 // NewClientset creates a Kubernetes clientset
277 func NewClientset(conf *KubernetesConfig) (*kubernetes.Clientset, error) {
278 var kconfig *rest.Config
281 if conf.Kubeconfig != "" {
282 // uses the current context in kubeconfig
283 kconfig, err = clientcmd.BuildConfigFromFlags("", conf.Kubeconfig)
289 return kubernetes.NewForConfig(kconfig)
292 func ConfigureNetConf(bytes []byte) (*types.NetConf, error) {
293 conf := &types.NetConf{}
294 if err := json.Unmarshal(bytes, conf); err != nil {
295 return nil, fmt.Errorf("failed to load netconf: %v", err)
298 if conf.RawPrevResult != nil {
299 if err := version.ParsePrevResult(conf); err != nil {
306 func GetNodeIntfName(node string) string {
308 h.Write([]byte(node))
310 encodednodeStr := hex.EncodeToString(bs)
311 return fmt.Sprintf("ovn4nfv0-%s", encodednodeStr[:6])