Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release-1.23] feat: support platformSubFaultDomain node label #1080

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion pkg/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ const (

// LabelFailureDomainBetaZone refer to https://github.com/kubernetes/api/blob/8519c5ea46199d57724725d5b969c5e8e0533692/core/v1/well_known_labels.go#L22-L23
LabelFailureDomainBetaZone = "failure-domain.beta.kubernetes.io/zone"

// LabelFailureDomainBetaRegion failure-domain region label
LabelFailureDomainBetaRegion = "failure-domain.beta.kubernetes.io/region"
// LabelPlatformSubFaultDomain is the label key of platformSubFaultDomain
LabelPlatformSubFaultDomain = "topology.kubernetes.azure.com/sub-fault-domain"

// ADFSIdentitySystem is the override value for tenantID on Azure Stack clouds.
ADFSIdentitySystem = "adfs"
Expand Down
5 changes: 5 additions & 0 deletions pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,8 @@ func (np *IMDSNodeProvider) InstanceType(ctx context.Context, name types.NodeNam
func (np *IMDSNodeProvider) GetZone(ctx context.Context, name types.NodeName) (cloudprovider.Zone, error) {
return np.azure.GetZone(ctx)
}

// GetPlatformSubFaultDomain returns the PlatformSubFaultDomain from IMDS if set.
func (np *IMDSNodeProvider) GetPlatformSubFaultDomain() (string, error) {
return np.azure.GetPlatformSubFaultDomain()
}
5 changes: 5 additions & 0 deletions pkg/node/nodearm.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,8 @@ func (np *ARMNodeProvider) GetZone(ctx context.Context, name types.NodeName) (cl

return np.azure.GetZone(ctx)
}

// GetPlatformSubFaultDomain returns the PlatformSubFaultDomain from IMDS if set.
func (np *ARMNodeProvider) GetPlatformSubFaultDomain() (string, error) {
return "", nil
}
177 changes: 91 additions & 86 deletions pkg/nodemanager/mock/mock_node_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,104 +17,109 @@ limitations under the License.
package mock

import (
"context"
context "context"
reflect "reflect"

gomock "github.com/golang/mock/gomock"
v1 "k8s.io/api/core/v1"
types "k8s.io/apimachinery/pkg/types"
cloudprovider "k8s.io/cloud-provider"
)

mock "github.com/stretchr/testify/mock"
// NodeProvider is a mock of NodeProvider interface.
type NodeProvider struct {
ctrl *gomock.Controller
recorder *NodeProviderMockRecorder
}

types "k8s.io/apimachinery/pkg/types"
// NodeProviderMockRecorder is the mock recorder for NodeProvider.
type NodeProviderMockRecorder struct {
mock *NodeProvider
}

v1 "k8s.io/api/core/v1"
)
// NewMockNodeProvider creates a new mock instance.
func NewMockNodeProvider(ctrl *gomock.Controller) *NodeProvider {
mock := &NodeProvider{ctrl: ctrl}
mock.recorder = &NodeProviderMockRecorder{mock}
return mock
}

// NodeProvider is an autogenerated mock type for the NodeProvider type
type NodeProvider struct {
mock.Mock
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *NodeProvider) EXPECT() *NodeProviderMockRecorder {
return m.recorder
}

// GetPlatformSubFaultDomain mocks base method.
func (m *NodeProvider) GetPlatformSubFaultDomain() (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetPlatformSubFaultDomain")
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}

// GetPlatformSubFaultDomain indicates an expected call of GetPlatformSubFaultDomain.
func (mr *NodeProviderMockRecorder) GetPlatformSubFaultDomain() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPlatformSubFaultDomain", reflect.TypeOf((*NodeProvider)(nil).GetPlatformSubFaultDomain))
}

// GetZone mocks base method.
func (m *NodeProvider) GetZone(arg0 context.Context, arg1 types.NodeName) (cloudprovider.Zone, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetZone", arg0, arg1)
ret0, _ := ret[0].(cloudprovider.Zone)
ret1, _ := ret[1].(error)
return ret0, ret1
}

// GetZone indicates an expected call of GetZone.
func (mr *NodeProviderMockRecorder) GetZone(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetZone", reflect.TypeOf((*NodeProvider)(nil).GetZone), arg0, arg1)
}

// InstanceID mocks base method.
func (m *NodeProvider) InstanceID(arg0 context.Context, arg1 types.NodeName) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InstanceID", arg0, arg1)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}

// InstanceID indicates an expected call of InstanceID.
func (mr *NodeProviderMockRecorder) InstanceID(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceID", reflect.TypeOf((*NodeProvider)(nil).InstanceID), arg0, arg1)
}

// GetZone provides a mock function with given fields: ctx
func (_m *NodeProvider) GetZone(ctx context.Context, name types.NodeName) (cloudprovider.Zone, error) {
ret := _m.Called(ctx)

var r0 cloudprovider.Zone
if rf, ok := ret.Get(0).(func(context.Context) cloudprovider.Zone); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(cloudprovider.Zone)
}

var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}

return r0, r1
// InstanceType mocks base method.
func (m *NodeProvider) InstanceType(arg0 context.Context, arg1 types.NodeName) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InstanceType", arg0, arg1)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}

