Skip to content

Commit 2bbbb6f

Browse files
Support overlay upgrades + wait for OEC to reach terminal state (#1682)
* reconcile CNI inline while building appgw config * remove err const * fix issue in bubbling up error * reconcile once * don't update if subnet matches * subnet change should cause re-creation * remove unused * move to func
1 parent 059f2f9 commit 2bbbb6f

File tree

10 files changed

+401
-142
lines changed

10 files changed

+401
-142
lines changed

cmd/appgw-ingress/main.go

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package main
77

88
import (
9-
"context"
109
"flag"
1110
"fmt"
1211
"os"
@@ -140,16 +139,6 @@ func main() {
140139
AppGwName: env.AppGwName,
141140
}
142141

143-
// create a new agic controller
144-
appGwIngressController := controller.NewAppGwIngressController(azClient, appGwIdentifier, k8sContext, recorder, metricStore, agicPod, env.HostedOnUnderlay)
145-
146-
// initialize the http server and start it
147-
httpServer := httpserver.NewHTTPServer(
148-
appGwIngressController,
149-
metricStore,
150-
env.HTTPServicePort)
151-
httpServer.Start()
152-
153142
klog.V(3).Infof("Application Gateway Details: Subscription=\"%s\" Resource Group=\"%s\" Name=\"%s\"", env.SubscriptionID, env.ResourceGroupName, env.AppGwName)
154143

155144
var authorizer autorest.Authorizer
@@ -215,12 +204,17 @@ func main() {
215204
klog.Fatal(errorLine)
216205
}
217206

218-
if err := cni.ReconcileCNI(context.Background(), azClient, ctrlClient, env.AGICPodNamespace, cpConfig, appGw, env.AddonMode); err != nil {
219-
if agicPod != nil {
220-
recorder.Event(agicPod, v1.EventTypeWarning, events.ReasonFailedCNIConfiguration, err.Error())
221-
}
222-
klog.Warning(err)
223-
}
207+
cniReconciler := cni.NewReconciler(azClient, ctrlClient, recorder, cpConfig, appGw, agicPod, env.AGICPodNamespace, env.AddonMode)
208+
209+
// create a new agic controller
210+
appGwIngressController := controller.NewAppGwIngressController(azClient, appGwIdentifier, k8sContext, recorder, metricStore, cniReconciler, agicPod, env.HostedOnUnderlay)
211+
212+
// initialize the http server and start it
213+
httpServer := httpserver.NewHTTPServer(
214+
appGwIngressController,
215+
metricStore,
216+
env.HTTPServicePort)
217+
httpServer.Start()
224218

225219
if err := appGwIngressController.Start(env); err != nil {
226220
errorLine := fmt.Sprint("Could not start AGIC: ", err)

cmd/appgw-ingress/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func validateNamespaces(namespaces []string, kubeClient *kubernetes.Clientset) e
3939
controllererrors.ErrorNoSuchNamespace,
4040
"error creating informers; Namespaces do not exist or Ingress Controller has no access to: %v", strings.Join(nonExistent, ","),
4141
)
42-
klog.Errorf(err.Error())
42+
klog.Error(err.Error())
4343
return err
4444
}
4545
return nil

pkg/azure/client.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,6 @@ func (az *azClient) ApplyRouteTable(subnetID string, routeTableID string) error
248248

249249
// if route table is not found, then simply add a log and return no error. routeTable will always be initialized.
250250
if routeTable.Response.StatusCode == 404 {
251-
klog.V(3).Infof("Error getting route table '%s' (this is relevant for AKS clusters using 'Kubenet' network plugin): %s",
252-
routeTableID,
253-
err.Error())
254251
return nil
255252
}
256253

pkg/cni/cni.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/azure"
77
n "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-03-01/network"
88
"github.com/pkg/errors"
9+
v1 "k8s.io/api/core/v1"
10+
"k8s.io/client-go/tools/record"
911
"sigs.k8s.io/controller-runtime/pkg/client"
1012
)
1113

