Skip to content

Commit d219919

Browse files
author
jwcesign
authored
Merge pull request #52 from helen-frank/helen-frank/dev-general
chore: fix vswitch status
2 parents 63beb54 + 3533565 commit d219919

File tree

11 files changed

+173
-18
lines changed

11 files changed

+173
-18
lines changed

cmd/controller/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ func main() {
5959
op.InstanceProvider,
6060
op.InstanceTypeProvider,
6161
op.PricingProvider,
62+
op.VSwitchProvider,
63+
op.SecurityGroupProvider,
64+
op.LaunchTemplateProvider,
6265
)...).
6366
Start(ctx, cloudProvider)
6467
}

config/components/crds/karpenter.k8s.alicloud_ecsnodeclasses.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ spec:
257257
additionalProperties:
258258
type: string
259259
description: |-
260-
Tags is a map of key/value tags used to select subnets
260+
Tags is a map of key/value tags used to select vSwitches
261261
Specifying '*' for a value selects all values for a given tag key.
262262
maxProperties: 20
263263
type: object

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ require (
113113
k8s.io/cloud-provider v0.30.3 // indirect
114114
k8s.io/component-base v0.30.3 // indirect
115115
k8s.io/csi-translation-lib v0.30.3 // indirect
116-
k8s.io/klog v1.0.0 // indirect
116+
k8s.io/klog v1.0.0
117117
k8s.io/klog/v2 v2.130.1
118118
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
119119
knative.dev/pkg v0.0.0-20231010144348-ca8c009405dd

pkg/apis/v1alpha1/ecsnodeclass.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ type VSwitchSelectorTerm struct {
8888
// SecurityGroupSelectorTerm defines selection logic for a security group used by Karpenter to launch nodes.
8989
// If multiple fields are used for selection, the requirements are ANDed.
9090
type SecurityGroupSelectorTerm struct {
91-
// Tags is a map of key/value tags used to select subnets
91+
// Tags is a map of key/value tags used to select vSwitches
9292
// Specifying '*' for a value selects all values for a given tag key.
9393
// +kubebuilder:validation:XValidation:message="empty tag keys aren't supported",rule="self.all(k, k != '')"
9494
// +kubebuilder:validation:MaxProperties:=20

pkg/apis/v1alpha1/ecsnodeclass_status.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
)
2323

2424
const (
25-
ConditionTypeVSwitchsReady = "VSwitchsReady"
25+
ConditionTypeVSwitchesReady = "VSwitchesReady"
2626
ConditionTypeSecurityGroupsReady = "SecurityGroupsReady"
2727
ConditionTypeInstanceRAMReady = "InstanceRAMReady"
2828
)
@@ -81,7 +81,7 @@ type ECSNodeClassStatus struct {
8181

8282
func (in *ECSNodeClass) StatusConditions() status.ConditionSet {
8383
return status.NewReadyConditions(
84-
ConditionTypeVSwitchsReady,
84+
ConditionTypeVSwitchesReady,
8585
ConditionTypeSecurityGroupsReady,
8686
ConditionTypeInstanceRAMReady,
8787
).For(in)

pkg/cloudprovider/drift.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ func (c *CloudProvider) isNodeClassDrifted(ctx context.Context, nodeClaim *karpv
4949
if err != nil {
5050
return "", fmt.Errorf("calculating securitygroup drift, %w", err)
5151
}
52-
subnetDrifted, err := c.isVSwitchDrifted(instance, nodeClass)
52+
vSwitchDrifted, err := c.isVSwitchDrifted(instance, nodeClass)
5353
if err != nil {
54-
return "", fmt.Errorf("calculating subnet drift, %w", err)
54+
return "", fmt.Errorf("calculating vSwitch drift, %w", err)
5555
}
56-
drifted := lo.FindOrElse([]cloudprovider.DriftReason{securitygroupDrifted, subnetDrifted}, "", func(i cloudprovider.DriftReason) bool {
56+
drifted := lo.FindOrElse([]cloudprovider.DriftReason{securitygroupDrifted, vSwitchDrifted}, "", func(i cloudprovider.DriftReason) bool {
5757
return string(i) != ""
5858
})
5959
return drifted, nil

pkg/controllers/controllers.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,29 @@ import (
3030
nodeclaimtagging "github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/controllers/nodeclaim/tagging"
3131
nodeclasshash "github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/controllers/nodeclass/hash"
3232
nodeclaasstatus "github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/controllers/nodeclass/status"
33+
nodeclasstermination "github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/controllers/nodeclass/termination"
3334
providersinstancetype "github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/controllers/providers/instancetype"
3435
controllerspricing "github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/controllers/providers/pricing"
3536
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/instance"
3637
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/instancetype"
38+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/launchtemplate"
3739
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/pricing"
40+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/securitygroup"
41+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/vswitch"
3842
)
3943

4044
func NewControllers(ctx context.Context, mgr manager.Manager, clk clock.Clock,
4145
kubeClient client.Client, recorder events.Recorder,
42-
cloudProvider cloudprovider.CloudProvider, instanceProvider instance.Provider,
43-
instanceTypeProvider instancetype.Provider,
44-
pricingProvider pricing.Provider) []controller.Controller {
46+
cloudProvider cloudprovider.CloudProvider,
47+
instanceProvider instance.Provider, instanceTypeProvider instancetype.Provider,
48+
pricingProvider pricing.Provider,
49+
vSwitchProvider vswitch.Provider, securitygroupProvider securitygroup.Provider,
50+
launchTemplateProvider launchtemplate.Provider) []controller.Controller {
4551

4652
controllers := []controller.Controller{
4753
nodeclasshash.NewController(kubeClient),
48-
nodeclaasstatus.NewController(kubeClient),
54+
nodeclaasstatus.NewController(kubeClient, vSwitchProvider, securitygroupProvider),
55+
nodeclasstermination.NewController(kubeClient, recorder, launchTemplateProvider),
4956
controllerspricing.NewController(pricingProvider),
5057
nodeclaimgarbagecollection.NewController(kubeClient, cloudProvider),
5158
nodeclaimtagging.NewController(kubeClient, instanceProvider),

pkg/controllers/nodeclass/status/controller.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121

2222
"github.com/awslabs/operatorpkg/reasonable"
23+
"go.uber.org/multierr"
2324
"k8s.io/apimachinery/pkg/api/equality"
2425
"k8s.io/apimachinery/pkg/api/errors"
2526
controllerruntime "sigs.k8s.io/controller-runtime"
@@ -29,17 +30,30 @@ import (
2930
"sigs.k8s.io/controller-runtime/pkg/manager"
3031
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3132
"sigs.k8s.io/karpenter/pkg/operator/injection"
33+
"sigs.k8s.io/karpenter/pkg/utils/result"
3234

3335
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/apis/v1alpha1"
36+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/securitygroup"
37+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/vswitch"
3438
)
3539

40+
type nodeClassStatusReconciler interface {
41+
Reconcile(context.Context, *v1alpha1.ECSNodeClass) (reconcile.Result, error)
42+
}
43+
3644
type Controller struct {
3745
kubeClient client.Client
46+
47+
vSwitch *VSwitch
48+
securitygroup *SecurityGroup
3849
}
3950

40-
func NewController(kubeClient client.Client) *Controller {
51+
func NewController(kubeClient client.Client, vSwitchProvider vswitch.Provider, securitygroupProvider securitygroup.Provider) *Controller {
4152
return &Controller{
4253
kubeClient: kubeClient,
54+
55+
vSwitch: &VSwitch{vSwitchProvider: vSwitchProvider},
56+
securitygroup: &SecurityGroup{securityGroupProvider: securitygroupProvider},
4357
}
4458
}
4559

@@ -64,8 +78,17 @@ func (c *Controller) Reconcile(ctx context.Context, nodeClass *v1alpha1.ECSNodeC
6478

6579
// TODO: implement different conditions setup
6680
nodeClass.StatusConditions().SetTrue(v1alpha1.ConditionTypeInstanceRAMReady)
67-
nodeClass.StatusConditions().SetTrue(v1alpha1.ConditionTypeSecurityGroupsReady)
68-
nodeClass.StatusConditions().SetTrue(v1alpha1.ConditionTypeVSwitchsReady)
81+
82+
var results []reconcile.Result
83+
var errs error
84+
for _, reconciler := range []nodeClassStatusReconciler{
85+
c.vSwitch,
86+
c.securitygroup,
87+
} {
88+
res, err := reconciler.Reconcile(ctx, nodeClass)
89+
errs = multierr.Append(errs, err)
90+
results = append(results, res)
91+
}
6992

7093
if !equality.Semantic.DeepEqual(stored, nodeClass) {
7194
// We use client.MergeFromWithOptimisticLock because patching a list with a JSON merge patch
@@ -75,11 +98,14 @@ func (c *Controller) Reconcile(ctx context.Context, nodeClass *v1alpha1.ECSNodeC
7598
if errors.IsConflict(err) {
7699
return reconcile.Result{Requeue: true}, nil
77100
}
78-
return reconcile.Result{}, client.IgnoreNotFound(err)
101+
errs = multierr.Append(errs, client.IgnoreNotFound(err))
79102
}
80103
}
81104

82-
return reconcile.Result{}, nil
105+
if errs != nil {
106+
return reconcile.Result{}, errs
107+
}
108+
return result.Min(results...), nil
83109
}
84110

85111
func (c *Controller) Register(_ context.Context, m manager.Manager) error {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
Copyright 2024 The CloudPilot AI Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package status
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"sort"
23+
"time"
24+
25+
ecsclient "github.com/alibabacloud-go/ecs-20140526/v4/client"
26+
"github.com/samber/lo"
27+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
28+
29+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/apis/v1alpha1"
30+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/securitygroup"
31+
)
32+
33+
type SecurityGroup struct {
34+
securityGroupProvider securitygroup.Provider
35+
}
36+
37+
func (sg *SecurityGroup) Reconcile(ctx context.Context, nodeClass *v1alpha1.ECSNodeClass) (reconcile.Result, error) {
38+
securityGroups, err := sg.securityGroupProvider.List(ctx, nodeClass)
39+
if err != nil {
40+
return reconcile.Result{}, fmt.Errorf("getting security groups, %w", err)
41+
}
42+
if len(securityGroups) == 0 && len(nodeClass.Spec.SecurityGroupSelectorTerms) > 0 {
43+
nodeClass.Status.SecurityGroups = nil
44+
nodeClass.StatusConditions().SetFalse(v1alpha1.ConditionTypeSecurityGroupsReady, "SecurityGroupsNotFound", "SecurityGroupSelector did not match any SecurityGroups")
45+
return reconcile.Result{}, nil
46+
}
47+
sort.Slice(securityGroups, func(i, j int) bool {
48+
return *securityGroups[i].SecurityGroupId < *securityGroups[j].SecurityGroupId
49+
})
50+
nodeClass.Status.SecurityGroups = lo.Map(securityGroups, func(securityGroup *ecsclient.DescribeSecurityGroupsResponseBodySecurityGroupsSecurityGroup, _ int) v1alpha1.SecurityGroup {
51+
return v1alpha1.SecurityGroup{
52+
ID: *securityGroup.SecurityGroupId,
53+
Name: *securityGroup.SecurityGroupName,
54+
}
55+
})
56+
nodeClass.StatusConditions().SetTrue(v1alpha1.ConditionTypeSecurityGroupsReady)
57+
return reconcile.Result{RequeueAfter: 5 * time.Minute}, nil
58+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
Copyright 2024 The CloudPilot AI Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package status
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"sort"
23+
"time"
24+
25+
vpc "github.com/alibabacloud-go/vpc-20160428/v6/client"
26+
"github.com/samber/lo"
27+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
28+
29+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/apis/v1alpha1"
30+
"github.com/cloudpilot-ai/karpenter-provider-alicloud/pkg/providers/vswitch"
31+
)
32+
33+
type VSwitch struct {
34+
vSwitchProvider vswitch.Provider
35+
}
36+
37+
func (v *VSwitch) Reconcile(ctx context.Context, nodeClass *v1alpha1.ECSNodeClass) (reconcile.Result, error) {
38+
vSwitches, err := v.vSwitchProvider.List(ctx, nodeClass)
39+
if err != nil {
40+
return reconcile.Result{}, fmt.Errorf("getting vSwitches, %w", err)
41+
}
42+
if len(vSwitches) == 0 {
43+
nodeClass.Status.VSwitches = nil
44+
nodeClass.StatusConditions().SetFalse(v1alpha1.ConditionTypeVSwitchesReady, "vSwitchesNotFound", "VSwitchSelector did not match any VSwitches")
45+
return reconcile.Result{}, nil
46+
}
47+
sort.Slice(vSwitches, func(i, j int) bool {
48+
if int(*vSwitches[i].AvailableIpAddressCount) != int(*vSwitches[j].AvailableIpAddressCount) {
49+
return int(*vSwitches[i].AvailableIpAddressCount) > int(*vSwitches[j].AvailableIpAddressCount)
50+
}
51+
return *vSwitches[i].VSwitchId < *vSwitches[j].VSwitchId
52+
})
53+
nodeClass.Status.VSwitches = lo.Map(vSwitches, func(ecsvSwitch *vpc.DescribeVSwitchesResponseBodyVSwitchesVSwitch, _ int) v1alpha1.VSwitch {
54+
return v1alpha1.VSwitch{
55+
ID: *ecsvSwitch.VSwitchId,
56+
ZoneID: *ecsvSwitch.ZoneId,
57+
}
58+
})
59+
nodeClass.StatusConditions().SetTrue(v1alpha1.ConditionTypeVSwitchesReady)
60+
return reconcile.Result{RequeueAfter: time.Minute}, nil
61+
}

0 commit comments

Comments
 (0)