Skip to content

Commit

Permalink
kubeadm: make the configured APICall timeout accessible from anywhere
Browse files Browse the repository at this point in the history
Currently the APICall timeout is only accessible as a constant.
Instead, any time a config is loaded or defaulted store the timeout
value and make it accessible from constants.GetAPICallTimeout().
  • Loading branch information
neolit123 committed Dec 29, 2023
1 parent 7b6be51 commit 3cd2fac
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 23 deletions.
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/apis/kubeadm/v1beta4/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func SetDefaults_Timeouts(obj *Timeouts) {
}
if obj.APICall == nil {
obj.APICall = &metav1.Duration{
Duration: constants.APICallTimeout,
Duration: constants.DefaultAPICallTimeout,
}
}
if obj.TLSBootstrap == nil {
Expand Down
25 changes: 23 additions & 2 deletions cmd/kubeadm/app/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"time"

"github.com/pkg/errors"
Expand Down Expand Up @@ -217,8 +218,6 @@ const (
TLSBootstrapTimeout = 5 * time.Minute
// TLSBootstrapRetryInterval specifies how long kubeadm should wait before retrying the TLS Bootstrap check
TLSBootstrapRetryInterval = 1 * time.Second
// APICallTimeout specifies how long kubeadm should wait for API calls
APICallTimeout = 1 * time.Minute

// PullImageRetry specifies how many times ContainerRuntime retries when pulling image failed
PullImageRetry = 5
Expand All @@ -229,6 +228,8 @@ const (
DefaultControlPlaneTimeout = 4 * time.Minute
// DefaultKubeletTimeout specifies the default kubelet timeout
DefaultKubeletTimeout = 4 * time.Minute
// DefaultAPICallTimeout specifies how long kubeadm should wait for API calls
DefaultAPICallTimeout = 1 * time.Minute

// MinimumAddressesInServiceSubnet defines minimum amount of nodes the Service subnet should allow.
// We need at least ten, because the DNS service is always at the tenth cluster clusterIP
Expand Down Expand Up @@ -490,6 +491,12 @@ var (
// defaultKubernetesPlaceholderVersion is a placeholder version in case the component-base
// version was not populated during build.
defaultKubernetesPlaceholderVersion = version.MustParseSemantic("v1.0.0-placeholder-version")

// apiCallTimeout is the local variable that holds the kubeadm API timeout value.
apiCallTimeout = DefaultAPICallTimeout

// timeoutMutex is a mutex that can be used to sync R/W operations on local timeout variables.
timeoutMutex = &sync.RWMutex{}
)

// getSkewedKubernetesVersion returns the current MAJOR.(MINOR+n).0 Kubernetes version with a skew of 'n'
Expand Down Expand Up @@ -673,3 +680,17 @@ func GetAPIServerVirtualIP(svcSubnetList string) (net.IP, error) {
}
return internalAPIServerVirtualIP, nil
}

// GetAPICallTimeout returns the API call timeout to use for this runtime of the kubeadm process
func GetAPICallTimeout() time.Duration {
timeoutMutex.RLock()
defer timeoutMutex.RUnlock()
return apiCallTimeout
}

// SetAPICallTimeout sets the API call timeout to use for this runtime of the kubeadm process
func SetAPICallTimeout(timeout time.Duration) {
timeoutMutex.Lock()
apiCallTimeout = timeout
timeoutMutex.Unlock()
}
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/phases/bootstraptoken/node/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func UpdateOrCreateTokens(client clientset.Interface, failIfExists bool, tokens
err = wait.PollUntilContextTimeout(
context.Background(),
kubeadmconstants.APICallRetryInterval,
kubeadmconstants.APICallTimeout,
kubeadmconstants.GetAPICallTimeout(),
true, func(_ context.Context) (bool, error) {
if err := apiclient.CreateOrUpdateSecret(client, updatedOrNewSecret); err != nil {
lastError = errors.Wrapf(err, "failed to create or update bootstrap token with name %s", secretName)
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ func EnsureAdminClusterRoleBinding(outDir string, ensureRBACFunc EnsureRBACFunc)

ctx := context.Background()
return ensureRBACFunc(
ctx, adminClient, superAdminClient, kubeadmconstants.APICallRetryInterval, kubeadmconstants.APICallTimeout)
ctx, adminClient, superAdminClient, kubeadmconstants.APICallRetryInterval, kubeadmconstants.GetAPICallTimeout())
}

// EnsureAdminClusterRoleBindingImpl first attempts to see if the ClusterRoleBinding
Expand Down
10 changes: 5 additions & 5 deletions cmd/kubeadm/app/util/apiclient/idempotency.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func CreateOrUpdateConfigMap(client clientset.Interface, cm *v1.ConfigMap) error
// taking place)
func CreateOrMutateConfigMap(client clientset.Interface, cm *v1.ConfigMap, mutator ConfigMapMutator) error {
var lastError error
err := wait.PollImmediate(constants.APICallRetryInterval, constants.APICallTimeout, func() (bool, error) {
err := wait.PollImmediate(constants.APICallRetryInterval, constants.GetAPICallTimeout(), func() (bool, error) {
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Create(context.TODO(), cm, metav1.CreateOptions{}); err != nil {
lastError = err
if apierrors.IsAlreadyExists(err) {
Expand All @@ -84,7 +84,7 @@ func CreateOrMutateConfigMap(client clientset.Interface, cm *v1.ConfigMap, mutat
// taking place).
func MutateConfigMap(client clientset.Interface, meta metav1.ObjectMeta, mutator ConfigMapMutator) error {
var lastError error
err := wait.PollImmediate(constants.APICallRetryInterval, constants.APICallTimeout, func() (bool, error) {
err := wait.PollImmediate(constants.APICallRetryInterval, constants.GetAPICallTimeout(), func() (bool, error) {
configMap, err := client.CoreV1().ConfigMaps(meta.Namespace).Get(context.TODO(), meta.Name, metav1.GetOptions{})
if err != nil {
lastError = err
Expand Down Expand Up @@ -190,7 +190,7 @@ func CreateOrUpdateDaemonSet(client clientset.Interface, ds *apps.DaemonSet) err
// CreateOrUpdateRole creates a Role if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateRole(client clientset.Interface, role *rbac.Role) error {
var lastError error
err := wait.PollImmediate(constants.APICallRetryInterval, constants.APICallTimeout, func() (bool, error) {
err := wait.PollImmediate(constants.APICallRetryInterval, constants.GetAPICallTimeout(), func() (bool, error) {
if _, err := client.RbacV1().Roles(role.ObjectMeta.Namespace).Create(context.TODO(), role, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
lastError = errors.Wrap(err, "unable to create RBAC role")
Expand All @@ -213,7 +213,7 @@ func CreateOrUpdateRole(client clientset.Interface, role *rbac.Role) error {
// CreateOrUpdateRoleBinding creates a RoleBinding if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateRoleBinding(client clientset.Interface, roleBinding *rbac.RoleBinding) error {
var lastError error
err := wait.PollImmediate(constants.APICallRetryInterval, constants.APICallTimeout, func() (bool, error) {
err := wait.PollImmediate(constants.APICallRetryInterval, constants.GetAPICallTimeout(), func() (bool, error) {
if _, err := client.RbacV1().RoleBindings(roleBinding.ObjectMeta.Namespace).Create(context.TODO(), roleBinding, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
lastError = errors.Wrap(err, "unable to create RBAC rolebinding")
Expand Down Expand Up @@ -320,7 +320,7 @@ func PatchNode(client clientset.Interface, nodeName string, patchFn func(*v1.Nod
// wait.Poll will rerun the condition function every interval function if
// the function returns false. If the condition function returns an error
// then the retries end and the error is returned.
err := wait.Poll(constants.APICallRetryInterval, constants.APICallTimeout, PatchNodeOnce(client, nodeName, patchFn, &lastError))
err := wait.Poll(constants.APICallRetryInterval, constants.GetAPICallTimeout(), PatchNodeOnce(client, nodeName, patchFn, &lastError))
if err == nil {
return nil
}
Expand Down
13 changes: 13 additions & 0 deletions cmd/kubeadm/app/util/config/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,16 @@ func isKubeadmPrereleaseVersion(versionInfo *apimachineryversion.Info, k8sVersio
}
return false
}

// prepareStaticVariables takes a given config and stores values from it in variables
// that can be used from multiple packages.
func prepareStaticVariables(config interface{}) {
switch config.(type) {
case *kubeadmapi.InitConfiguration:
c := config.(*kubeadmapi.InitConfiguration)
constants.SetAPICallTimeout(c.Timeouts.APICall.Duration)
case *kubeadmapi.JoinConfiguration:
c := config.(*kubeadmapi.JoinConfiguration)
constants.SetAPICallTimeout(c.Timeouts.APICall.Duration)
}
}
19 changes: 13 additions & 6 deletions cmd/kubeadm/app/util/config/initconfiguration.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func DefaultedStaticInitConfiguration() (*kubeadmapi.InitConfiguration, error) {
}

// DefaultedInitConfiguration takes a versioned init config (often populated by flags), defaults it and converts it into internal InitConfiguration
func DefaultedInitConfiguration(versionedInitCfg *kubeadmapiv1.InitConfiguration, versionedClusterCfg *kubeadmapiv1.ClusterConfiguration, skipCRIDetect bool) (*kubeadmapi.InitConfiguration, error) {
func DefaultedInitConfiguration(versionedInitCfg *kubeadmapiv1.InitConfiguration, versionedClusterCfg *kubeadmapiv1.ClusterConfiguration, opts LoadOrDefaultConfigurationOptions) (*kubeadmapi.InitConfiguration, error) {
internalcfg := &kubeadmapi.InitConfiguration{}

// Takes passed flags into account; the defaulting is executed once again enforcing assignment of
Expand All @@ -245,7 +245,7 @@ func DefaultedInitConfiguration(versionedInitCfg *kubeadmapiv1.InitConfiguration
}

// Applies dynamic defaults to settings not provided with flags
if err := SetInitDynamicDefaults(internalcfg, skipCRIDetect); err != nil {
if err := SetInitDynamicDefaults(internalcfg, opts.SkipCRIDetect); err != nil {
return nil, err
}
// Validates cfg (flags/configs + defaults + dynamic defaults)
Expand Down Expand Up @@ -273,13 +273,20 @@ func LoadInitConfigurationFromFile(cfgPath string, opts LoadOrDefaultConfigurati
// Right thereafter, the configuration is defaulted again with dynamic values (like IP addresses of a machine, etc)
// Lastly, the internal config is validated and returned.
func LoadOrDefaultInitConfiguration(cfgPath string, versionedInitCfg *kubeadmapiv1.InitConfiguration, versionedClusterCfg *kubeadmapiv1.ClusterConfiguration, opts LoadOrDefaultConfigurationOptions) (*kubeadmapi.InitConfiguration, error) {
var (
config *kubeadmapi.InitConfiguration
err error
)
if cfgPath != "" {
// Loads configuration from config file, if provided
// Nb. --config overrides command line flags
return LoadInitConfigurationFromFile(cfgPath, opts)
config, err = LoadInitConfigurationFromFile(cfgPath, opts)
} else {
config, err = DefaultedInitConfiguration(versionedInitCfg, versionedClusterCfg, opts)
}

return DefaultedInitConfiguration(versionedInitCfg, versionedClusterCfg, opts.SkipCRIDetect)
if err == nil {
prepareStaticVariables(config)
}
return config, err
}

// BytesToInitConfiguration converts a byte slice to an internal, defaulted and validated InitConfiguration object.
Expand Down
15 changes: 11 additions & 4 deletions cmd/kubeadm/app/util/config/joinconfiguration.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,20 @@ func SetJoinControlPlaneDefaults(cfg *kubeadmapi.JoinControlPlane) error {
// Right thereafter, the configuration is defaulted again with dynamic values (like IP addresses of a machine, etc)
// Lastly, the internal config is validated and returned.
func LoadOrDefaultJoinConfiguration(cfgPath string, defaultversionedcfg *kubeadmapiv1.JoinConfiguration, opts LoadOrDefaultConfigurationOptions) (*kubeadmapi.JoinConfiguration, error) {
var (
config *kubeadmapi.JoinConfiguration
err error
)
if cfgPath != "" {
// Loads configuration from config file, if provided
// Nb. --config overrides command line flags, TODO: fix this
return LoadJoinConfigurationFromFile(cfgPath, opts)
config, err = LoadJoinConfigurationFromFile(cfgPath, opts)
} else {
config, err = DefaultedJoinConfiguration(defaultversionedcfg, opts)
}

return DefaultedJoinConfiguration(defaultversionedcfg, opts)
if err == nil {
prepareStaticVariables(config)
}
return config, err
}

// LoadJoinConfigurationFromFile loads versioned JoinConfiguration from file, converts it to internal, defaults and validates it
Expand Down
14 changes: 11 additions & 3 deletions cmd/kubeadm/app/util/config/resetconfiguration.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,20 @@ func SetResetDynamicDefaults(cfg *kubeadmapi.ResetConfiguration, skipCRIDetect b
// Right thereafter, the configuration is defaulted again with dynamic values
// Lastly, the internal config is validated and returned.
func LoadOrDefaultResetConfiguration(cfgPath string, defaultversionedcfg *kubeadmapiv1.ResetConfiguration, opts LoadOrDefaultConfigurationOptions) (*kubeadmapi.ResetConfiguration, error) {
var (
config *kubeadmapi.ResetConfiguration
err error
)
if cfgPath != "" {
// Loads configuration from config file, if provided
return LoadResetConfigurationFromFile(cfgPath, opts)
config, err = LoadResetConfigurationFromFile(cfgPath, opts)
} else {
config, err = DefaultedResetConfiguration(defaultversionedcfg, opts)
}

return DefaultedResetConfiguration(defaultversionedcfg, opts)
if err == nil {
prepareStaticVariables(config)
}
return config, err
}

// LoadResetConfigurationFromFile loads versioned ResetConfiguration from file, converts it to internal, defaults and validates it
Expand Down

0 comments on commit 3cd2fac

Please sign in to comment.