@@ -14,30 +16,45 @@ import (
1416
type Reconciler struct {
1517
armClient azure.AzClient
1618
client client.Client
19+
cpConfig *azure.CloudProviderConfig
20+
appGw n.ApplicationGateway
1721
namespace string
1822
addonMode bool
23+
24+
reconciledKubenetCNI bool
25+
reconciledOverlayCNI bool
1926
}
2027

21-
func ReconcileCNI(ctx context.Context, armClient azure.AzClient, client client.Client, namespace string, cpConfig *azure.CloudProviderConfig, appGw n.ApplicationGateway, addonMode bool) error {
22-
r := &Reconciler{
23-
armClient: armClient,
24-
client: client,
25-
namespace: namespace,
26-
addonMode: addonMode,
28+
func NewReconciler(armClient azure.AzClient,
29+
client client.Client,
30+
recorder record.EventRecorder,
31+
cpConfig *azure.CloudProviderConfig,
32+
appGw n.ApplicationGateway,
33+
agicPod *v1.Pod,
34+
namespace string,
35+
addonMode bool) *Reconciler {
36+
return &Reconciler{
37+
armClient: armClient,
38+
client: client,
39+
cpConfig: cpConfig,
40+
appGw: appGw,
41+
namespace: namespace,
42+
addonMode: addonMode,
43+
reconciledKubenetCNI: false,
44+
reconciledOverlayCNI: false,
2745
}
28-
29-
return r.Reconcile(ctx, cpConfig, appGw)
3046
}
3147

32-
func (r *Reconciler) Reconcile(ctx context.Context, cpConfig *azure.CloudProviderConfig, appGw n.ApplicationGateway) error {
33-
subnetID := *(*appGw.GatewayIPConfigurations)[0].Subnet.ID
48+
func (r *Reconciler) Reconcile(ctx context.Context) error {
49+
subnetID := *(*r.appGw.GatewayIPConfigurations)[0].Subnet.ID
50+
51+
if err := r.reconcileKubenetCniIfNeeded(r.cpConfig, subnetID); err != nil {
52+
return errors.Wrap(err, "failed to reconcile kubenet CNI")
53+
}
3454

3555
if err := r.reconcileOverlayCniIfNeeded(ctx, subnetID); err != nil {
3656
return errors.Wrap(err, "failed to reconcile overlay CNI")
3757
}
3858

39-
if err := r.reconcileKubenetCniIfNeeded(cpConfig, subnetID); err != nil {
40-
return errors.Wrap(err, "failed to reconcile kubenet CNI")
41-
}
4259
return nil
4360
}

pkg/cni/kubenet.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import (
66
)
77

88
func (r *Reconciler) reconcileKubenetCniIfNeeded(cpConfig *azure.CloudProviderConfig, subnetID string) error {
9+
if r.reconciledKubenetCNI {
10+
return nil
11+
}
12+
913
if cpConfig == nil || cpConfig.RouteTableName == "" {
1014
return nil
1115
}
@@ -17,5 +21,6 @@ func (r *Reconciler) reconcileKubenetCniIfNeeded(cpConfig *azure.CloudProviderCo
1721
routeTableID)
1822
}
1923

24+
r.reconciledKubenetCNI = true
2025
return nil
2126
}

pkg/cni/kubenet_test.go

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import (
55

66
. "github.com/onsi/ginkgo/v2"
77
. "github.com/onsi/gomega"
8+
"github.com/pkg/errors"
9+
v1 "k8s.io/api/core/v1"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/client-go/tools/record"
812
ctrl_client "sigs.k8s.io/controller-runtime/pkg/client"
913
ctrl_client_fake "sigs.k8s.io/controller-runtime/pkg/client/fake"
1014

@@ -16,9 +20,12 @@ import (
1620
)
1721

1822
var _ = Describe("Kubenet CNI", func() {
19-
var ctx = context.TODO()
23+
var ctx context.Context
24+
var cancel context.CancelFunc
2025
var azClient *azure.FakeAzClient
2126
var k8sClient ctrl_client.Client
27+
var recorder *record.FakeRecorder
28+
var agicPod *v1.Pod
2229
var appGw = n.ApplicationGateway{
2330
ApplicationGatewayPropertiesFormat: &n.ApplicationGatewayPropertiesFormat{
2431
GatewayIPConfigurations: &[]n.ApplicationGatewayIPConfiguration{
@@ -32,12 +39,32 @@ var _ = Describe("Kubenet CNI", func() {
3239
},
3340
},
3441
}
42+
var reconciler *cni.Reconciler
3543

3644
BeforeEach(func() {
45+
ctx, cancel = context.WithCancel(context.Background())
3746
azClient = azure.NewFakeAzClient()
47+
recorder = record.NewFakeRecorder(100)
48+
recorder.IncludeObject = true
49+
agicPod = &v1.Pod{
50+
ObjectMeta: metav1.ObjectMeta{
51+
Name: "agic",
52+
Namespace: "kube-system",
53+
},
54+
TypeMeta: metav1.TypeMeta{
55+
Kind: "Pod",
56+
APIVersion: "v1",
57+
},
58+
}
3859

3960
scheme, _ := k8s.NewScheme()
4061
k8sClient = ctrl_client_fake.NewClientBuilder().WithScheme(scheme).Build()
62+
63+
reconciler = cni.NewReconciler(azClient, k8sClient, recorder, &azure.CloudProviderConfig{
64+
SubscriptionID: "test-sub",
65+
RouteTableResourceGroup: "test-rg",
66+
RouteTableName: "test-rt",
67+
}, appGw, agicPod, "test", false)
4168
})
4269

4370
Context("reconcileKubenetCniIfNeeded", func() {
@@ -48,12 +75,8 @@ var _ = Describe("Kubenet CNI", func() {
4875
return nil
4976
}
5077

51-
err := cni.ReconcileCNI(ctx, azClient, k8sClient, "test", &azure.CloudProviderConfig{
52-
SubscriptionID: "test-sub",
53-
RouteTableResourceGroup: "test-rg",
54-
RouteTableName: "test-rt",
55-
}, appGw, false)
56-
Expect(err).To(BeNil())
78+
reconciler.Reconcile(ctx)
79+
Eventually(recorder.Events).ShouldNot(Receive())
5780
})
5881

5982
It("should return nil if RouteTableName is empty", func() {
@@ -62,10 +85,26 @@ var _ = Describe("Kubenet CNI", func() {
6285
return nil
6386
}
6487

65-
err := cni.ReconcileCNI(ctx, azClient, k8sClient, "test", &azure.CloudProviderConfig{
66-
RouteTableName: "",
67-
}, appGw, false)
68-
Expect(err).To(BeNil())
88+
reconciler = cni.NewReconciler(azClient, k8sClient, recorder, &azure.CloudProviderConfig{
89+
SubscriptionID: "test-sub",
90+
}, appGw, agicPod, "test", false)
91+
92+
err := reconciler.Reconcile(ctx)
93+
Expect(err).ToNot(HaveOccurred())
6994
})
95+
96+
It("should create event if ApplyRouteTable fails", func() {
97+
azClient.ApplyRouteTableFunc = func(subnetID string, routeTableID string) error {
98+
return errors.New("failed to apply route table")
99+
}
100+
101+
err := reconciler.Reconcile(ctx)
102+
Expect(err).To(HaveOccurred())
103+
Expect(err.Error()).To(ContainSubstring("failed to apply route table"))
104+
})
105+
})
106+
107+
AfterEach(func() {
108+
cancel()
70109
})
71110
})

0 commit comments

Comments
 (0)