mirror of https://github.com/k3s-io/k3s
Merge pull request #73163 from MalloZup/phases-preflight
expose preflight join as phasespull/564/head
commit
f2ade8e993
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -38,6 +37,7 @@ import (
|
||||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
||||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
|
@ -68,17 +68,6 @@ var (
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
|
||||||
notReadyToJoinControPlaneTemp = template.Must(template.New("join").Parse(dedent.Dedent(`
|
|
||||||
One or more conditions for hosting a new control plane instance is not satisfied.
|
|
||||||
|
|
||||||
{{.Error}}
|
|
||||||
|
|
||||||
Please ensure that:
|
|
||||||
* The cluster has a stable controlPlaneEndpoint address.
|
|
||||||
* The certificates that must be shared among control plane instances are provided.
|
|
||||||
|
|
||||||
`)))
|
|
||||||
|
|
||||||
joinControPlaneDoneTemp = template.Must(template.New("join").Parse(dedent.Dedent(`
|
joinControPlaneDoneTemp = template.Must(template.New("join").Parse(dedent.Dedent(`
|
||||||
This node has joined the cluster and a new control plane instance was created:
|
This node has joined the cluster and a new control plane instance was created:
|
||||||
|
|
||||||
|
@ -210,9 +199,7 @@ func NewCmdJoin(out io.Writer, joinOptions *joinOptions) *cobra.Command {
|
||||||
AddJoinConfigFlags(cmd.Flags(), joinOptions.externalcfg)
|
AddJoinConfigFlags(cmd.Flags(), joinOptions.externalcfg)
|
||||||
AddJoinOtherFlags(cmd.Flags(), &joinOptions.cfgPath, &joinOptions.ignorePreflightErrors, &joinOptions.controlPlane, &joinOptions.token)
|
AddJoinOtherFlags(cmd.Flags(), &joinOptions.cfgPath, &joinOptions.ignorePreflightErrors, &joinOptions.controlPlane, &joinOptions.token)
|
||||||
|
|
||||||
// initialize the workflow runner with the list of phases
|
joinRunner.AppendPhase(phases.NewPreflightJoinPhase())
|
||||||
// TODO: append phases here like so:
|
|
||||||
// joinRunner.AppendPhase(phases.NewPreflightMasterPhase())
|
|
||||||
|
|
||||||
// sets the data builder function, that will be used by the runner
|
// sets the data builder function, that will be used by the runner
|
||||||
// both when running the entire workflow or single phases
|
// both when running the entire workflow or single phases
|
||||||
|
@ -445,14 +432,6 @@ func (j *joinData) OutputWriter() io.Writer {
|
||||||
|
|
||||||
// Run executes worker node provisioning and tries to join an existing cluster.
|
// Run executes worker node provisioning and tries to join an existing cluster.
|
||||||
func (j *joinData) Run() error {
|
func (j *joinData) Run() error {
|
||||||
fmt.Println("[preflight] Running pre-flight checks")
|
|
||||||
|
|
||||||
// Start with general checks
|
|
||||||
klog.V(1).Infoln("[preflight] Running general checks")
|
|
||||||
if err := preflight.RunJoinNodeChecks(utilsexec.New(), j.cfg, j.ignorePreflightErrors); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the init configuration based on the join configuration.
|
// Fetch the init configuration based on the join configuration.
|
||||||
// TODO: individual phases should call these:
|
// TODO: individual phases should call these:
|
||||||
// - phases that need initCfg should call joinData.InitCfg().
|
// - phases that need initCfg should call joinData.InitCfg().
|
||||||
|
@ -465,35 +444,7 @@ func (j *joinData) Run() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue with more specific checks based on the init configuration
|
|
||||||
klog.V(1).Infoln("[preflight] Running configuration dependant checks")
|
|
||||||
if err := preflight.RunOptionalJoinNodeChecks(utilsexec.New(), &initCfg.ClusterConfiguration, j.ignorePreflightErrors); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if j.cfg.ControlPlane != nil {
|
if j.cfg.ControlPlane != nil {
|
||||||
// Checks if the cluster configuration supports
|
|
||||||
// joining a new control plane instance and if all the necessary certificates are provided
|
|
||||||
if err := j.CheckIfReadyForAdditionalControlPlane(&initCfg.ClusterConfiguration); err != nil {
|
|
||||||
// outputs the not ready for hosting a new control plane instance message
|
|
||||||
ctx := map[string]string{
|
|
||||||
"Error": err.Error(),
|
|
||||||
}
|
|
||||||
|
|
||||||
var msg bytes.Buffer
|
|
||||||
notReadyToJoinControPlaneTemp.Execute(&msg, ctx)
|
|
||||||
return errors.New(msg.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// run kubeadm init preflight checks for checking all the prequisites
|
|
||||||
fmt.Println("[join] Running pre-flight checks before initializing the new control plane instance")
|
|
||||||
preflight.RunInitMasterChecks(utilsexec.New(), initCfg, j.ignorePreflightErrors)
|
|
||||||
|
|
||||||
fmt.Println("[join] Pulling control-plane images")
|
|
||||||
if err := preflight.RunPullImagesCheck(utilsexec.New(), initCfg, j.ignorePreflightErrors); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Prepares the node for hosting a new control plane instance by writing necessary
|
// Prepares the node for hosting a new control plane instance by writing necessary
|
||||||
// kubeconfig files, and static pod manifests
|
// kubeconfig files, and static pod manifests
|
||||||
if err := j.PrepareForHostingControlPlane(initCfg); err != nil {
|
if err := j.PrepareForHostingControlPlane(initCfg); err != nil {
|
||||||
|
@ -539,22 +490,6 @@ func (j *joinData) Run() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckIfReadyForAdditionalControlPlane ensures that the cluster is in a state that supports
|
|
||||||
// joining an additional control plane instance and if the node is ready to join
|
|
||||||
func (j *joinData) CheckIfReadyForAdditionalControlPlane(cfg *kubeadmapi.ClusterConfiguration) error {
|
|
||||||
// blocks if the cluster was created without a stable control plane endpoint
|
|
||||||
if cfg.ControlPlaneEndpoint == "" {
|
|
||||||
return errors.New("unable to add a new control plane instance a cluster that doesn't have a stable controlPlaneEndpoint address")
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks if the certificates that must be equal across contolplane instances are provided
|
|
||||||
if ret, err := certsphase.SharedCertificateExists(cfg); !ret {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrepareForHostingControlPlane makes all preparation activities require for a node hosting a new control plane instance
|
// PrepareForHostingControlPlane makes all preparation activities require for a node hosting a new control plane instance
|
||||||
func (j *joinData) PrepareForHostingControlPlane(initConfiguration *kubeadmapi.InitConfiguration) error {
|
func (j *joinData) PrepareForHostingControlPlane(initConfiguration *kubeadmapi.InitConfiguration) error {
|
||||||
|
|
||||||
|
|
|
@ -17,23 +17,43 @@ limitations under the License.
|
||||||
package phases
|
package phases
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/lithammer/dedent"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/klog"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
||||||
"k8s.io/kubernetes/pkg/util/normalizer"
|
"k8s.io/kubernetes/pkg/util/normalizer"
|
||||||
utilsexec "k8s.io/utils/exec"
|
utilsexec "k8s.io/utils/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
masterPreflightExample = normalizer.Examples(`
|
initPreflightExample = normalizer.Examples(`
|
||||||
# Run master pre-flight checks using a config file.
|
# Run master pre-flight checks using a config file.
|
||||||
kubeadm init phase preflight --config kubeadm-config.yml
|
kubeadm init phase preflight --config kubeadm-config.yml
|
||||||
`)
|
`)
|
||||||
|
joinPreflightExample = normalizer.Examples(`
|
||||||
|
# Run join pre-flight checks using a config file.
|
||||||
|
kubeadm join phase preflight --config kubeadm-config.yml
|
||||||
|
`)
|
||||||
|
|
||||||
|
notReadyToJoinControPlaneTemp = template.Must(template.New("join").Parse(dedent.Dedent(`
|
||||||
|
One or more conditions for hosting a new control plane instance is not satisfied.
|
||||||
|
|
||||||
|
{{.Error}}
|
||||||
|
|
||||||
|
Please ensure that:
|
||||||
|
* The cluster has a stable controlPlaneEndpoint address.
|
||||||
|
* The certificates that must be shared among control plane instances are provided.
|
||||||
|
|
||||||
|
`)))
|
||||||
)
|
)
|
||||||
|
|
||||||
// preflightMasterData defines the behavior that a runtime data struct passed to the PreflightMaster master phase
|
// preflightMasterData defines the behavior that a runtime data struct passed to the PreflightMaster master phase
|
||||||
|
@ -45,13 +65,19 @@ type preflightMasterData interface {
|
||||||
IgnorePreflightErrors() sets.String
|
IgnorePreflightErrors() sets.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type preflightJoinData interface {
|
||||||
|
Cfg() *kubeadmapi.JoinConfiguration
|
||||||
|
InitCfg() (*kubeadmapi.InitConfiguration, error)
|
||||||
|
IgnorePreflightErrors() sets.String
|
||||||
|
}
|
||||||
|
|
||||||
// NewPreflightMasterPhase creates a kubeadm workflow phase that implements preflight checks for a new master node.
|
// NewPreflightMasterPhase creates a kubeadm workflow phase that implements preflight checks for a new master node.
|
||||||
func NewPreflightMasterPhase() workflow.Phase {
|
func NewPreflightMasterPhase() workflow.Phase {
|
||||||
return workflow.Phase{
|
return workflow.Phase{
|
||||||
Name: "preflight",
|
Name: "preflight",
|
||||||
Short: "Run master pre-flight checks",
|
Short: "Run master pre-flight checks",
|
||||||
Long: "Run master pre-flight checks, functionally equivalent to what implemented by kubeadm init.",
|
Long: "Run master pre-flight checks, functionally equivalent to what implemented by kubeadm init.",
|
||||||
Example: masterPreflightExample,
|
Example: initPreflightExample,
|
||||||
Run: runPreflightMaster,
|
Run: runPreflightMaster,
|
||||||
InheritFlags: []string{
|
InheritFlags: []string{
|
||||||
options.CfgPath,
|
options.CfgPath,
|
||||||
|
@ -60,6 +86,7 @@ func NewPreflightMasterPhase() workflow.Phase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(dmaiocchi): rename all instances of master to controlPlane in this file.
|
||||||
// runPreflightMaster executes preflight checks logic.
|
// runPreflightMaster executes preflight checks logic.
|
||||||
func runPreflightMaster(c workflow.RunData) error {
|
func runPreflightMaster(c workflow.RunData) error {
|
||||||
data, ok := c.(preflightMasterData)
|
data, ok := c.(preflightMasterData)
|
||||||
|
@ -85,3 +112,96 @@ func runPreflightMaster(c workflow.RunData) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPreflightJoinPhase creates a kubeadm workflow phase that implements preflight checks for a new node join
|
||||||
|
func NewPreflightJoinPhase() workflow.Phase {
|
||||||
|
return workflow.Phase{
|
||||||
|
Name: "preflight",
|
||||||
|
Short: "Run join pre-flight checks",
|
||||||
|
Long: "Run join pre-flight checks, functionally equivalent to what is implemented by kubeadm join.",
|
||||||
|
Example: joinPreflightExample,
|
||||||
|
Run: runPreflightJoin,
|
||||||
|
InheritFlags: []string{
|
||||||
|
options.CfgPath,
|
||||||
|
options.IgnorePreflightErrors,
|
||||||
|
options.TLSBootstrapToken,
|
||||||
|
options.TokenStr,
|
||||||
|
options.ControlPlane,
|
||||||
|
options.APIServerAdvertiseAddress,
|
||||||
|
options.APIServerBindPort,
|
||||||
|
options.NodeCRISocket,
|
||||||
|
options.NodeName,
|
||||||
|
options.FileDiscovery,
|
||||||
|
options.TokenDiscovery,
|
||||||
|
options.TokenDiscoveryCAHash,
|
||||||
|
options.TokenDiscoverySkipCAHash,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// runPreflightJoin executes preflight checks logic.
|
||||||
|
func runPreflightJoin(c workflow.RunData) error {
|
||||||
|
j, ok := c.(preflightJoinData)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("preflight phase invoked with an invalid data struct")
|
||||||
|
}
|
||||||
|
// Start with general checks
|
||||||
|
klog.V(1).Infoln("[preflight] Running general checks")
|
||||||
|
if err := preflight.RunJoinNodeChecks(utilsexec.New(), j.Cfg(), j.IgnorePreflightErrors()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
initCfg, err := j.InitCfg()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with more specific checks based on the init configuration
|
||||||
|
klog.V(1).Infoln("[preflight] Running configuration dependant checks")
|
||||||
|
if err := preflight.RunOptionalJoinNodeChecks(utilsexec.New(), &initCfg.ClusterConfiguration, j.IgnorePreflightErrors()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if j.Cfg().ControlPlane != nil {
|
||||||
|
// Checks if the cluster configuration supports
|
||||||
|
// joining a new control plane instance and if all the necessary certificates are provided
|
||||||
|
if err := checkIfReadyForAdditionalControlPlane(&initCfg.ClusterConfiguration); err != nil {
|
||||||
|
// outputs the not ready for hosting a new control plane instance message
|
||||||
|
ctx := map[string]string{
|
||||||
|
"Error": err.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg bytes.Buffer
|
||||||
|
notReadyToJoinControPlaneTemp.Execute(&msg, ctx)
|
||||||
|
return errors.New(msg.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// run kubeadm init preflight checks for checking all the prequisites
|
||||||
|
fmt.Println("[preflight] Running pre-flight checks before initializing the new control plane instance")
|
||||||
|
if err := preflight.RunInitMasterChecks(utilsexec.New(), initCfg, j.IgnorePreflightErrors()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[preflight] Pulling control-plane images")
|
||||||
|
if err := preflight.RunPullImagesCheck(utilsexec.New(), initCfg, j.IgnorePreflightErrors()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkIfReadyForAdditionalControlPlane ensures that the cluster is in a state that supports
|
||||||
|
// joining an additional control plane instance and if the node is ready to preflight
|
||||||
|
func checkIfReadyForAdditionalControlPlane(initConfiguration *kubeadmapi.ClusterConfiguration) error {
|
||||||
|
// blocks if the cluster was created without a stable control plane endpoint
|
||||||
|
if initConfiguration.ControlPlaneEndpoint == "" {
|
||||||
|
return errors.New("unable to add a new control plane instance a cluster that doesn't have a stable controlPlaneEndpoint address")
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if the certificates that must be equal across contolplane instances are provided
|
||||||
|
if ret, err := certs.SharedCertificateExists(initConfiguration); !ret {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue