mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
Merge pull request #50626 from luxas/kubeadm_separate_apiclient
Automatic merge from submit-queue (batch tested with PRs 50626, 50683, 50679, 50684, 50460) kubeadm: Centralize client create-or-update logic in one package **What this PR does / why we need it**: Moves all Create-or-Update logic into one package instead of duplicating that logic all around in the codebase. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # **Special notes for your reviewer**: This PR depends on https://github.com/kubernetes/kubernetes/pull/50214. Note that commit 2 is the only one that needs reviewing. This PR is required for https://github.com/kubernetes/kubernetes/pull/48899 (kubeadm upgrade) **Release note**: ```release-note NONE ``` @kubernetes/sig-cluster-lifecycle-pr-reviews @mattmoyer @fabriziopandini
This commit is contained in:
commit
d72fc055ee
@ -39,6 +39,7 @@ go_library(
|
||||
"//cmd/kubeadm/app/phases/uploadconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//cmd/kubeadm/app/util/config:go_default_library",
|
||||
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/util/pubkeypin:go_default_library",
|
||||
|
@ -47,7 +47,9 @@ import (
|
||||
uploadconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
@ -253,11 +255,15 @@ func (i *Init) Run(out io.Writer) error {
|
||||
}
|
||||
}
|
||||
|
||||
client, err := kubeadmutil.CreateClientAndWaitForAPI(kubeadmconstants.GetAdminKubeConfigPath())
|
||||
client, err := kubeconfigutil.ClientSetFromFile(kubeadmconstants.GetAdminKubeConfigPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("[init] Waiting for the kubelet to boot up the control plane as Static Pods from directory %q\n", kubeadmconstants.GetStaticPodDirectory())
|
||||
// TODO: Don't wait forever here
|
||||
apiclient.WaitForAPI(client)
|
||||
|
||||
// PHASE 4: Mark the master with the right label/taint
|
||||
if err := markmasterphase.MarkMaster(client, i.cfg.NodeName); err != nil {
|
||||
return err
|
||||
|
@ -73,10 +73,6 @@ const (
|
||||
NodesGroup = "system:nodes"
|
||||
NodesClusterRoleBinding = "system:node"
|
||||
|
||||
// Constants for what we name our ServiceAccounts with limited access to the cluster in case of RBAC
|
||||
KubeDNSServiceAccountName = "kube-dns"
|
||||
KubeProxyServiceAccountName = "kube-proxy"
|
||||
|
||||
// APICallRetryInterval defines how long kubeadm should wait before retrying a failed API operation
|
||||
APICallRetryInterval = 500 * time.Millisecond
|
||||
// DiscoveryRetryInterval specifies how long kubeadm should wait before retrying to connect to the master when doing discovery
|
||||
|
@ -34,6 +34,7 @@ go_library(
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
|
@ -30,9 +30,15 @@ import (
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
const (
|
||||
// KubeDNSServiceAccountName describes the name of the ServiceAccount for the kube-dns addon
|
||||
KubeDNSServiceAccountName = "kube-dns"
|
||||
)
|
||||
|
||||
// EnsureDNSAddon creates the kube-dns addon
|
||||
func EnsureDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
|
||||
if err := CreateServiceAccount(client); err != nil {
|
||||
@ -62,7 +68,7 @@ func EnsureDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interf
|
||||
return fmt.Errorf("error when parsing kube-proxy configmap template: %v", err)
|
||||
}
|
||||
|
||||
if err = createKubeDNSAddon(dnsDeploymentBytes, dnsServiceBytes, client); err != nil {
|
||||
if err := createKubeDNSAddon(dnsDeploymentBytes, dnsServiceBytes, client); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("[addons] Applied essential addon: kube-dns")
|
||||
@ -71,18 +77,13 @@ func EnsureDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interf
|
||||
|
||||
// CreateServiceAccount creates the necessary serviceaccounts that kubeadm uses/might use, if they don't already exist.
|
||||
func CreateServiceAccount(client clientset.Interface) error {
|
||||
sa := v1.ServiceAccount{
|
||||
|
||||
return apiclient.CreateOrUpdateServiceAccount(client, &v1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kubeadmconstants.KubeDNSServiceAccountName,
|
||||
Name: KubeDNSServiceAccountName,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
}
|
||||
if _, err := client.CoreV1().ServiceAccounts(metav1.NamespaceSystem).Create(&sa); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func createKubeDNSAddon(deploymentBytes, serviceBytes []byte, client clientset.Interface) error {
|
||||
@ -91,14 +92,9 @@ func createKubeDNSAddon(deploymentBytes, serviceBytes []byte, client clientset.I
|
||||
return fmt.Errorf("unable to decode kube-dns deployment %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.ExtensionsV1beta1().Deployments(metav1.NamespaceSystem).Create(kubednsDeployment); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create a new kube-dns deployment: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.ExtensionsV1beta1().Deployments(metav1.NamespaceSystem).Update(kubednsDeployment); err != nil {
|
||||
return fmt.Errorf("unable to update the kube-dns deployment: %v", err)
|
||||
}
|
||||
// Create the Deployment for kube-dns or update it in case it already exists
|
||||
if err := apiclient.CreateOrUpdateDeployment(client, kubednsDeployment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kubednsService := &v1.Service{}
|
||||
@ -106,6 +102,7 @@ func createKubeDNSAddon(deploymentBytes, serviceBytes []byte, client clientset.I
|
||||
return fmt.Errorf("unable to decode kube-dns service %v", err)
|
||||
}
|
||||
|
||||
// Can't use a generic apiclient helper func here as we have to tolerate more than AlreadyExists.
|
||||
if _, err := client.CoreV1().Services(metav1.NamespaceSystem).Create(kubednsService); err != nil {
|
||||
// Ignore if the Service is invalid with this error message:
|
||||
// Service "kube-dns" is invalid: spec.clusterIP: Invalid value: "10.96.0.10": provided IP is already allocated
|
||||
|
@ -33,12 +33,10 @@ go_library(
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//plugin/pkg/scheduler/algorithm:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
|
@ -23,17 +23,14 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
rbac "k8s.io/api/rbac/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kuberuntime "k8s.io/apimachinery/pkg/runtime"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
apiclientutil "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
k8sversion "k8s.io/kubernetes/pkg/util/version"
|
||||
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
|
||||
)
|
||||
|
||||
@ -41,9 +38,12 @@ const (
|
||||
// KubeProxyClusterRoleName sets the name for the kube-proxy ClusterRole
|
||||
// TODO: This k8s-generic, well-known constant should be fetchable from another source, not be in this package
|
||||
KubeProxyClusterRoleName = "system:node-proxier"
|
||||
|
||||
// KubeProxyServiceAccountName describes the name of the ServiceAccount for the kube-proxy addon
|
||||
KubeProxyServiceAccountName = "kube-proxy"
|
||||
)
|
||||
|
||||
// EnsureProxyAddon creates the kube-proxy and kube-dns addons
|
||||
// EnsureProxyAddon creates the kube-proxy addons
|
||||
func EnsureProxyAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
|
||||
if err := CreateServiceAccount(client); err != nil {
|
||||
return fmt.Errorf("error when creating kube-proxy service account: %v", err)
|
||||
@ -70,41 +70,30 @@ func EnsureProxyAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Inte
|
||||
return fmt.Errorf("error when parsing kube-proxy daemonset template: %v", err)
|
||||
}
|
||||
|
||||
if err = createKubeProxyAddon(proxyConfigMapBytes, proxyDaemonSetBytes, client); err != nil {
|
||||
if err := createKubeProxyAddon(proxyConfigMapBytes, proxyDaemonSetBytes, client); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("[addons] Applied essential addon: kube-proxy")
|
||||
|
||||
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't parse kubernetes version %q: %v", cfg.KubernetesVersion, err)
|
||||
}
|
||||
if err = CreateRBACRules(client, k8sVersion); err != nil {
|
||||
if err := CreateRBACRules(client); err != nil {
|
||||
return fmt.Errorf("error when creating kube-proxy RBAC rules: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("[addons] Applied essential addon: kube-proxy")
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateServiceAccount creates the necessary serviceaccounts that kubeadm uses/might use, if they don't already exist.
|
||||
func CreateServiceAccount(client clientset.Interface) error {
|
||||
sa := v1.ServiceAccount{
|
||||
|
||||
return apiclient.CreateOrUpdateServiceAccount(client, &v1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kubeadmconstants.KubeProxyServiceAccountName,
|
||||
Name: KubeProxyServiceAccountName,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := client.CoreV1().ServiceAccounts(metav1.NamespaceSystem).Create(&sa); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// CreateRBACRules creates the essential RBAC rules for a minimally set-up cluster
|
||||
func CreateRBACRules(client clientset.Interface, k8sVersion *k8sversion.Version) error {
|
||||
func CreateRBACRules(client clientset.Interface) error {
|
||||
if err := createClusterRoleBindings(client); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -117,14 +106,9 @@ func createKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client clientse
|
||||
return fmt.Errorf("unable to decode kube-proxy configmap %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Create(kubeproxyConfigMap); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create a new kube-proxy configmap: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Update(kubeproxyConfigMap); err != nil {
|
||||
return fmt.Errorf("unable to update the kube-proxy configmap: %v", err)
|
||||
}
|
||||
// Create the ConfigMap for kube-proxy or update it in case it already exists
|
||||
if err := apiclient.CreateOrUpdateConfigMap(client, kubeproxyConfigMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kubeproxyDaemonSet := &extensions.DaemonSet{}
|
||||
@ -132,20 +116,15 @@ func createKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client clientse
|
||||
return fmt.Errorf("unable to decode kube-proxy daemonset %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(kubeproxyDaemonSet); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create a new kube-proxy daemonset: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Update(kubeproxyDaemonSet); err != nil {
|
||||
return fmt.Errorf("unable to update the kube-proxy daemonset: %v", err)
|
||||
}
|
||||
// Create the DaemonSet for kube-proxy or update it in case it already exists
|
||||
if err := apiclient.CreateOrUpdateDaemonSet(client, kubeproxyDaemonSet); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createClusterRoleBindings(client clientset.Interface) error {
|
||||
return apiclientutil.CreateClusterRoleBindingIfNotExists(client, &rbac.ClusterRoleBinding{
|
||||
return apiclient.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "kubeadm:node-proxier",
|
||||
},
|
||||
@ -157,7 +136,7 @@ func createClusterRoleBindings(client clientset.Interface) error {
|
||||
Subjects: []rbac.Subject{
|
||||
{
|
||||
Kind: rbac.ServiceAccountKind,
|
||||
Name: kubeadmconstants.KubeProxyServiceAccountName,
|
||||
Name: KubeProxyServiceAccountName,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
},
|
||||
|
@ -28,12 +28,12 @@ import (
|
||||
)
|
||||
|
||||
// CreateRBACRules creates the essential RBAC rules for a minimally set-up cluster
|
||||
// TODO: This function and phase package is DEPRECATED.
|
||||
// When the v1.9 cycle starts and deletePermissiveNodesBindingWhenUsingNodeAuthorization can be removed, this package will be removed with it.
|
||||
func CreateRBACRules(client clientset.Interface, k8sVersion *version.Version) error {
|
||||
if err := deletePermissiveNodesBindingWhenUsingNodeAuthorization(client, k8sVersion); err != nil {
|
||||
return fmt.Errorf("failed to remove the permissive 'system:nodes' Group Subject in the 'system:node' ClusterRoleBinding: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("[apiconfig] Created RBAC rules")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
apiclientutil "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1beta1"
|
||||
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
|
||||
)
|
||||
@ -59,7 +59,7 @@ func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, file string
|
||||
}
|
||||
|
||||
// Create or update the ConfigMap in the kube-public namespace
|
||||
return apiclientutil.CreateConfigMapIfNotExists(client, &v1.ConfigMap{
|
||||
return apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: bootstrapapi.ConfigMapClusterInfo,
|
||||
Namespace: metav1.NamespacePublic,
|
||||
@ -72,7 +72,7 @@ func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, file string
|
||||
|
||||
// CreateClusterInfoRBACRules creates the RBAC rules for exposing the cluster-info ConfigMap in the kube-public namespace to unauthenticated users
|
||||
func CreateClusterInfoRBACRules(client clientset.Interface) error {
|
||||
err := apiclientutil.CreateRoleIfNotExists(client, &rbac.Role{
|
||||
err := apiclient.CreateOrUpdateRole(client, &rbac.Role{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: BootstrapSignerClusterRoleName,
|
||||
Namespace: metav1.NamespacePublic,
|
||||
@ -85,7 +85,7 @@ func CreateClusterInfoRBACRules(client clientset.Interface) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return apiclientutil.CreateRoleBindingIfNotExists(client, &rbac.RoleBinding{
|
||||
return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: BootstrapSignerClusterRoleName,
|
||||
Namespace: metav1.NamespacePublic,
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
apiclientutil "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
@ -47,7 +47,7 @@ func AllowBootstrapTokensToPostCSRs(client clientset.Interface) error {
|
||||
|
||||
fmt.Println("[bootstraptoken] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials")
|
||||
|
||||
return apiclientutil.CreateClusterRoleBindingIfNotExists(client, &rbac.ClusterRoleBinding{
|
||||
return apiclient.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: NodeKubeletBootstrap,
|
||||
},
|
||||
@ -73,7 +73,7 @@ func AutoApproveNodeBootstrapTokens(client clientset.Interface, k8sVersion *vers
|
||||
// TODO: When the v1.9 cycle starts (targeting v1.9 at HEAD) and v1.8.0 is the minimum supported version, we can remove this function as the ClusterRole will always exist
|
||||
if k8sVersion.LessThan(constants.MinimumCSRAutoApprovalClusterRolesVersion) {
|
||||
|
||||
err := apiclientutil.CreateClusterRoleIfNotExists(client, &rbac.ClusterRole{
|
||||
err := apiclient.CreateOrUpdateClusterRole(client, &rbac.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: CSRAutoApprovalClusterRoleName,
|
||||
},
|
||||
@ -87,7 +87,7 @@ func AutoApproveNodeBootstrapTokens(client clientset.Interface, k8sVersion *vers
|
||||
}
|
||||
|
||||
// Always create this kubeadm-specific binding though
|
||||
return apiclientutil.CreateClusterRoleBindingIfNotExists(client, &rbac.ClusterRoleBinding{
|
||||
return apiclient.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: NodeAutoApproveBootstrap,
|
||||
},
|
||||
|
@ -32,11 +32,10 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
|
@ -24,13 +24,12 @@ import (
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kuberuntime "k8s.io/apimachinery/pkg/runtime"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
@ -69,19 +68,13 @@ func CreateSelfHostedControlPlane(cfg *kubeadmapi.MasterConfiguration, client cl
|
||||
ds := buildDaemonSet(cfg, componentName, podSpec)
|
||||
|
||||
// Create the DaemonSet in the API Server
|
||||
if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(ds); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("failed to create self-hosted %q daemonset [%v]", componentName, err)
|
||||
}
|
||||
|
||||
if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Update(ds); err != nil {
|
||||
// TODO: We should retry on 409 responses
|
||||
return fmt.Errorf("failed to update self-hosted %q daemonset [%v]", componentName, err)
|
||||
}
|
||||
if err := apiclient.CreateOrUpdateDaemonSet(client, ds); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the self-hosted component to come up
|
||||
kubeadmutil.WaitForPodsWithLabel(client, buildSelfHostedWorkloadLabelQuery(componentName))
|
||||
// TODO: Enforce a timeout
|
||||
apiclient.WaitForPodsWithLabel(client, buildSelfHostedWorkloadLabelQuery(componentName))
|
||||
|
||||
// Remove the old Static Pod manifest
|
||||
if err := os.RemoveAll(manifestPath); err != nil {
|
||||
@ -89,7 +82,8 @@ func CreateSelfHostedControlPlane(cfg *kubeadmapi.MasterConfiguration, client cl
|
||||
}
|
||||
|
||||
// Make sure the API is responsive at /healthz
|
||||
kubeadmutil.WaitForAPI(client)
|
||||
// TODO: Follow-up on fixing the race condition here and respect the timeout error that can be returned
|
||||
apiclient.WaitForAPI(client)
|
||||
|
||||
fmt.Printf("[self-hosted] self-hosted %s ready after %f seconds\n", componentName, time.Since(start).Seconds())
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ go_library(
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
],
|
||||
|
@ -22,12 +22,12 @@ import (
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
@ -45,7 +45,7 @@ func UploadConfiguration(cfg *kubeadmapi.MasterConfiguration, client clientset.I
|
||||
return err
|
||||
}
|
||||
|
||||
cm := &v1.ConfigMap{
|
||||
return apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kubeadmconstants.MasterConfigurationConfigMap,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
@ -53,15 +53,5 @@ func UploadConfiguration(cfg *kubeadmapi.MasterConfiguration, client clientset.I
|
||||
Data: map[string]string{
|
||||
kubeadmconstants.MasterConfigurationConfigMapKey: string(cfgYaml),
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Create(cm); err != nil {
|
||||
if !apierrs.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Update(cm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -9,20 +9,13 @@ load(
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"apiclient.go",
|
||||
"error.go",
|
||||
"template.go",
|
||||
"version.go",
|
||||
],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -7,11 +7,18 @@ load(
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["idempotency.go"],
|
||||
srcs = [
|
||||
"idempotency.go",
|
||||
"wait.go",
|
||||
],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -14,49 +14,77 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
package apiclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
rbac "k8s.io/api/rbac/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// TODO: We should invent a dynamic mechanism for this using the dynamic client instead of hard-coding these functions per-type
|
||||
// TODO: We may want to retry if .Update() fails on 409 Conflict
|
||||
|
||||
// CreateClusterRoleIfNotExists creates a ClusterRole if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateClusterRoleIfNotExists(client clientset.Interface, clusterRole *rbac.ClusterRole) error {
|
||||
if _, err := client.RbacV1beta1().ClusterRoles().Create(clusterRole); err != nil {
|
||||
// CreateOrUpdateConfigMap creates a ConfigMap if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateOrUpdateConfigMap(client clientset.Interface, cm *v1.ConfigMap) error {
|
||||
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Create(cm); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create RBAC clusterrole: %v", err)
|
||||
return fmt.Errorf("unable to create configmap: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.RbacV1beta1().ClusterRoles().Update(clusterRole); err != nil {
|
||||
return fmt.Errorf("unable to update RBAC clusterrole: %v", err)
|
||||
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Update(cm); err != nil {
|
||||
return fmt.Errorf("unable to update configmap: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateClusterRoleBindingIfNotExists creates a ClusterRoleBinding if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateClusterRoleBindingIfNotExists(client clientset.Interface, clusterRoleBinding *rbac.ClusterRoleBinding) error {
|
||||
if _, err := client.RbacV1beta1().ClusterRoleBindings().Create(clusterRoleBinding); err != nil {
|
||||
// CreateOrUpdateServiceAccount creates a ServiceAccount if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateOrUpdateServiceAccount(client clientset.Interface, sa *v1.ServiceAccount) error {
|
||||
if _, err := client.CoreV1().ServiceAccounts(sa.ObjectMeta.Namespace).Create(sa); err != nil {
|
||||
// Note: We don't run .Update here afterwards as that's probably not required
|
||||
// Only thing that could be updated is annotations/labels in .metadata, but we don't use that currently
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create RBAC clusterrolebinding: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.RbacV1beta1().ClusterRoleBindings().Update(clusterRoleBinding); err != nil {
|
||||
return fmt.Errorf("unable to update RBAC clusterrolebinding: %v", err)
|
||||
return fmt.Errorf("unable to create serviceaccount: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateRoleIfNotExists creates a Role if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateRoleIfNotExists(client clientset.Interface, role *rbac.Role) error {
|
||||
// CreateOrUpdateDeployment creates a Deployment if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateOrUpdateDeployment(client clientset.Interface, deploy *extensions.Deployment) error {
|
||||
if _, err := client.ExtensionsV1beta1().Deployments(deploy.ObjectMeta.Namespace).Create(deploy); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create deployment: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.ExtensionsV1beta1().Deployments(deploy.ObjectMeta.Namespace).Update(deploy); err != nil {
|
||||
return fmt.Errorf("unable to update deployment: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateOrUpdateDaemonSet creates a DaemonSet if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateOrUpdateDaemonSet(client clientset.Interface, ds *extensions.DaemonSet) error {
|
||||
if _, err := client.ExtensionsV1beta1().DaemonSets(ds.ObjectMeta.Namespace).Create(ds); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create daemonset: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.ExtensionsV1beta1().DaemonSets(ds.ObjectMeta.Namespace).Update(ds); err != nil {
|
||||
return fmt.Errorf("unable to update daemonset: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if _, err := client.RbacV1beta1().Roles(role.ObjectMeta.Namespace).Create(role); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create RBAC role: %v", err)
|
||||
@ -69,8 +97,8 @@ func CreateRoleIfNotExists(client clientset.Interface, role *rbac.Role) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateRoleBindingIfNotExists creates a RoleBinding if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateRoleBindingIfNotExists(client clientset.Interface, roleBinding *rbac.RoleBinding) 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 {
|
||||
if _, err := client.RbacV1beta1().RoleBindings(roleBinding.ObjectMeta.Namespace).Create(roleBinding); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create RBAC rolebinding: %v", err)
|
||||
@ -83,15 +111,29 @@ func CreateRoleBindingIfNotExists(client clientset.Interface, roleBinding *rbac.
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateConfigMapIfNotExists creates a ConfigMap if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateConfigMapIfNotExists(client clientset.Interface, cm *v1.ConfigMap) error {
|
||||
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Create(cm); err != nil {
|
||||
// CreateOrUpdateClusterRole creates a ClusterRole if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateOrUpdateClusterRole(client clientset.Interface, clusterRole *rbac.ClusterRole) error {
|
||||
if _, err := client.RbacV1beta1().ClusterRoles().Create(clusterRole); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create configmap: %v", err)
|
||||
return fmt.Errorf("unable to create RBAC clusterrole: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Update(cm); err != nil {
|
||||
return fmt.Errorf("unable to update configmap: %v", err)
|
||||
if _, err := client.RbacV1beta1().ClusterRoles().Update(clusterRole); err != nil {
|
||||
return fmt.Errorf("unable to update RBAC clusterrole: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateOrUpdateClusterRoleBinding creates a ClusterRoleBinding if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateOrUpdateClusterRoleBinding(client clientset.Interface, clusterRoleBinding *rbac.ClusterRoleBinding) error {
|
||||
if _, err := client.RbacV1beta1().ClusterRoleBindings().Create(clusterRoleBinding); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create RBAC clusterrolebinding: %v", err)
|
||||
}
|
||||
|
||||
if _, err := client.RbacV1beta1().ClusterRoleBindings().Update(clusterRoleBinding); err != nil {
|
||||
return fmt.Errorf("unable to update RBAC clusterrolebinding: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
package apiclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -26,22 +26,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||
)
|
||||
|
||||
// CreateClientAndWaitForAPI takes a path to a kubeconfig file, makes a client of it and waits for the API to be healthy
|
||||
func CreateClientAndWaitForAPI(file string) (*clientset.Clientset, error) {
|
||||
client, err := kubeconfigutil.ClientSetFromFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Println("[apiclient] Created API client, waiting for the control plane to become ready")
|
||||
WaitForAPI(client)
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// WaitForAPI waits for the API Server's /healthz endpoint to report "ok"
|
||||
func WaitForAPI(client clientset.Interface) {
|
||||
start := time.Now()
|
Loading…
Reference in New Issue
Block a user