// InstanceID provides a mock function with given fields: ctx, name
func (_m *NodeProvider) InstanceID(ctx context.Context, name types.NodeName) (string, error) {
ret := _m.Called(ctx, name)

var r0 string
if rf, ok := ret.Get(0).(func(context.Context, types.NodeName) string); ok {
r0 = rf(ctx, name)
} else {
r0 = ret.Get(0).(string)
}

var r1 error
if rf, ok := ret.Get(1).(func(context.Context, types.NodeName) error); ok {
r1 = rf(ctx, name)
} else {
r1 = ret.Error(1)
}

return r0, r1
// InstanceType indicates an expected call of InstanceType.
func (mr *NodeProviderMockRecorder) InstanceType(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceType", reflect.TypeOf((*NodeProvider)(nil).InstanceType), arg0, arg1)
}

// InstanceType provides a mock function with given fields: ctx, name
func (_m *NodeProvider) InstanceType(ctx context.Context, name types.NodeName) (string, error) {
ret := _m.Called(ctx, name)

var r0 string
if rf, ok := ret.Get(0).(func(context.Context, types.NodeName) string); ok {
r0 = rf(ctx, name)
} else {
r0 = ret.Get(0).(string)
}

var r1 error
if rf, ok := ret.Get(1).(func(context.Context, types.NodeName) error); ok {
r1 = rf(ctx, name)
} else {
r1 = ret.Error(1)
}

return r0, r1
// NodeAddresses mocks base method.
func (m *NodeProvider) NodeAddresses(arg0 context.Context, arg1 types.NodeName) ([]v1.NodeAddress, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NodeAddresses", arg0, arg1)
ret0, _ := ret[0].([]v1.NodeAddress)
ret1, _ := ret[1].(error)
return ret0, ret1
}

// NodeAddresses provides a mock function with given fields: ctx, name
func (_m *NodeProvider) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) {
ret := _m.Called(ctx, name)

var r0 []v1.NodeAddress
if rf, ok := ret.Get(0).(func(context.Context, types.NodeName) []v1.NodeAddress); ok {
r0 = rf(ctx, name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]v1.NodeAddress)
}
}

var r1 error
if rf, ok := ret.Get(1).(func(context.Context, types.NodeName) error); ok {
r1 = rf(ctx, name)
} else {
r1 = ret.Error(1)
}

return r0, r1
// NodeAddresses indicates an expected call of NodeAddresses.
func (mr *NodeProviderMockRecorder) NodeAddresses(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeAddresses", reflect.TypeOf((*NodeProvider)(nil).NodeAddresses), arg0, arg1)
}
26 changes: 26 additions & 0 deletions pkg/nodemanager/nodemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import (
cloudnodeutil "k8s.io/cloud-provider/node/helpers"
nodeutil "k8s.io/component-helpers/node/util"
"k8s.io/klog/v2"

"sigs.k8s.io/cloud-provider-azure/pkg/consts"
)

// NodeProvider defines the interfaces for node provider.
Expand All @@ -56,6 +58,8 @@ type NodeProvider interface {
InstanceType(ctx context.Context, name types.NodeName) (string, error)
// GetZone returns the Zone containing the current failure zone and locality region that the program is running in
GetZone(ctx context.Context, name types.NodeName) (cloudprovider.Zone, error)
// GetPlatformSubFaultDomain returns the PlatformSubFaultDomain from IMDS if set.
GetPlatformSubFaultDomain() (string, error)
}

// labelReconcileInfo lists Node labels to reconcile, and how to reconcile them.
Expand Down Expand Up @@ -492,6 +496,20 @@ func (cnc *CloudNodeController) getNodeModifiersFromCloudProvider(ctx context.Co
})
}

platformSubFaultDomain, err := cnc.getPlatformSubFaultDomain()
if err != nil {
return nil, fmt.Errorf("failed to get platformSubFaultDomain: %w", err)
}
if platformSubFaultDomain != "" {
klog.V(2).Infof("Adding node label from cloud provider: %s=%s", consts.LabelPlatformSubFaultDomain, platformSubFaultDomain)
nodeModifiers = append(nodeModifiers, func(n *v1.Node) {
if n.Labels == nil {
n.Labels = map[string]string{}
}
n.Labels[consts.LabelPlatformSubFaultDomain] = platformSubFaultDomain
})
}

return nodeModifiers, nil
}

Expand Down Expand Up @@ -598,6 +616,14 @@ func (cnc *CloudNodeController) getZoneByName(ctx context.Context, node *v1.Node
return zone, nil
}

func (cnc *CloudNodeController) getPlatformSubFaultDomain() (string, error) {
subFD, err := cnc.nodeProvider.GetPlatformSubFaultDomain()
if err != nil {
return "", fmt.Errorf("cnc.getPlatformSubfaultDomain: %w", err)
}
return subFD, nil
}

func (cnc *CloudNodeController) updateNetworkingCondition(node *v1.Node, networkReady bool) error {
_, condition := nodeutil.GetNodeCondition(&(node.Status), v1.NodeNetworkUnavailable)
if networkReady && condition != nil && condition.Status == v1.ConditionFalse {
Expand Down