feat(host): support netplan configuration

This commit is contained in:
Zexi Li
2021-06-23 10:08:09 +08:00
parent 9766509e3e
commit 02e57f7e8f
5 changed files with 500 additions and 1 deletions
+31 -1
View File
@@ -536,6 +536,14 @@ func (d *sDebianLikeRootFs) PrepareFsForTemplate(rootFs IDiskPartition) error {
return errors.Wrap(err, "file put content /etc/network/interface")
}
}
// clean /etc/netplan/*
netplanDir := "/etc/netplan/"
if rootFs.Exists(netplanDir, false) {
for _, f := range rootFs.ListDir(netplanDir, false) {
rootFs.Remove(netplanDir+f, false)
}
}
return nil
}
@@ -577,6 +585,16 @@ func getNicTeamingConfigCmds(slaves []*types.SServerNic) string {
return cmds.String()
}
func (d *sDebianLikeRootFs) deployNetplanConfigFile(rootFs IDiskPartition, nics []*types.SServerNic) error {
netplanDir := "/etc/netplan/"
dirExists := rootFs.Exists(netplanDir, false)
if !dirExists {
return nil
}
return nil
}
func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
if err := d.sLinuxRootFs.DeployNetworkingScripts(rootFs, nics); err != nil {
return err
@@ -587,7 +605,19 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
cmds.WriteString("iface lo inet loopback\n\n")
// ToServerNics(nics)
allNics, _ := convertNicConfigs(nics)
allNics, bondNics := convertNicConfigs(nics)
netplanDir := "/etc/netplan"
if rootFs.Exists(netplanDir, false) {
for _, f := range rootFs.ListDir(netplanDir, false) {
rootFs.Remove(netplanDir+f, false)
}
netplanConfig := NewNetplanConfig(allNics, bondNics)
if err := rootFs.FilePutContents(path.Join(netplanDir, "config.yaml"), netplanConfig.YAMLString(), false, false); err != nil {
return errors.Wrap(err, "Put netplan config")
}
}
mainNic, err := getMainNic(allNics)
if err != nil {
return err
+125
View File
@@ -0,0 +1,125 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fsdriver
import (
"fmt"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/util/netplan"
"yunion.io/x/onecloud/pkg/util/netutils2"
)
func NewNetplanConfig(allNics []*types.SServerNic, bondNics []*types.SServerNic) *netplan.Configuration {
network := newNetplanNetwork(allNics, bondNics)
return netplan.NewConfiguration(network)
}
func newNetplanNetwork(allNics []*types.SServerNic, bondNics []*types.SServerNic) *netplan.Network {
network := netplan.NewNetwork()
for _, nic := range allNics {
nicConf := getNetplanEthernetConfig(nic, false)
if nicConf == nil {
continue
}
network.AddEthernet(nic.Name, nicConf)
}
for _, bondNic := range bondNics {
if len(bondNic.TeamingSlaves) < 2 {
log.Warningf("BondNic %s slaves nic %#v less than 2", bondNic.Name, bondNic.TeamingSlaves)
continue
}
var defaultMtu = 1442
interfaces := make([]string, len(bondNic.TeamingSlaves))
for i, sn := range bondNic.TeamingSlaves {
interfaces[i] = sn.Name
nicConf := &netplan.EthernetConfig{
DHCP4: false,
MacAddress: sn.Mac,
Match: netplan.NewEthernetConfigMatchMac(sn.Mac),
}
if sn.Mtu > 0 {
nicConf.Mtu = sn.Mtu
} else {
nicConf.Mtu = defaultMtu
}
network.AddEthernet(sn.Name, nicConf)
}
primaryNic := bondNic.TeamingSlaves[0]
netConf := getNetplanEthernetConfig(primaryNic, true)
netConf.MacAddress = primaryNic.Mac
if netConf.Mtu == 0 {
netConf.Mtu = defaultMtu
}
// TODO: implement kinds of bond mode config
// bondConf := netplan.NewBondMode4(netConf, interfaces)
bondConf := netplan.NewBondMode1(netConf, interfaces)
network.AddBond(bondNic.Name, bondConf)
}
return network
}
func getNetplanEthernetConfig(nic *types.SServerNic, isBond bool) *netplan.EthernetConfig {
var nicConf *netplan.EthernetConfig
if !isBond && (nic.TeamingMaster != nil || nic.TeamingSlaves != nil) {
return nil
} else if nic.Virtual {
addr := fmt.Sprintf("%s/32", netutils2.PSEUDO_VIP)
nicConf = netplan.NewStaticEthernetConfig(addr, "", nil, nil, nil)
} else if nic.Manual {
addr := fmt.Sprintf("%s/%d", nic.Ip, nic.Masklen)
gateway := nic.Gateway
var routes []*netplan.Route
for _, route := range nic.Routes {
routes = append(routes, &netplan.Route{
To: route[0],
Via: route[1],
})
}
nicConf = netplan.NewStaticEthernetConfig(
addr, gateway,
[]string{nic.Domain},
netutils2.GetNicDns(nic),
routes,
)
if nic.Mtu > 0 {
nicConf.Mtu = nic.Mtu
}
} else {
// dhcp
nicConf = netplan.NewDHCP4EthernetConfig()
}
return nicConf
}
+1
View File
@@ -0,0 +1 @@
package netplan // import "yunion.io/x/onecloud/pkg/util/netplan"
+242
View File
@@ -0,0 +1,242 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package netplan
import "yunion.io/x/jsonutils"
// Configuration examples reference from https://netplan.io/examples/
// manpage: http://manpages.ubuntu.com/manpages/cosmic/man5/netplan.5.html
type Configuration struct {
Network *Network `json:"network"`
}
func NewConfiguration(network *Network) *Configuration {
return &Configuration{
Network: network,
}
}
func (c *Configuration) YAMLString() string {
return toYAMLString(c)
}
type NetworkRenderer string
const (
VERSION2 = 2
NetworkRendererNetworkd NetworkRenderer = "networkd"
)
type Network struct {
Version uint `json:"version"`
Renderer NetworkRenderer `json:"renderer"`
Ethernets map[string]*EthernetConfig `json:"ethernets"`
Bonds map[string]*Bond `json:"bonds"`
}
type EthernetConfigMatch struct {
MacAddress string `json:"macaddress"`
}
func NewEthernetConfigMatchMac(macAddr string) *EthernetConfigMatch {
return &EthernetConfigMatch{
MacAddress: macAddr,
}
}
type EthernetConfig struct {
DHCP4 bool `json:"dhcp4"`
Addresses []string `json:"addresses"`
Match *EthernetConfigMatch `json:"match"`
MacAddress string `json:"macaddress"`
Gateway4 string `json:"gateway4"`
Routes []*Route `json:"routes"`
Nameservers *Nameservers `json:"nameservers"`
Mtu int `json:"mtu,omitzero"`
}
type Route struct {
To string `json:"to"`
Via string `json:"via"`
Metric uint `json:"metric"`
// OnLink bool `json:"on-link"`
}
type Nameservers struct {
Search []string `json:"search"`
Addresses []string `json:"addresses"`
}
type Bond struct {
EthernetConfig
Interfaces []string `json:"interfaces"`
Parameters IBondModeParams `json:"parameters"`
}
func toYAMLString(obj interface{}) string {
return jsonutils.Marshal(obj).YAMLString()
}
func (b *Bond) YAMLString() string {
return toYAMLString(b)
}
type BondMode string
const (
// ref: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/networking_guide/overview-of-bonding-modes-and-the-required-settings-on-the-switch
// mode0
bondModeBalanceRR = "balance-rr"
// mode1
bondModeActiveBackup = "active-backup"
// mode4
bondMode8023AD = "802.3ad"
)
type IBondModeParams interface {
GetMode() string
}
type BondModeBaseParams struct {
Mode string `json:"mode"`
MiiMonitorInterval int `json:"mii-monitor-interval,omitzero"`
GratuitiousArp int `json:"gratuitiousi-arp,omitzero"`
}
func (c BondModeBaseParams) GetMode() string {
return c.Mode
}
func (c *BondModeBaseParams) SetMiiMonitorInterval(i int) {
c.MiiMonitorInterval = i
}
func (c *BondModeBaseParams) SetGratutiousArp(g int) {
c.GratuitiousArp = g
}
type BondModeActiveBackupParams struct {
*BondModeBaseParams
Primary string `json:"primary"`
}
func NewBondMode0Params() *BondModeBaseParams {
return &BondModeBaseParams{
Mode: bondModeBalanceRR,
}
}
func NewBondModeActiveBackupParams(primary string) *BondModeActiveBackupParams {
return &BondModeActiveBackupParams{
BondModeBaseParams: &BondModeBaseParams{
Mode: bondModeActiveBackup,
},
Primary: primary,
}
}
type BondMode4Params struct {
*BondModeBaseParams
}
func NewBondMode4Params() *BondMode4Params {
return &BondMode4Params{
BondModeBaseParams: &BondModeBaseParams{
Mode: bondMode8023AD,
},
}
}
func NewNetwork() *Network {
return &Network{
Version: VERSION2,
Renderer: NetworkRendererNetworkd,
Ethernets: make(map[string]*EthernetConfig),
Bonds: make(map[string]*Bond),
}
}
func (n *Network) AddEthernet(name string, ether *EthernetConfig) *Network {
n.Ethernets[name] = ether
return n
}
func (n *Network) AddBond(name string, bond *Bond) *Network {
n.Bonds[name] = bond
return n
}
func (n *Network) YAMLString() string {
return toYAMLString(n)
}
func NewDHCP4EthernetConfig() *EthernetConfig {
return &EthernetConfig{
DHCP4: true,
}
}
func NewStaticEthernetConfig(
addr string,
gateway string,
search []string,
nameservers []string,
routes []*Route,
) *EthernetConfig {
return &EthernetConfig{
DHCP4: false,
Addresses: []string{addr},
Gateway4: gateway,
Routes: routes,
Nameservers: &Nameservers{
Search: search,
Addresses: nameservers,
},
}
}
func (c *EthernetConfig) YAMLString() string {
return toYAMLString(c)
}
func newBondModeByParams(conf *EthernetConfig, interfaces []string, params IBondModeParams) *Bond {
return &Bond{
EthernetConfig: *conf,
Interfaces: interfaces,
Parameters: params,
}
}
func NewBondMode0(conf *EthernetConfig, interfaces []string) *Bond {
params := NewBondMode0Params()
params.SetMiiMonitorInterval(100)
return newBondModeByParams(conf, interfaces, params)
}
func NewBondMode1(conf *EthernetConfig, interfaces []string) *Bond {
params := NewBondModeActiveBackupParams(interfaces[0])
params.SetMiiMonitorInterval(100)
return newBondModeByParams(conf, interfaces, params)
}
func NewBondMode4(conf *EthernetConfig, interfaces []string) *Bond {
params := NewBondMode4Params()
// TODO: figure out what follows options related to netplan config
// miimon: 1
// lacp_rate: 1
// xmit_hash_policy: 1
params.SetMiiMonitorInterval(100)
return newBondModeByParams(conf, interfaces, params)
}
+101
View File
@@ -0,0 +1,101 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package netplan
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewEthernetConfig(t *testing.T) {
c := NewDHCP4EthernetConfig()
assert := assert.New(t)
assert.YAMLEq("dhcp4: true", c.YAMLString())
}
func TestNewBondMode4(t *testing.T) {
c := NewBondMode4(
&EthernetConfig{
DHCP4: false,
Gateway4: "192.168.1.1",
Addresses: []string{"192.168.1.252/24"},
Nameservers: &Nameservers{
Search: []string{"local"},
Addresses: []string{"8.8.8.8", "8.8.4.4"},
},
},
[]string{"enp2s0", "enp3s0"},
)
yamlStr := `
addresses:
- 192.168.1.252/24
dhcp4: false
gateway4: 192.168.1.1
interfaces:
- enp2s0
- enp3s0
nameservers:
addresses:
- 8.8.8.8
- 8.8.4.4
search:
- local
parameters:
mii-monitor-interval: 100
mode: "802.3ad"
`
assert := assert.New(t)
assert.YAMLEq(yamlStr, c.YAMLString())
}
func TestNewNetwork(t *testing.T) {
n := NewNetwork()
n.AddEthernet("eth0", NewDHCP4EthernetConfig())
n.AddEthernet("eth1", NewStaticEthernetConfig(
"10.10.10.2/24",
"10.10.10.1",
[]string{"mydomain", "otherdomain"},
[]string{"114.114.114.114"},
nil,
))
c := NewConfiguration(n)
yamlStr := `
network:
ethernets:
eth0:
dhcp4: true
eth1:
addresses:
- 10.10.10.2/24
dhcp4: false
gateway4: 10.10.10.1
nameservers:
addresses:
- 114.114.114.114
search: ["mydomain", "otherdomain"]
renderer: networkd
version: 2
`
assert := assert.New(t)
assert.YAMLEq(yamlStr, c.YAMLString())
}