Skip to content
Permalink
Browse files

⚠️ Move Status.APIEndpoints to Spec.ControlPlaneEndpoint

Signed-off-by: Vince Prignano <vincepri@vmware.com>
  • Loading branch information
vincepri committed Nov 20, 2019
1 parent 7ef40d7 commit 86b014131e13c592bb8b6b09483bcd76cf1bbb42
@@ -28,14 +28,39 @@ import (
func (src *Cluster) ConvertTo(dstRaw conversion.Hub) error {
dst := dstRaw.(*v1alpha3.Cluster)

return Convert_v1alpha2_Cluster_To_v1alpha3_Cluster(src, dst, nil)
if err := Convert_v1alpha2_Cluster_To_v1alpha3_Cluster(src, dst, nil); err != nil {
return err
}

// Manually convert Status.APIEndpoints to Spec.ControlPlaneEndpoint.
if len(src.Status.APIEndpoints) > 0 {
endpoint := src.Status.APIEndpoints[0]
dst.Spec.ControlPlaneEndpoint.Host = endpoint.Host
dst.Spec.ControlPlaneEndpoint.Port = int32(endpoint.Port)
}

return nil
}

// nolint
func (dst *Cluster) ConvertFrom(srcRaw conversion.Hub) error {
src := srcRaw.(*v1alpha3.Cluster)

return Convert_v1alpha3_Cluster_To_v1alpha2_Cluster(src, dst, nil)
if err := Convert_v1alpha3_Cluster_To_v1alpha2_Cluster(src, dst, nil); err != nil {
return err
}

// Manually convert Spec.ControlPlaneEndpoint to Status.APIEndpoints.
if !src.Spec.ControlPlaneEndpoint.IsZero() {
dst.Status.APIEndpoints = []APIEndpoint{
{
Host: src.Spec.ControlPlaneEndpoint.Host,
Port: int(src.Spec.ControlPlaneEndpoint.Port),
},
}
}

return nil
}

func (src *ClusterList) ConvertTo(dstRaw conversion.Hub) error {
@@ -139,6 +164,13 @@ func Convert_v1alpha2_MachineSpec_To_v1alpha3_MachineSpec(in *MachineSpec, out *
return nil
}

func Convert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(in *ClusterSpec, out *v1alpha3.ClusterSpec, s apiconversion.Scope) error {
if err := autoConvert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(in, out, s); err != nil {
return err
}
return nil
}

func Convert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(in *ClusterStatus, out *v1alpha3.ClusterStatus, s apiconversion.Scope) error {
if err := autoConvert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(in, out, s); err != nil {
return err
@@ -199,6 +231,13 @@ func Convert_v1alpha2_MachineStatus_To_v1alpha3_MachineStatus(in *MachineStatus,
return nil
}

func Convert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(in *v1alpha3.ClusterSpec, out *ClusterSpec, s apiconversion.Scope) error {
if err := autoConvert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(in, out, s); err != nil {
return err
}
return nil
}

func Convert_v1alpha3_MachineStatus_To_v1alpha2_MachineStatus(in *v1alpha3.MachineStatus, out *MachineStatus, s apiconversion.Scope) error {
if err := autoConvert_v1alpha3_MachineStatus_To_v1alpha2_MachineStatus(in, out, s); err != nil {
return err
@@ -288,6 +288,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*ClusterSpec)(nil), (*v1alpha3.ClusterSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(a.(*ClusterSpec), b.(*v1alpha3.ClusterSpec), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*ClusterStatus)(nil), (*v1alpha3.ClusterStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(a.(*ClusterStatus), b.(*v1alpha3.ClusterStatus), scope)
}); err != nil {
@@ -308,6 +313,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*v1alpha3.ClusterSpec)(nil), (*ClusterSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(a.(*v1alpha3.ClusterSpec), b.(*ClusterSpec), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*v1alpha3.ClusterStatus)(nil), (*ClusterStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha3_ClusterStatus_To_v1alpha2_ClusterStatus(a.(*v1alpha3.ClusterStatus), b.(*ClusterStatus), scope)
}); err != nil {
@@ -496,34 +506,15 @@ func autoConvert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(in *ClusterSpec, o
return nil
}

// Convert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec is an autogenerated conversion function.
func Convert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(in *ClusterSpec, out *v1alpha3.ClusterSpec, s conversion.Scope) error {
return autoConvert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(in, out, s)
}

func autoConvert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(in *v1alpha3.ClusterSpec, out *ClusterSpec, s conversion.Scope) error {
out.ClusterNetwork = (*ClusterNetwork)(unsafe.Pointer(in.ClusterNetwork))
// WARNING: in.ControlPlaneEndpoint requires manual conversion: does not exist in peer-type
out.InfrastructureRef = (*v1.ObjectReference)(unsafe.Pointer(in.InfrastructureRef))
return nil
}

// Convert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec is an autogenerated conversion function.
func Convert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(in *v1alpha3.ClusterSpec, out *ClusterSpec, s conversion.Scope) error {
return autoConvert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(in, out, s)
}

func autoConvert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(in *ClusterStatus, out *v1alpha3.ClusterStatus, s conversion.Scope) error {
if in.APIEndpoints != nil {
in, out := &in.APIEndpoints, &out.APIEndpoints
*out = make([]v1alpha3.APIEndpoint, len(*in))
for i := range *in {
if err := Convert_v1alpha2_APIEndpoint_To_v1alpha3_APIEndpoint(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.APIEndpoints = nil
}
// WARNING: in.APIEndpoints requires manual conversion: does not exist in peer-type
// WARNING: in.ErrorReason requires manual conversion: does not exist in peer-type
// WARNING: in.ErrorMessage requires manual conversion: does not exist in peer-type
out.Phase = in.Phase
@@ -533,17 +524,6 @@ func autoConvert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(in *ClusterSta
}

func autoConvert_v1alpha3_ClusterStatus_To_v1alpha2_ClusterStatus(in *v1alpha3.ClusterStatus, out *ClusterStatus, s conversion.Scope) error {
if in.APIEndpoints != nil {
in, out := &in.APIEndpoints, &out.APIEndpoints
*out = make([]APIEndpoint, len(*in))
for i := range *in {
if err := Convert_v1alpha3_APIEndpoint_To_v1alpha2_APIEndpoint(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.APIEndpoints = nil
}
// WARNING: in.FailureReason requires manual conversion: does not exist in peer-type
// WARNING: in.FailureMessage requires manual conversion: does not exist in peer-type
out.Phase = in.Phase
@@ -17,6 +17,8 @@ limitations under the License.
package v1alpha3

import (
"fmt"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
capierrors "sigs.k8s.io/cluster-api/errors"
@@ -34,6 +36,10 @@ type ClusterSpec struct {
// +optional
ClusterNetwork *ClusterNetwork `json:"clusterNetwork,omitempty"`

// ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
// +optional
ControlPlaneEndpoint APIEndpoint `json:"controlPlaneEndpoint"`

// InfrastructureRef is a reference to a provider-specific resource that holds the details
// for provisioning infrastructure for a cluster in said provider.
// +optional
@@ -79,10 +85,6 @@ type NetworkRanges struct {

// ClusterStatus defines the observed state of Cluster
type ClusterStatus struct {
// APIEndpoints represents the endpoints to communicate with the control plane.
// +optional
APIEndpoints []APIEndpoint `json:"apiEndpoints,omitempty"`

// FailureReason indicates that there is a fatal problem reconciling the
// state, and will be set to a token value suitable for
// programmatic interpretation.
@@ -142,6 +144,16 @@ type APIEndpoint struct {
Port int32 `json:"port"`
}

// IsZero returns true if either the host or the port are zero values.
func (v APIEndpoint) IsZero() bool {
return v.Host == "" || v.Port == 0
}

// String returns a formatted version HOST:PORT of this APIEndpoint.
func (v APIEndpoint) String() string {
return fmt.Sprintf("%s:%d", v.Host, v.Port)
}

// ANCHOR_END: APIEndpoint

// +kubebuilder:object:root=true
@@ -491,12 +491,11 @@ func (r *KubeadmConfigReconciler) reconcileDiscovery(cluster *clusterv1.Cluster,
// if BootstrapToken already contains an APIServerEndpoint, respect it; otherwise inject the APIServerEndpoint endpoint defined in cluster status
apiServerEndpoint := config.Spec.JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint
if apiServerEndpoint == "" {
if len(cluster.Status.APIEndpoints) == 0 {
return errors.Wrap(&capierrors.RequeueAfterError{RequeueAfter: 10 * time.Second}, "Waiting for Cluster Controller to set cluster.Status.APIEndpoints")
if cluster.Spec.ControlPlaneEndpoint.IsZero() {
return errors.Wrap(&capierrors.RequeueAfterError{RequeueAfter: 10 * time.Second}, "Waiting for Cluster Controller to set Cluster.Spec.ControlPlaneEndpoint")
}

// NB. CABPK only uses the first APIServerEndpoint defined in cluster status if there are multiple defined.
apiServerEndpoint = fmt.Sprintf("%s:%d", cluster.Status.APIEndpoints[0].Host, cluster.Status.APIEndpoints[0].Port)
apiServerEndpoint = cluster.Spec.ControlPlaneEndpoint.String()
config.Spec.JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint = apiServerEndpoint
log.Info("Altering JoinConfiguration.Discovery.BootstrapToken", "APIServerEndpoint", apiServerEndpoint)
}
@@ -531,11 +530,11 @@ func (r *KubeadmConfigReconciler) reconcileDiscovery(cluster *clusterv1.Cluster,
func (r *KubeadmConfigReconciler) reconcileTopLevelObjectSettings(cluster *clusterv1.Cluster, machine *clusterv1.Machine, config *bootstrapv1.KubeadmConfig) {
log := r.Log.WithValues("kubeadmconfig", fmt.Sprintf("%s/%s", config.Namespace, config.Name))

// If there are no ControlPlaneEndpoint defined in ClusterConfiguration but there are APIEndpoints defined at cluster level (e.g. the load balancer endpoint),
// then use cluster APIEndpoints as a control plane endpoint for the K8s cluster
if config.Spec.ClusterConfiguration.ControlPlaneEndpoint == "" && len(cluster.Status.APIEndpoints) > 0 {
// NB. CABPK only uses the first APIServerEndpoint defined in cluster status if there are multiple defined.
config.Spec.ClusterConfiguration.ControlPlaneEndpoint = fmt.Sprintf("%s:%d", cluster.Status.APIEndpoints[0].Host, cluster.Status.APIEndpoints[0].Port)
// If there is no ControlPlaneEndpoint defined in ClusterConfiguration but
// there is a ControlPlaneEndpoint defined at Cluster level (e.g. the load balancer endpoint),
// then use Cluster's ControlPlaneEndpoint as a control plane endpoint for the Kubernetes cluster.
if config.Spec.ClusterConfiguration.ControlPlaneEndpoint == "" && !cluster.Spec.ControlPlaneEndpoint.IsZero() {
config.Spec.ClusterConfiguration.ControlPlaneEndpoint = cluster.Spec.ControlPlaneEndpoint.String()
log.Info("Altering ClusterConfiguration", "ControlPlaneEndpoint", config.Spec.ClusterConfiguration.ControlPlaneEndpoint)
}

@@ -454,7 +454,7 @@ func TestKubeadmConfigReconciler_Reconcile_ErrorIfJoiningControlPlaneHasInvalidC
cluster := newCluster("cluster")
cluster.Status.InfrastructureReady = true
cluster.Status.ControlPlaneInitialized = true
cluster.Status.APIEndpoints = []clusterv1.APIEndpoint{{Host: "100.105.150.1", Port: 6443}}
cluster.Spec.ControlPlaneEndpoint = clusterv1.APIEndpoint{Host: "100.105.150.1", Port: 6443}
controlPlaneInitMachine := newControlPlaneMachine(cluster, "control-plane-init-machine")
controlPlaneInitConfig := newControlPlaneInitKubeadmConfig(controlPlaneInitMachine, "control-plane-init-cfg")

@@ -543,7 +543,7 @@ func TestReconcileIfJoinNodesAndControlPlaneIsReady(t *testing.T) {
cluster := newCluster("cluster")
cluster.Status.InfrastructureReady = true
cluster.Status.ControlPlaneInitialized = true
cluster.Status.APIEndpoints = []clusterv1.APIEndpoint{{Host: "100.105.150.1", Port: 6443}}
cluster.Spec.ControlPlaneEndpoint = clusterv1.APIEndpoint{Host: "100.105.150.1", Port: 6443}

var useCases = []struct {
name string
@@ -646,7 +646,7 @@ func TestBootstrapTokenTTLExtension(t *testing.T) {
cluster := newCluster("cluster")
cluster.Status.InfrastructureReady = true
cluster.Status.ControlPlaneInitialized = true
cluster.Status.APIEndpoints = []clusterv1.APIEndpoint{{Host: "100.105.150.1", Port: 6443}}
cluster.Spec.ControlPlaneEndpoint = clusterv1.APIEndpoint{Host: "100.105.150.1", Port: 6443}

controlPlaneInitMachine := newControlPlaneMachine(cluster, "control-plane-init-machine")
initConfig := newControlPlaneInitKubeadmConfig(controlPlaneInitMachine, "control-plane-init-config")
@@ -856,12 +856,10 @@ func TestKubeadmConfigReconciler_Reconcile_DisocveryReconcileBehaviors(t *testin
},
}
goodcluster := &clusterv1.Cluster{
Status: clusterv1.ClusterStatus{
APIEndpoints: []clusterv1.APIEndpoint{
{
Host: "example.com",
Port: 6443,
},
Spec: clusterv1.ClusterSpec{
ControlPlaneEndpoint: clusterv1.APIEndpoint{
Host: "example.com",
Port: 6443,
},
},
}
@@ -1015,7 +1013,7 @@ func TestKubeadmConfigReconciler_Reconcile_DisocveryReconcileFailureBehaviors(t
config *bootstrapv1.KubeadmConfig
}{
{
name: "Fail if cluster has not APIEndpoints",
name: "Fail if cluster has not ControlPlaneEndpoint",
cluster: &clusterv1.Cluster{}, // cluster without endpoints
config: &bootstrapv1.KubeadmConfig{
Spec: bootstrapv1.KubeadmConfigSpec{
@@ -1080,9 +1078,7 @@ func TestKubeadmConfigReconciler_Reconcile_DynamicDefaultsForClusterConfiguratio
Pods: &clusterv1.NetworkRanges{CIDRBlocks: []string{"otherPodsCidr"}},
ServiceDomain: "otherServiceDomain",
},
},
Status: clusterv1.ClusterStatus{
APIEndpoints: []clusterv1.APIEndpoint{{Host: "otherVersion", Port: 0}},
ControlPlaneEndpoint: clusterv1.APIEndpoint{Host: "otherVersion", Port: 0},
},
},
machine: &clusterv1.Machine{
@@ -1108,9 +1104,7 @@ func TestKubeadmConfigReconciler_Reconcile_DynamicDefaultsForClusterConfiguratio
Pods: &clusterv1.NetworkRanges{CIDRBlocks: []string{"myPodSubnet"}},
ServiceDomain: "myDNSDomain",
},
},
Status: clusterv1.ClusterStatus{
APIEndpoints: []clusterv1.APIEndpoint{{Host: "myControlPlaneEndpoint", Port: 6443}},
ControlPlaneEndpoint: clusterv1.APIEndpoint{Host: "myControlPlaneEndpoint", Port: 6443},
},
},
machine: &clusterv1.Machine{
@@ -1154,11 +1148,9 @@ func TestKubeadmConfigReconciler_Reconcile_AlwaysCheckCAVerificationUnlessReques
cluster := newCluster(clusterName)
cluster.Status.ControlPlaneInitialized = true
cluster.Status.InfrastructureReady = true
cluster.Status.APIEndpoints = []clusterv1.APIEndpoint{
{
Host: "example.com",
Port: 6443,
},
cluster.Spec.ControlPlaneEndpoint = clusterv1.APIEndpoint{
Host: "example.com",
Port: 6443,
}
controlPlaneInitMachine := newControlPlaneMachine(cluster, "my-control-plane-init-machine")
initConfig := newControlPlaneInitKubeadmConfig(controlPlaneInitMachine, "my-control-plane-init-config")
@@ -39,27 +39,22 @@ import (
)

func (r *ClusterReconciler) reconcilePhase(_ context.Context, cluster *clusterv1.Cluster) {
// Set the phase to "pending" if nil.
if cluster.Status.Phase == "" {
cluster.Status.SetTypedPhase(clusterv1.ClusterPhasePending)
}

// Set the phase to "provisioning" if the Cluster has an InfrastructureRef object associated.
if cluster.Spec.InfrastructureRef != nil {
cluster.Status.SetTypedPhase(clusterv1.ClusterPhaseProvisioning)
}

// Set the phase to "provisioned" if the infrastructure is ready and APIEndpoints exists
if cluster.Status.InfrastructureReady && len(cluster.Status.APIEndpoints) > 0 {
if cluster.Status.InfrastructureReady && !cluster.Spec.ControlPlaneEndpoint.IsZero() {
cluster.Status.SetTypedPhase(clusterv1.ClusterPhaseProvisioned)
}

// Set the phase to "failed" if any of Status.FailureReason or Status.FailureMessage is not-nil.
if cluster.Status.FailureReason != nil || cluster.Status.FailureMessage != nil {
cluster.Status.SetTypedPhase(clusterv1.ClusterPhaseFailed)
}

// Set the phase to "deleting" if the deletion timestamp is set.
if !cluster.DeletionTimestamp.IsZero() {
cluster.Status.SetTypedPhase(clusterv1.ClusterPhaseDeleting)
}
@@ -174,12 +169,9 @@ func (r *ClusterReconciler) reconcileInfrastructure(ctx context.Context, cluster
}

// Get and parse Status.APIEndpoint field from the infrastructure provider.
if len(cluster.Status.APIEndpoints) == 0 {
if err := util.UnstructuredUnmarshalField(infraConfig, &cluster.Status.APIEndpoints, "status", "apiEndpoints"); err != nil {
return errors.Wrapf(err, "failed to retrieve Status.APIEndpoints from infrastructure provider for Cluster %q in namespace %q",
cluster.Name, cluster.Namespace)
} else if len(cluster.Status.APIEndpoints) == 0 {
return errors.Wrapf(err, "retrieved empty Status.APIEndpoints from infrastructure provider for Cluster %q in namespace %q",
if cluster.Spec.ControlPlaneEndpoint.IsZero() {
if err := util.UnstructuredUnmarshalField(infraConfig, &cluster.Spec.ControlPlaneEndpoint, "spec", "controlPlaneEndpoint"); err != nil {
return errors.Wrapf(err, "failed to retrieve Spec.ControlPlaneEndpoint from infrastructure provider for Cluster %q in namespace %q",
cluster.Name, cluster.Namespace)
}
}
@@ -188,7 +180,7 @@ func (r *ClusterReconciler) reconcileInfrastructure(ctx context.Context, cluster
}

func (r *ClusterReconciler) reconcileKubeconfig(ctx context.Context, cluster *clusterv1.Cluster) error {
if len(cluster.Status.APIEndpoints) == 0 {
if cluster.Spec.ControlPlaneEndpoint.IsZero() {
return nil
}

0 comments on commit 86b0141

Please sign in to comment.
You can’t perform that action at this time.