Skip to content

Commit 35c50dc

Browse files
justinsbchrischdi
andcommitted
MachinePool: populate providerIDList
In order for nodes to be associated to the MachinePool, we need to populate the spec.providerIDList field. This field is known to the MachinePool controller. Co-authored-by: Christian Schlotter <christi.schlotter@gmail.com>
1 parent 9cf7d93 commit 35c50dc

File tree

7 files changed

+93
-18
lines changed

7 files changed

+93
-18
lines changed

cloud/services/compute/instancegroupmanagers/instancegroupmanagers_reconcile.go

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,27 @@ package instancegroupmanagers
1919
import (
2020
"context"
2121
"fmt"
22+
"strings"
2223

24+
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/filter"
2325
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
2426
"google.golang.org/api/compute/v1"
2527
"sigs.k8s.io/cluster-api-provider-gcp/cloud/gcperrors"
2628
"sigs.k8s.io/cluster-api-provider-gcp/pkg/gcp"
2729
"sigs.k8s.io/controller-runtime/pkg/log"
2830
)
2931

30-
// Reconcile reconcile machine instance.
31-
func (s *Service) Reconcile(ctx context.Context, instanceTemplateKey *meta.Key) error {
32+
// Reconcile reconciles GCP instanceGroupManager resources.
33+
func (s *Service) Reconcile(ctx context.Context, instanceTemplateKey *meta.Key) (*compute.InstanceGroupManager, error) {
3234
log := log.FromContext(ctx)
3335
log.Info("Reconciling instanceGroupManager resources")
3436
igm, err := s.createOrGet(ctx, instanceTemplateKey)
3537
if err != nil {
36-
return err
38+
return nil, err
3739
}
3840
log.V(2).Info("Reconciled instanceGroupManager", "selfLink", igm.SelfLink)
3941

40-
return nil
42+
return igm, nil
4143
}
4244

4345
// Delete deletes the GCP instanceGroupManager resource.
@@ -150,3 +152,33 @@ func (s *Service) createOrGet(ctx context.Context, instanceTemplateKey *meta.Key
150152

151153
return actual, nil
152154
}
155+
156+
// ListInstances lists instances in the the instanceGroup linked to the passed instanceGroupManager.
157+
func (s *Service) ListInstances(ctx context.Context, instanceGroupManager *compute.InstanceGroupManager) ([]*compute.InstanceWithNamedPorts, error) {
158+
log := log.FromContext(ctx)
159+
160+
var igKey *meta.Key
161+
{
162+
instanceGroup := instanceGroupManager.InstanceGroup
163+
instanceGroup = strings.TrimPrefix(instanceGroup, "https://www.googleapis.com/")
164+
instanceGroup = strings.TrimPrefix(instanceGroup, "compute/v1/")
165+
tokens := strings.Split(instanceGroup, "/")
166+
if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "zones" && tokens[4] == "instanceGroups" {
167+
igKey = meta.ZonalKey(tokens[5], tokens[3])
168+
} else {
169+
return nil, fmt.Errorf("unexpected format for instanceGroup: %q", instanceGroup)
170+
}
171+
}
172+
173+
log.Info("Listing instances in instanceGroup", "instanceGroup", instanceGroupManager.InstanceGroup)
174+
listInstancesRequest := &compute.InstanceGroupsListInstancesRequest{
175+
InstanceState: "ALL",
176+
}
177+
instances, err := s.instanceGroups.ListInstances(ctx, igKey, listInstancesRequest, filter.None)
178+
if err != nil {
179+
log.Error(err, "Error listing instances in instanceGroup", "instanceGroup", instanceGroupManager.InstanceGroup)
180+
return nil, fmt.Errorf("listing instances in instanceGroup %q: %w", instanceGroupManager.InstanceGroup, err)
181+
}
182+
183+
return instances, nil
184+
}

cloud/services/compute/instancegroupmanagers/service.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type Scope interface {
5050
type Service struct {
5151
scope Scope
5252
instanceGroupManagers instanceGroupManagersClient
53+
instanceGroups k8scloud.InstanceGroups
5354
}
5455

5556
// var _ cloud.Reconciler = &Service{}
@@ -61,5 +62,6 @@ func New(scope Scope) *Service {
6162
return &Service{
6263
scope: scope,
6364
instanceGroupManagers: cloudScope.InstanceGroupManagers(),
65+
instanceGroups: cloudScope.InstanceGroups(),
6466
}
6567
}

config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachinepools.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,13 @@ spec:
256256
preemptible:
257257
description: Preemptible defines if instance is preemptible
258258
type: boolean
259+
providerIDList:
260+
description: |-
261+
ProviderIDList are the identification IDs of machine instances provided by the provider.
262+
This field must match the provider IDs as seen on the node objects corresponding to a machine pool's machine instances.
263+
items:
264+
type: string
265+
type: array
259266
provisioningModel:
260267
description: |-
261268
ProvisioningModel defines if instance is spot.

exp/api/v1beta1/gcpmachinepool_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ const (
3232

3333
// GCPMachinePoolSpec defines the desired state of GCPMachinePool.
3434
type GCPMachinePoolSpec struct {
35+
// ProviderIDList are the identification IDs of machine instances provided by the provider.
36+
// This field must match the provider IDs as seen on the node objects corresponding to a machine pool's machine instances.
37+
// +optional
38+
ProviderIDList []string `json:"providerIDList,omitempty"`
39+
3540
// InstanceType is the type of instance to create. Example: n1.standard-2
3641
InstanceType string `json:"instanceType"`
3742

exp/api/v1beta1/gcpmachinepool_webhook.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package v1beta1
1919
import (
2020
"context"
2121
"fmt"
22-
"reflect"
2322

2423
apierrors "k8s.io/apimachinery/pkg/api/errors"
2524
"k8s.io/apimachinery/pkg/runtime"
@@ -60,23 +59,14 @@ func (*gcpMachinePoolWebhook) ValidateCreate(_ context.Context, obj runtime.Obje
6059
}
6160

6261
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
63-
func (*gcpMachinePoolWebhook) ValidateUpdate(_ context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
64-
old, ok := oldObj.(*GCPMachinePool)
65-
if !ok {
66-
return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a GCPMachinePool but got a %T", oldObj))
67-
}
68-
62+
func (*gcpMachinePoolWebhook) ValidateUpdate(_ context.Context, _, newObj runtime.Object) (admission.Warnings, error) {
6963
r, ok := newObj.(*GCPMachinePool)
7064
if !ok {
71-
return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a GCPMachinePool but got a %T", newObj))
65+
return nil, fmt.Errorf("expected a GCPMachinePool object but got %T", r)
7266
}
7367

7468
gcpMachinePoolLog.Info("Validating GCPMachinePool update", "name", r.Name)
7569

76-
if !reflect.DeepEqual(r.Spec, old.Spec) {
77-
return nil, apierrors.NewBadRequest("GCPMachinePool.Spec is immutable")
78-
}
79-
8070
return nil, nil
8171
}
8272

exp/api/v1beta1/zz_generated.deepcopy.go

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

exp/controllers/gcpmachinepool_controller.go

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ package controllers
2020
import (
2121
"context"
2222
"fmt"
23+
"strings"
24+
"time"
2325

2426
"github.com/google/go-cmp/cmp"
2527
corev1 "k8s.io/api/core/v1"
@@ -223,7 +225,8 @@ func (r *GCPMachinePoolReconciler) reconcile(ctx context.Context, machinePoolSco
223225
Status: metav1.ConditionTrue,
224226
})
225227

226-
if err := instancegroupmanagers.New(machinePoolScope).Reconcile(ctx, instanceTemplateKey); err != nil {
228+
igm, err := instancegroupmanagers.New(machinePoolScope).Reconcile(ctx, instanceTemplateKey)
229+
if err != nil {
227230
log.Error(err, "Error reconciling instanceGroupManager")
228231
// record.Warnf(machineScope.GCPMachine, "GCPMachineReconcile", "Reconcile error - %v", err)
229232
conditions.Set(machinePoolScope.GCPMachinePool, metav1.Condition{
@@ -241,7 +244,38 @@ func (r *GCPMachinePoolReconciler) reconcile(ctx context.Context, machinePoolSco
241244
Status: metav1.ConditionTrue,
242245
})
243246

244-
return ctrl.Result{}, nil
247+
igmInstances, err := instancegroupmanagers.New(machinePoolScope).ListInstances(ctx, igm)
248+
if err != nil {
249+
log.Error(err, "Error listing instances in instanceGroupManager")
250+
return ctrl.Result{}, err
251+
}
252+
253+
providerIDList := make([]string, len(igmInstances))
254+
255+
for i, instance := range igmInstances {
256+
var providerID string
257+
258+
// Convert instance URL to providerID format
259+
u := instance.Instance
260+
u = strings.TrimPrefix(u, "https://www.googleapis.com/compute/v1/")
261+
tokens := strings.Split(u, "/")
262+
if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "zones" && tokens[4] == "instances" {
263+
providerID = fmt.Sprintf("gce://%s/%s/%s", tokens[1], tokens[3], tokens[5])
264+
} else {
265+
return ctrl.Result{}, fmt.Errorf("unexpected instance URL format: %s", instance.Instance)
266+
}
267+
268+
providerIDList[i] = providerID
269+
}
270+
271+
machinePoolScope.GCPMachinePool.Spec.ProviderIDList = providerIDList
272+
machinePoolScope.GCPMachinePool.Status.Replicas = int32(len(providerIDList))
273+
machinePoolScope.GCPMachinePool.Status.Ready = true
274+
275+
// Requeue so that we can keep the spec.providerIDList and status in sync with the MIG.
276+
// This is important for scaling up and down, as the CAPI MachinePool controller relies on
277+
// the providerIDList to determine which machines belong to the MachinePool.
278+
return ctrl.Result{RequeueAfter: 1 * time.Minute}, nil
245279
}
246280

247281
func (r *GCPMachinePoolReconciler) reconcileDelete(ctx context.Context, machinePoolScope *scope.MachinePoolScope) error {

0 commit comments

Comments
 (0)