Skip to content

Commit

Permalink
OCPBUGS-41834: Add agent installer checks for hosts interface table
Browse files Browse the repository at this point in the history
Add checks for the host interface table to validate:
- at least one entry is defined in the interface table when using
  network configuration
- the MAC addresses in the interface table are using the expected format
  • Loading branch information
bfournie committed Sep 24, 2024
1 parent 30ba9c5 commit df4120d
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 3 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ require (
github.com/go-openapi/runtime v0.28.0
github.com/go-openapi/strfmt v0.23.0
github.com/go-openapi/swag v0.23.0
github.com/go-openapi/validate v0.24.0
github.com/go-playground/validator/v10 v10.19.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/mock v1.7.0-rc.1
Expand Down Expand Up @@ -185,7 +186,6 @@ require (
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/loads v0.22.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/gobuffalo/flect v1.0.2 // indirect
Expand Down
24 changes: 24 additions & 0 deletions pkg/asset/agent/manifests/nmstateconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,30 @@ func TestNMStateConfig_Generate(t *testing.T) {
expectedConfig: nil,
expectedError: "failed to validate network yaml",
},
{
name: "invalid networkConfig, no interfaces in interface table",
dependencies: []asset.Asset{
&workflow.AgentWorkflow{Workflow: workflow.AgentWorkflowTypeInstall},
&joiner.ClusterInfo{},
getAgentHostsConfigNoInterfaces(),
getValidOptionalInstallConfig(),
},
requiresNmstatectl: true,
expectedConfig: nil,
expectedError: "at least one interface for host 0 must be provided",
},
{
name: "invalid networkConfig, invalid mac in interface table",
dependencies: []asset.Asset{
&workflow.AgentWorkflow{Workflow: workflow.AgentWorkflowTypeInstall},
&joiner.ClusterInfo{},
getAgentHostsConfigInvalidMac(),
getValidOptionalInstallConfig(),
},
requiresNmstatectl: true,
expectedConfig: nil,
expectedError: "MAC address 98-af-65-a5-8d-02 for host 0 is incorrectly formatted, use XX:XX:XX:XX:XX:XX format",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
Expand Down
11 changes: 9 additions & 2 deletions pkg/asset/agent/manifests/staticnetworkconfig/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"sort"
"strings"

"github.com/go-openapi/validate"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -219,20 +220,26 @@ func (s *staticNetworkConfigGenerator) formatNMConnection(nmConnection string) (
func (s *staticNetworkConfigGenerator) ValidateStaticConfigParams(ctx context.Context, staticNetworkConfig []*models.HostStaticNetworkConfig) error {
var err *multierror.Error
for i, hostConfig := range staticNetworkConfig {
err = multierror.Append(err, s.validateMacInterfaceName(i, hostConfig.MacInterfaceMap))
err = multierror.Append(err, s.validateMacInterfaceTable(i, hostConfig.MacInterfaceMap))
if validateErr := s.ValidateNMStateYaml(ctx, hostConfig.NetworkYaml); validateErr != nil {
err = multierror.Append(err, fmt.Errorf("failed to validate network yaml for host %d, %w", i, validateErr))
}
}
return err.ErrorOrNil()
}

func (s *staticNetworkConfigGenerator) validateMacInterfaceName(hostIdx int, macInterfaceMap models.MacInterfaceMap) error {
func (s *staticNetworkConfigGenerator) validateMacInterfaceTable(hostIdx int, macInterfaceMap models.MacInterfaceMap) error {
if len(macInterfaceMap) == 0 {
return fmt.Errorf("at least one interface for host %d must be provided", hostIdx)
}
interfaceCheck := make(map[string]struct{}, len(macInterfaceMap))
macCheck := make(map[string]struct{}, len(macInterfaceMap))
for _, macInterface := range macInterfaceMap {
interfaceCheck[macInterface.LogicalNicName] = struct{}{}
macCheck[macInterface.MacAddress] = struct{}{}
if err := validate.Pattern("mac_address", "body", macInterface.MacAddress, `^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$`); err != nil {
return fmt.Errorf("MAC address %s for host %d is incorrectly formatted, use XX:XX:XX:XX:XX:XX format", macInterface.MacAddress, hostIdx)
}
}
if len(interfaceCheck) < len(macInterfaceMap) || len(macCheck) < len(macInterfaceMap) {
return fmt.Errorf("MACs and Interfaces for host %d must be unique", hostIdx)
Expand Down
33 changes: 33 additions & 0 deletions pkg/asset/agent/manifests/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,39 @@ func getAgentHostsWithBMCConfig() *agentconfig.AgentHosts {
}
}

func getAgentHostsConfigNoInterfaces() *agentconfig.AgentHosts {
return &agentconfig.AgentHosts{
Hosts: []agenttypes.Host{
{
Hostname: "control-0.example.org",
Interfaces: []*v1beta1.Interface{},
NetworkConfig: v1beta1.NetConfig{
Raw: unmarshalJSON([]byte(rawNMStateConfig)),
},
},
},
}
}

func getAgentHostsConfigInvalidMac() *agentconfig.AgentHosts {
return &agentconfig.AgentHosts{
Hosts: []agenttypes.Host{
{
Hostname: "control-0.example.org",
Interfaces: []*v1beta1.Interface{
{
Name: "enp2s0",
MacAddress: "98-af-65-a5-8d-02",
},
},
NetworkConfig: v1beta1.NetConfig{
Raw: unmarshalJSON([]byte(rawNMStateConfig)),
},
},
},
}
}

func getGoodACI() *hiveext.AgentClusterInstall {
goodACI := &hiveext.AgentClusterInstall{
TypeMeta: metav1.TypeMeta{
Expand Down

0 comments on commit df4120d

Please sign in to comment.