Add check support for: bridge, ipvlan, macvlan, p2p, vlan and host-device main plugins

host-local and static ipam plugins
  tuning, bandwidth and portmap meta plugins

  Utility functions created for common PrevResult checking

  Fix windows build
This commit is contained in:
Michael Cambria
2018-12-06 15:42:37 -05:00
parent 82a0651d0a
commit 74a2596573
28 changed files with 3759 additions and 167 deletions

View File

@ -138,3 +138,44 @@ func chainExists(ipt *iptables.IPTables, tableName, chainName string) (bool, err
}
return false, nil
}
// check the chain.
func (c *chain) check(ipt *iptables.IPTables) error {
exists, err := chainExists(ipt, c.table, c.name)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("chain %s not found in iptables table %s", c.name, c.table)
}
for i := len(c.rules) - 1; i >= 0; i-- {
match := checkRule(ipt, c.table, c.name, c.rules[i])
if !match {
return fmt.Errorf("rule %s in chain %s not found in table %s", c.rules, c.name, c.table)
}
}
for _, entryChain := range c.entryChains {
for i := len(c.entryRules) - 1; i >= 0; i-- {
r := []string{}
r = append(r, c.entryRules[i]...)
r = append(r, "-j", c.name)
matchEntryChain := checkRule(ipt, c.table, entryChain, r)
if !matchEntryChain {
return fmt.Errorf("rule %s in chain %s not found in table %s", c.entryRules, entryChain, c.table)
}
}
}
return nil
}
func checkRule(ipt *iptables.IPTables, table, chain string, rule []string) bool {
exists, err := ipt.Exists(table, chain, rule...)
if err != nil {
return false
}
return exists
}

View File

@ -55,8 +55,6 @@ type PortMapConf struct {
RuntimeConfig struct {
PortMaps []PortMapEntry `json:"portMappings,omitempty"`
} `json:"runtimeConfig,omitempty"`
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
PrevResult *current.Result `json:"-"`
// These are fields parsed out of the config or the environment;
// included here for convenience
@ -70,7 +68,7 @@ type PortMapConf struct {
const DefaultMarkBit = 13
func cmdAdd(args *skel.CmdArgs) error {
netConf, err := parseConfig(args.StdinData, args.IfName)
netConf, _, err := parseConfig(args.StdinData, args.IfName)
if err != nil {
return fmt.Errorf("failed to parse config: %v", err)
}
@ -102,7 +100,7 @@ func cmdAdd(args *skel.CmdArgs) error {
}
func cmdDel(args *skel.CmdArgs) error {
netConf, err := parseConfig(args.StdinData, args.IfName)
netConf, _, err := parseConfig(args.StdinData, args.IfName)
if err != nil {
return fmt.Errorf("failed to parse config: %v", err)
}
@ -119,36 +117,60 @@ func cmdDel(args *skel.CmdArgs) error {
func main() {
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
func cmdCheck(args *skel.CmdArgs) error {
conf, result, err := parseConfig(args.StdinData, args.IfName)
if err != nil {
return err
}
// Ensure we have previous result.
if result == nil {
return fmt.Errorf("Required prevResult missing")
}
if len(conf.RuntimeConfig.PortMaps) == 0 {
return nil
}
conf.ContainerID = args.ContainerID
if conf.ContIPv4 != nil {
if err := checkPorts(conf, conf.ContIPv4); err != nil {
return err
}
}
if conf.ContIPv6 != nil {
if err := checkPorts(conf, conf.ContIPv6); err != nil {
return err
}
}
return nil
}
// parseConfig parses the supplied configuration (and prevResult) from stdin.
func parseConfig(stdin []byte, ifName string) (*PortMapConf, error) {
func parseConfig(stdin []byte, ifName string) (*PortMapConf, *current.Result, error) {
conf := PortMapConf{}
if err := json.Unmarshal(stdin, &conf); err != nil {
return nil, fmt.Errorf("failed to parse network configuration: %v", err)
return nil, nil, fmt.Errorf("failed to parse network configuration: %v", err)
}
// Parse previous result.
var result *current.Result
if conf.RawPrevResult != nil {
resultBytes, err := json.Marshal(conf.RawPrevResult)
if err != nil {
return nil, fmt.Errorf("could not serialize prevResult: %v", err)
var err error
if err = version.ParsePrevResult(&conf.NetConf); err != nil {
return nil, nil, fmt.Errorf("could not parse prevResult: %v", err)
}
res, err := version.NewResult(conf.CNIVersion, resultBytes)
result, err = current.NewResultFromResult(conf.PrevResult)
if err != nil {
return nil, fmt.Errorf("could not parse prevResult: %v", err)
}
conf.RawPrevResult = nil
conf.PrevResult, err = current.NewResultFromResult(res)
if err != nil {
return nil, fmt.Errorf("could not convert result to current version: %v", err)
return nil, nil, fmt.Errorf("could not convert result to current version: %v", err)
}
}
@ -158,7 +180,7 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, error) {
}
if conf.MarkMasqBit != nil && conf.ExternalSetMarkChain != nil {
return nil, fmt.Errorf("Cannot specify externalSetMarkChain and markMasqBit")
return nil, nil, fmt.Errorf("Cannot specify externalSetMarkChain and markMasqBit")
}
if conf.MarkMasqBit == nil {
@ -167,21 +189,21 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, error) {
}
if *conf.MarkMasqBit < 0 || *conf.MarkMasqBit > 31 {
return nil, fmt.Errorf("MasqMarkBit must be between 0 and 31")
return nil, nil, fmt.Errorf("MasqMarkBit must be between 0 and 31")
}
// Reject invalid port numbers
for _, pm := range conf.RuntimeConfig.PortMaps {
if pm.ContainerPort <= 0 {
return nil, fmt.Errorf("Invalid container port number: %d", pm.ContainerPort)
return nil, nil, fmt.Errorf("Invalid container port number: %d", pm.ContainerPort)
}
if pm.HostPort <= 0 {
return nil, fmt.Errorf("Invalid host port number: %d", pm.HostPort)
return nil, nil, fmt.Errorf("Invalid host port number: %d", pm.HostPort)
}
}
if conf.PrevResult != nil {
for _, ip := range conf.PrevResult.IPs {
for _, ip := range result.IPs {
if ip.Version == "6" && conf.ContIPv6 != nil {
continue
} else if ip.Version == "4" && conf.ContIPv4 != nil {
@ -192,9 +214,9 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, error) {
if ip.Interface != nil {
intIdx := *ip.Interface
if intIdx >= 0 &&
intIdx < len(conf.PrevResult.Interfaces) &&
(conf.PrevResult.Interfaces[intIdx].Name != ifName ||
conf.PrevResult.Interfaces[intIdx].Sandbox == "") {
intIdx < len(result.Interfaces) &&
(result.Interfaces[intIdx].Name != ifName ||
result.Interfaces[intIdx].Sandbox == "") {
continue
}
}
@ -207,5 +229,5 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, error) {
}
}
return &conf, nil
return &conf, result, nil
}

View File

@ -111,6 +111,46 @@ func forwardPorts(config *PortMapConf, containerIP net.IP) error {
return nil
}
func checkPorts(config *PortMapConf, containerIP net.IP) error {
dnatChain := genDnatChain(config.Name, config.ContainerID)
fillDnatRules(&dnatChain, config, containerIP)
ip4t := maybeGetIptables(false)
ip6t := maybeGetIptables(true)
if ip4t == nil && ip6t == nil {
return fmt.Errorf("neither iptables nor ip6tables usable")
}
if ip4t != nil {
exists, err := chainExists(ip4t, dnatChain.table, dnatChain.name)
if err != nil {
return err
}
if !exists {
return err
}
if err := dnatChain.check(ip4t); err != nil {
return fmt.Errorf("could not check ipv4 dnat: %v", err)
}
}
if ip6t != nil {
exists, err := chainExists(ip6t, dnatChain.table, dnatChain.name)
if err != nil {
return err
}
if !exists {
return err
}
if err := dnatChain.check(ip6t); err != nil {
return fmt.Errorf("could not check ipv6 dnat: %v", err)
}
}
return nil
}
// genToplevelDnatChain creates the top-level summary chain that we'll
// add our chain to. This is easy, because creating chains is idempotent.
// IMPORTANT: do not change this, or else upgrading plugins will require

View File

@ -68,7 +68,7 @@ var _ = Describe("portmapping configuration", func() {
]
}
}`)
c, err := parseConfig(configBytes, "container")
c, _, err := parseConfig(configBytes, "container")
Expect(err).NotTo(HaveOccurred())
Expect(c.CNIVersion).To(Equal("0.3.1"))
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
@ -91,7 +91,7 @@ var _ = Describe("portmapping configuration", func() {
"conditionsV4": ["a", "b"],
"conditionsV6": ["c", "d"]
}`)
c, err := parseConfig(configBytes, "container")
c, _, err := parseConfig(configBytes, "container")
Expect(err).NotTo(HaveOccurred())
Expect(c.CNIVersion).To(Equal("0.3.1"))
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
@ -115,7 +115,7 @@ var _ = Describe("portmapping configuration", func() {
]
}
}`)
_, err := parseConfig(configBytes, "container")
_, _, err := parseConfig(configBytes, "container")
Expect(err).To(MatchError("Invalid host port number: 0"))
})
@ -143,7 +143,7 @@ var _ = Describe("portmapping configuration", func() {
]
}
}`)
_, err := parseConfig(configBytes, "container")
_, _, err := parseConfig(configBytes, "container")
Expect(err).NotTo(HaveOccurred())
})
})
@ -175,7 +175,7 @@ var _ = Describe("portmapping configuration", func() {
"conditionsV6": ["c", "d"]
}`)
conf, err := parseConfig(configBytes, "foo")
conf, _, err := parseConfig(configBytes, "foo")
Expect(err).NotTo(HaveOccurred())
conf.ContainerID = containerID
@ -271,7 +271,7 @@ var _ = Describe("portmapping configuration", func() {
"conditionsV6": ["c", "d"]
}`)
conf, err := parseConfig(configBytes, "foo")
conf, _, err := parseConfig(configBytes, "foo")
Expect(err).NotTo(HaveOccurred())
conf.ContainerID = containerID