Skip to content

Commit

Permalink
ClusterClass: propagate metadata to machines
Browse files Browse the repository at this point in the history
Signed-off-by: Stefan Büringer [email protected]

Co-authored-by: fabriziopandini <[email protected]>
  • Loading branch information
sbueringer and fabriziopandini committed Aug 27, 2021
1 parent b3a86a7 commit d2f6425
Show file tree
Hide file tree
Showing 14 changed files with 165 additions and 98 deletions.
7 changes: 7 additions & 0 deletions api/v1alpha4/cluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ type Topology struct {

// ControlPlaneTopology specifies the parameters for the control plane nodes in the cluster.
type ControlPlaneTopology struct {
// Metadata is the metadata applied to the machines of the ControlPlane.
// At runtime this metadata is merged with the corresponding metadata from the ClusterClass.
//
// This field is supported if and only if the control plane provider template
// referenced in the ClusterClass is Machine based.
Metadata ObjectMeta `json:"metadata,omitempty"`

// Replicas is the number of control plane nodes.
Expand All @@ -112,6 +117,8 @@ type WorkersTopology struct {
// MachineDeploymentTopology specifies the different parameters for a set of worker nodes in the topology.
// This set of nodes is managed by a MachineDeployment object whose lifecycle is managed by the Cluster controller.
type MachineDeploymentTopology struct {
// Metadata is the metadata applied to the machines of the MachineDeployment.
// At runtime this metadata is merged with the corresponding metadata from the ClusterClass.
Metadata ObjectMeta `json:"metadata,omitempty"`

// Class is the name of the MachineDeploymentClass used to create the set of worker nodes.
Expand Down
7 changes: 7 additions & 0 deletions api/v1alpha4/clusterclass_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ type ClusterClassSpec struct {

// ControlPlaneClass defines the class for the control plane.
type ControlPlaneClass struct {
// Metadata is the metadata applied to the machines of the ControlPlane.
// At runtime this metadata is merged with the corresponding metadata from the topology.
//
// This field is supported if and only if the control plane provider template
// referenced is Machine based.
Metadata ObjectMeta `json:"metadata,omitempty"`

// LocalObjectTemplate contains the reference to the control plane provider.
Expand Down Expand Up @@ -93,6 +98,8 @@ type MachineDeploymentClass struct {
// MachineDeploymentClassTemplate defines how a MachineDeployment generated from a MachineDeploymentClass
// should look like.
type MachineDeploymentClassTemplate struct {
// Metadata is the metadata applied to the machines of the MachineDeployment.
// At runtime this metadata is merged with the corresponding metadata from the topology.
Metadata ObjectMeta `json:"metadata,omitempty"`

// Bootstrap contains the bootstrap template reference to be used
Expand Down
2 changes: 1 addition & 1 deletion controllers/topology/current_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (r *ClusterReconciler) getCurrentControlPlaneState(ctx context.Context, clu
}

// Otherwise, get the control plane machine infrastructureMachine template.
machineInfrastructureRef, err := contract.ControlPlane().InfrastructureMachineTemplate().Get(res.Object)
machineInfrastructureRef, err := contract.ControlPlane().MachineTemplate().InfrastructureRef().Get(res.Object)
if err != nil {
return res, errors.Wrapf(err, "failed to get InfrastructureMachineTemplate reference for %s, %s", res.Object.GetKind(), res.Object.GetName())
}
Expand Down
59 changes: 22 additions & 37 deletions controllers/topology/desired_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,29 +105,25 @@ func computeInfrastructureCluster(_ context.Context, s *scope.Scope) (*unstructu
// that should be referenced by the ControlPlane object.
func computeControlPlaneInfrastructureMachineTemplate(_ context.Context, s *scope.Scope) (*unstructured.Unstructured, error) {
template := s.Blueprint.ControlPlane.InfrastructureMachineTemplate
templateClonedFromref := s.Blueprint.ClusterClass.Spec.ControlPlane.MachineInfrastructure.Ref
templateClonedFromRef := s.Blueprint.ClusterClass.Spec.ControlPlane.MachineInfrastructure.Ref
cluster := s.Current.Cluster

// Check if the current control plane object has a machineTemplate.infrastructureRef already defined.
// TODO: Move the next few lines into a method on scope.ControlPlaneState
var currentRef *corev1.ObjectReference
if s.Current.ControlPlane != nil && s.Current.ControlPlane.Object != nil {
var err error
if currentRef, err = contract.ControlPlane().InfrastructureMachineTemplate().Get(s.Current.ControlPlane.Object); err != nil {
if currentRef, err = contract.ControlPlane().MachineTemplate().InfrastructureRef().Get(s.Current.ControlPlane.Object); err != nil {
return nil, errors.Wrap(err, "failed to get spec.machineTemplate.infrastructureRef for the current ControlPlane object")
}
}
topologyMetadata := s.Blueprint.Topology.ControlPlane.Metadata
clusterClassMetadata := s.Blueprint.ClusterClass.Spec.ControlPlane.Metadata

controlPlaneInfrastructureMachineTemplate := templateToTemplate(templateToInput{
template: template,
templateClonedFromRef: templateClonedFromref,
templateClonedFromRef: templateClonedFromRef,
cluster: cluster,
namePrefix: controlPlaneInfrastructureMachineTemplateNamePrefix(cluster.Name),
currentObjectRef: currentRef,
labels: mergeMap(topologyMetadata.Labels, clusterClassMetadata.Labels),
annotations: mergeMap(topologyMetadata.Annotations, clusterClassMetadata.Annotations),
})
return controlPlaneInfrastructureMachineTemplate, nil
}
Expand All @@ -139,28 +135,34 @@ func computeControlPlane(_ context.Context, s *scope.Scope, infrastructureMachin
templateClonedFromRef := s.Blueprint.ClusterClass.Spec.ControlPlane.Ref
cluster := s.Current.Cluster
currentRef := cluster.Spec.ControlPlaneRef
topologyMetadata := s.Blueprint.Topology.ControlPlane.Metadata
clusterClassMetadata := s.Blueprint.ClusterClass.Spec.ControlPlane.Metadata

controlPlane, err := templateToObject(templateToInput{
template: template,
templateClonedFromRef: templateClonedFromRef,
cluster: cluster,
namePrefix: fmt.Sprintf("%s-", cluster.Name),
currentObjectRef: currentRef,
labels: mergeMap(topologyMetadata.Labels, clusterClassMetadata.Labels),
annotations: mergeMap(topologyMetadata.Annotations, clusterClassMetadata.Annotations),
})
if err != nil {
return nil, errors.Wrapf(err, "failed to generate the ControlPlane object from the %s", template.GetKind())
}

// If the clusterClass mandates the controlPlane has infrastructureMachines, add a reference to InfrastructureMachine
// template to be used for the control plane machines.
// If the ClusterClass mandates the controlPlane has infrastructureMachines, add a reference to InfrastructureMachine
// template and metadata to be used for the control plane machines.
if s.Blueprint.HasControlPlaneInfrastructureMachine() {
if err := contract.ControlPlane().InfrastructureMachineTemplate().Set(controlPlane, infrastructureMachineTemplate); err != nil {
if err := contract.ControlPlane().MachineTemplate().InfrastructureRef().Set(controlPlane, infrastructureMachineTemplate); err != nil {
return nil, errors.Wrap(err, "failed to spec.machineTemplate.infrastructureRef in the ControlPlane object")
}

// Compute the labels and annotations to be applied to ControlPlane machines.
// We merge the labels and annotations from topology and ClusterClass.
topologyMetadata := s.Blueprint.Topology.ControlPlane.Metadata
clusterClassMetadata := s.Blueprint.ClusterClass.Spec.ControlPlane.Metadata
labels := mergeMap(topologyMetadata.Labels, clusterClassMetadata.Labels)
annotations := mergeMap(topologyMetadata.Annotations, clusterClassMetadata.Annotations)
if err := contract.ControlPlane().MachineTemplate().Metadata().Set(controlPlane, &clusterv1.ObjectMeta{Labels: labels, Annotations: annotations}); err != nil {
return nil, errors.Wrap(err, "failed to spec.machineTemplate.metadata in the ControlPlane object")
}
}

// If it is required to manage the number of replicas for the control plane, set the corresponding field.
Expand Down Expand Up @@ -230,8 +232,6 @@ func computeMachineDeployment(_ context.Context, s *scope.Scope, machineDeployme
cluster: s.Current.Cluster,
namePrefix: bootstrapTemplateNamePrefix(s.Current.Cluster.Name, machineDeploymentTopology.Name),
currentObjectRef: currentBootstrapTemplateRef,
labels: mergeMap(machineDeploymentTopology.Metadata.Labels, machineDeploymentBlueprint.Metadata.Labels),
annotations: mergeMap(machineDeploymentTopology.Metadata.Annotations, machineDeploymentBlueprint.Metadata.Annotations),
})

// Compute the Infrastructure template.
Expand All @@ -245,8 +245,6 @@ func computeMachineDeployment(_ context.Context, s *scope.Scope, machineDeployme
cluster: s.Current.Cluster,
namePrefix: infrastructureMachineTemplateNamePrefix(s.Current.Cluster.Name, machineDeploymentTopology.Name),
currentObjectRef: currentInfraMachineTemplateRef,
labels: mergeMap(machineDeploymentTopology.Metadata.Labels, machineDeploymentBlueprint.Metadata.Labels),
annotations: mergeMap(machineDeploymentTopology.Metadata.Annotations, machineDeploymentBlueprint.Metadata.Annotations),
})

// Compute the MachineDeployment object.
Expand All @@ -263,6 +261,10 @@ func computeMachineDeployment(_ context.Context, s *scope.Scope, machineDeployme
Spec: clusterv1.MachineDeploymentSpec{
ClusterName: s.Current.Cluster.Name,
Template: clusterv1.MachineTemplateSpec{
ObjectMeta: clusterv1.ObjectMeta{
Labels: mergeMap(machineDeploymentTopology.Metadata.Labels, machineDeploymentBlueprint.Metadata.Labels),
Annotations: mergeMap(machineDeploymentTopology.Metadata.Annotations, machineDeploymentBlueprint.Metadata.Annotations),
},
Spec: clusterv1.MachineSpec{
ClusterName: s.Current.Cluster.Name,
// Sets the desired Kubernetes version for the MachineDeployment.
Expand All @@ -285,16 +287,12 @@ func computeMachineDeployment(_ context.Context, s *scope.Scope, machineDeployme
// NOTE: On top of all the labels applied to managed objects we are applying the ClusterTopologyMachineDeploymentLabel
// keeping track of the MachineDeployment name from the Topology; this will be used to identify the object in next reconcile loops.
// NOTE: Topology label takes precedence on labels defined in the topology/in the ClusterClass.
labels := mergeMap(machineDeploymentTopology.Metadata.Labels, machineDeploymentBlueprint.Metadata.Labels)
labels := map[string]string{}
labels[clusterv1.ClusterLabelName] = s.Current.Cluster.Name
labels[clusterv1.ClusterTopologyOwnedLabel] = ""
labels[clusterv1.ClusterTopologyMachineDeploymentLabelName] = machineDeploymentTopology.Name
desiredMachineDeploymentObj.SetLabels(labels)

// Apply Labels
// NOTE: Topology label takes precedence on labels defined in the topology/in the ClusterClass.
desiredMachineDeploymentObj.Annotations = mergeMap(machineDeploymentTopology.Metadata.Annotations, machineDeploymentBlueprint.Metadata.Annotations)

// Set the desired replicas.
desiredMachineDeploymentObj.Spec.Replicas = machineDeploymentTopology.Replicas

Expand All @@ -308,21 +306,15 @@ type templateToInput struct {
cluster *clusterv1.Cluster
namePrefix string
currentObjectRef *corev1.ObjectReference
labels map[string]string
annotations map[string]string
}

// templateToObject generates an object from a template, taking care
// of adding required labels (cluster, topology), annotations (clonedFrom)
// and assigning a meaningful name (or reusing current reference name).
func templateToObject(in templateToInput) (*unstructured.Unstructured, error) {
// Enforce the topology labels into the provided label set.
// NOTE: The cluster label is added at creation time so this object could be read by the ClusterTopology
// controller immediately after creation, even before other controllers are going to add the label (if missing).
labels := in.labels
if labels == nil {
labels = map[string]string{}
}
labels := map[string]string{}
labels[clusterv1.ClusterLabelName] = in.cluster.Name
labels[clusterv1.ClusterTopologyOwnedLabel] = ""

Expand All @@ -334,7 +326,6 @@ func templateToObject(in templateToInput) (*unstructured.Unstructured, error) {
TemplateRef: in.templateClonedFromRef,
Namespace: in.cluster.Namespace,
Labels: labels,
Annotations: in.annotations,
ClusterName: in.cluster.Name,
})
if err != nil {
Expand Down Expand Up @@ -375,9 +366,6 @@ func templateToTemplate(in templateToInput) *unstructured.Unstructured {
if labels == nil {
labels = map[string]string{}
}
for key, value := range in.labels {
labels[key] = value
}
labels[clusterv1.ClusterLabelName] = in.cluster.Name
labels[clusterv1.ClusterTopologyOwnedLabel] = ""
template.SetLabels(labels)
Expand All @@ -387,9 +375,6 @@ func templateToTemplate(in templateToInput) *unstructured.Unstructured {
if annotations == nil {
annotations = map[string]string{}
}
for key, value := range in.annotations {
annotations[key] = value
}
annotations[clusterv1.TemplateClonedFromNameAnnotation] = in.templateClonedFromRef.Name
annotations[clusterv1.TemplateClonedFromGroupKindAnnotation] = in.templateClonedFromRef.GroupVersionKind().GroupKind().String()
template.SetAnnotations(annotations)
Expand Down
Loading

0 comments on commit d2f6425

Please sign in to comment.