Skip to content

Commit f1e81c1

Browse files
committed
fix AzureManagedCluster deployments when the resource group is not present
1 parent dcbe30d commit f1e81c1

11 files changed

+209
-105
lines changed

Tiltfile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ settings = {
1414
"kind_cluster_name": "capz",
1515
"capi_version": "v0.3.7",
1616
"cert_manager_version": "v0.11.0",
17+
"kubernetes_version": "v1.18.6",
18+
"aks_kubernetes_version": "v1.17.7"
1719
}
1820

1921
keys = ["AZURE_SUBSCRIPTION_ID_B64", "AZURE_TENANT_ID_B64", "AZURE_CLIENT_SECRET_B64", "AZURE_CLIENT_ID_B64", "AZURE_ENVIRONMENT"]
@@ -152,8 +154,7 @@ COPY manager .
152154
def capz():
153155
# Apply the kustomized yaml for this provider
154156
substitutions = settings.get("kustomize_substitutions", {})
155-
for substitution in substitutions:
156-
os.putenv(substitution, substitutions[substitution])
157+
os.environ.update(substitutions)
157158
yaml = str(kustomizesub("./config"))
158159

159160

@@ -266,13 +267,17 @@ def deploy_worker_templates(flavor, substitutions):
266267
"AZURE_VNET_NAME": flavor + "-template-vnet",
267268
"AZURE_RESOURCE_GROUP": flavor + "-template-rg",
268269
"CONTROL_PLANE_MACHINE_COUNT": "1",
269-
"KUBERNETES_VERSION": "v1.18.6",
270+
"KUBERNETES_VERSION": settings.get("kubernetes_version"),
270271
"AZURE_CONTROL_PLANE_MACHINE_TYPE": "Standard_D2s_v3",
271272
"WORKER_MACHINE_COUNT": "2",
272273
"AZURE_NODE_MACHINE_TYPE": "Standard_D2s_v3",
273274
"AZURE_JSON_B64": base64_encode(azure_json(flavor, substitutions)),
274275
}
275276

277+
if flavor == "aks":
278+
# AKS version support is usually a bit behind CAPI version, so use an older version
279+
substitutions["KUBERNETES_VERSION"] = settings.get("aks_kubernetes_version")
280+
276281
for substitution in substitutions:
277282
value = substitutions[substitution]
278283
yaml = yaml.replace("${" + substitution + "}", value)

cloud/scope/managedcontrolplane.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,18 @@ package scope
1818

1919
import (
2020
"context"
21+
2122
"github.com/Azure/go-autorest/autorest"
2223
"github.com/go-logr/logr"
2324
"github.com/pkg/errors"
2425
"k8s.io/apimachinery/pkg/runtime"
2526
"k8s.io/klog/klogr"
26-
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha3"
2727
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
2828
expv1 "sigs.k8s.io/cluster-api/exp/api/v1alpha3"
2929

30+
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3"
31+
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha3"
32+
3033
"sigs.k8s.io/cluster-api/util/patch"
3134
"sigs.k8s.io/controller-runtime/pkg/client"
3235
)
@@ -94,6 +97,33 @@ type ManagedControlPlaneScope struct {
9497
PatchTarget runtime.Object
9598
}
9699

100+
func (s *ManagedControlPlaneScope) ResourceGroup() string {
101+
if s.ControlPlane == nil {
102+
return ""
103+
}
104+
return s.ControlPlane.Spec.ResourceGroup
105+
}
106+
107+
func (s *ManagedControlPlaneScope) ClusterName() string {
108+
return s.Cluster.Name
109+
}
110+
111+
func (s *ManagedControlPlaneScope) Location() string {
112+
if s.ControlPlane == nil {
113+
return ""
114+
}
115+
return s.ControlPlane.Spec.Location
116+
}
117+
118+
// AdditionalTags returns AdditionalTags from the ControlPlane spec.
119+
func (s *ManagedControlPlaneScope) AdditionalTags() infrav1.Tags {
120+
tags := make(infrav1.Tags)
121+
if s.ControlPlane.Spec.AdditionalTags != nil {
122+
tags = s.ControlPlane.Spec.AdditionalTags.DeepCopy()
123+
}
124+
return tags
125+
}
126+
97127
// SubscriptionID returns the Azure client Subscription ID.
98128
func (s *ManagedControlPlaneScope) SubscriptionID() string {
99129
return s.AzureClients.SubscriptionID

cloud/services/groups/mock_groups/groups_mock.go

Lines changed: 0 additions & 70 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloud/services/groups/service.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package groups
1818

1919
import (
2020
"github.com/go-logr/logr"
21+
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3"
2122
azure "sigs.k8s.io/cluster-api-provider-azure/cloud"
2223
)
2324

@@ -30,7 +31,11 @@ type Service struct {
3031
// GroupScope defines the scope interface for a group service.
3132
type GroupScope interface {
3233
logr.Logger
33-
azure.ClusterDescriber
34+
azure.Authorizer
35+
ResourceGroup() string
36+
ClusterName() string
37+
Location() string
38+
AdditionalTags() infrav1.Tags
3439
}
3540

3641
// NewService creates a new service.

config/crd/bases/exp.infrastructure.cluster.x-k8s.io_azuremanagedcontrolplanes.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ spec:
9898
type: string
9999
sshPublicKey:
100100
description: SSHPublicKey is a string literal containing an ssh public
101-
key.
101+
key base64 encoded.
102102
type: string
103103
subscriptionID:
104104
description: SubscriotionID is the GUID of the Azure subscription

exp/api/v1alpha3/azuremanagedcontrolplane_types.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
corev1 "k8s.io/api/core/v1"
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
23+
24+
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3"
2325
)
2426

2527
// AzureManagedControlPlaneSpec defines the desired state of AzureManagedControlPlane
@@ -44,7 +46,7 @@ type AzureManagedControlPlaneSpec struct {
4446
// AdditionalTags is an optional set of tags to add to Azure resources managed by the Azure provider, in addition to the
4547
// ones added by default.
4648
// +optional
47-
AdditionalTags map[string]string `json:"additionalTags,omitempty"`
49+
AdditionalTags infrav1.Tags `json:"additionalTags,omitempty"`
4850

4951
// NetworkPlugin used for building Kubernetes network. Possible values include: 'Azure', 'Kubenet'. Defaults to Azure.
5052
// +kubebuilder:validation:Enum=Azure;Kubenet
@@ -54,7 +56,7 @@ type AzureManagedControlPlaneSpec struct {
5456
// +kubebuilder:validation:Enum=Calico;Azure
5557
NetworkPolicy *string `json:"networkPolicy,omitempty"`
5658

57-
// SSHPublicKey is a string literal containing an ssh public key.
59+
// SSHPublicKey is a string literal containing an ssh public key base64 encoded.
5860
SSHPublicKey string `json:"sshPublicKey"`
5961

6062
// DefaultPoolRef is the specification for the default pool, without which an AKS cluster cannot be created.

exp/api/v1alpha3/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/controllers/azuremanagedmachinepool_controller.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ func (r *AzureManagedMachinePoolReconciler) Reconcile(req ctrl.Request) (_ ctrl.
168168
return reconcile.Result{}, errors.Errorf("failed to create scope: %+v", err)
169169
}
170170

171+
// Always patch when exiting so we can persist changes to finalizers and status
172+
defer func() {
173+
if err := mcpScope.PatchObject(ctx); err != nil && reterr == nil {
174+
reterr = err
175+
}
176+
}()
177+
171178
// Handle deleted clusters
172179
if !infraPool.DeletionTimestamp.IsZero() {
173180
return r.reconcileDelete(ctx, mcpScope)
@@ -188,6 +195,12 @@ func (r *AzureManagedMachinePoolReconciler) reconcileNormal(ctx context.Context,
188195
}
189196

190197
if err := newAzureManagedMachinePoolReconciler(scope).Reconcile(ctx, scope); err != nil {
198+
if IsAgentPoolVMSSNotFoundError(err) {
199+
// if the underlying VMSS is not yet created, requeue for 30s in the future
200+
return reconcile.Result{
201+
RequeueAfter: 30 * time.Second,
202+
}, nil
203+
}
191204
return reconcile.Result{}, errors.Wrapf(err, "error creating AzureManagedMachinePool %s/%s", scope.InfraMachinePool.Namespace, scope.InfraMachinePool.Name)
192205
}
193206

exp/controllers/azuremanagedmachinepool_reconciler.go

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,47 @@ import (
3030
"sigs.k8s.io/controller-runtime/pkg/client"
3131
)
3232

33-
// azureManagedMachinePoolReconciler are list of services required by cluster controller
34-
type azureManagedMachinePoolReconciler struct {
35-
kubeclient client.Client
36-
agentPoolsSvc azure.OldService
37-
scaleSetsSvc NodeLister
33+
type (
34+
// azureManagedMachinePoolReconciler are list of services required by cluster controller
35+
azureManagedMachinePoolReconciler struct {
36+
kubeclient client.Client
37+
agentPoolsSvc azure.OldService
38+
scaleSetsSvc NodeLister
39+
}
40+
41+
// AgentPoolVMSSNotFoundError represents a reconcile error when the VMSS for an agent pool can't be found
42+
AgentPoolVMSSNotFoundError struct {
43+
NodeResourceGroup string
44+
PoolName string
45+
}
46+
47+
// NodeLister is a service interface for returning generic lists.
48+
NodeLister interface {
49+
ListInstances(context.Context, string, string) ([]compute.VirtualMachineScaleSetVM, error)
50+
List(context.Context, string) ([]compute.VirtualMachineScaleSet, error)
51+
}
52+
)
53+
54+
var (
55+
notFoundErr = new(AgentPoolVMSSNotFoundError)
56+
)
57+
58+
// NewAgentPoolVMSSNotFoundError creates a new AgentPoolVMSSNotFoundError
59+
func NewAgentPoolVMSSNotFoundError(nodeResourceGroup, poolName string) *AgentPoolVMSSNotFoundError {
60+
return &AgentPoolVMSSNotFoundError{
61+
NodeResourceGroup: nodeResourceGroup,
62+
PoolName: poolName,
63+
}
3864
}
3965

40-
// NodeLister is a service interface for returning generic lists.
41-
type NodeLister interface {
42-
ListInstances(context.Context, string, string) ([]compute.VirtualMachineScaleSetVM, error)
43-
List(context.Context, string) ([]compute.VirtualMachineScaleSet, error)
66+
func (a *AgentPoolVMSSNotFoundError) Error() string {
67+
msgFmt := "failed to find vm scale set in resource group %s matching pool named %s"
68+
return fmt.Sprintf(msgFmt, a.NodeResourceGroup, a.PoolName)
69+
}
70+
71+
func (a *AgentPoolVMSSNotFoundError) Is(target error) bool {
72+
_, ok := target.(*AgentPoolVMSSNotFoundError)
73+
return ok
4474
}
4575

4676
// newAzureManagedMachinePoolReconciler populates all the services based on input scope
@@ -62,23 +92,24 @@ func (r *azureManagedMachinePoolReconciler) Reconcile(ctx context.Context, scope
6292
normalizedVersion = &v
6393
}
6494

95+
replicas := int32(1)
96+
if scope.MachinePool.Spec.Replicas != nil {
97+
replicas = *scope.MachinePool.Spec.Replicas
98+
}
99+
65100
agentPoolSpec := &agentpools.Spec{
66101
Name: scope.InfraMachinePool.Name,
67102
ResourceGroup: scope.ControlPlane.Spec.ResourceGroup,
68103
Cluster: scope.ControlPlane.Name,
69104
SKU: scope.InfraMachinePool.Spec.SKU,
70-
Replicas: 1,
105+
Replicas: replicas,
71106
Version: normalizedVersion,
72107
}
73108

74109
if scope.InfraMachinePool.Spec.OSDiskSizeGB != nil {
75110
agentPoolSpec.OSDiskSizeGB = *scope.InfraMachinePool.Spec.OSDiskSizeGB
76111
}
77112

78-
if scope.MachinePool.Spec.Replicas != nil {
79-
agentPoolSpec.Replicas = *scope.MachinePool.Spec.Replicas
80-
}
81-
82113
if err := r.agentPoolsSvc.Reconcile(ctx, agentPoolSpec); err != nil {
83114
return errors.Wrapf(err, "failed to reconcile machine pool %s", scope.InfraMachinePool.Name)
84115
}
@@ -99,7 +130,7 @@ func (r *azureManagedMachinePoolReconciler) Reconcile(ctx context.Context, scope
99130
}
100131

101132
if match == nil {
102-
return errors.New("failed to find vm scale set matching pool")
133+
return NewAgentPoolVMSSNotFoundError(nodeResourceGroup, scope.InfraMachinePool.Name)
103134
}
104135

105136
instances, err := r.scaleSetsSvc.ListInstances(ctx, nodeResourceGroup, *match.Name)
@@ -108,9 +139,8 @@ func (r *azureManagedMachinePoolReconciler) Reconcile(ctx context.Context, scope
108139
}
109140

110141
var providerIDs = make([]string, len(instances))
111-
for _, vm := range instances {
112-
vm := vm
113-
providerIDs = append(providerIDs, fmt.Sprintf("azure://%s", *vm.ID))
142+
for i := 0; i < len(instances); i++ {
143+
providerIDs[i] = fmt.Sprintf("azure://%s", *instances[i].ID)
114144
}
115145

116146
scope.InfraMachinePool.Spec.ProviderIDList = providerIDs
@@ -136,3 +166,8 @@ func (r *azureManagedMachinePoolReconciler) Delete(ctx context.Context, scope *s
136166

137167
return nil
138168
}
169+
170+
// IsAgentPoolVMSSNotFoundError returns true if the error is a AgentPoolVMSSNotFoundError
171+
func IsAgentPoolVMSSNotFoundError(err error) bool {
172+
return errors.Is(err, notFoundErr)
173+
}

0 commit comments

Comments
 (0)