Skip to content

Commit

Permalink
Make route tables reconcile/delete async
Browse files Browse the repository at this point in the history
Update routetables_test.go
  • Loading branch information
Cecile Robert-Michon committed Sep 14, 2021
1 parent f2833b4 commit 9121e36
Showing 10 changed files with 397 additions and 535 deletions.
2 changes: 2 additions & 0 deletions api/v1alpha4/conditions_consts.go
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ import clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4"

// AzureCluster Conditions and Reasons.
const (
// NetworkInfrastructureReadyCondition reports of current status of cluster infrastructure.
NetworkInfrastructureReadyCondition clusterv1.ConditionType = "NetworkInfrastructureReady"
// NamespaceNotAllowedByIdentity used to indicate cluster in a namespace not allowed by identity.
NamespaceNotAllowedByIdentity = "NamespaceNotAllowedByIdentity"
)
19 changes: 14 additions & 5 deletions azure/scope/cluster.go
Original file line number Diff line number Diff line change
@@ -36,6 +36,7 @@ import (

infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha4"
"sigs.k8s.io/cluster-api-provider-azure/azure"
"sigs.k8s.io/cluster-api-provider-azure/azure/services/routetables"
"sigs.k8s.io/cluster-api-provider-azure/azure/services/securitygroups"
"sigs.k8s.io/cluster-api-provider-azure/azure/services/virtualnetworks"
"sigs.k8s.io/cluster-api-provider-azure/util/futures"
@@ -219,16 +220,20 @@ func (s *ClusterScope) LBSpecs() []azure.LBSpec {
return specs
}

// RouteTableSpecs returns the node route table.
func (s *ClusterScope) RouteTableSpecs() []azure.RouteTableSpec {
routetables := []azure.RouteTableSpec{}
// RouteTableSpecs returns the subnet route tables.
func (s *ClusterScope) RouteTableSpecs() []azure.ResourceSpecGetter {
specs := []azure.ResourceSpecGetter{}
for _, subnet := range s.AzureCluster.Spec.NetworkSpec.Subnets {
if subnet.RouteTable.Name != "" {
routetables = append(routetables, azure.RouteTableSpec{Name: subnet.RouteTable.Name, Subnet: subnet})
specs = append(specs, &routetables.RouteTableSpec{
Name: subnet.RouteTable.Name,
Location: s.Location(),
ResourceGroup: s.ResourceGroup(),
})
}
}

return routetables
return specs
}

// NatGatewaySpecs returns the node nat gateway.
@@ -565,6 +570,8 @@ func (s *ClusterScope) PatchObject(ctx context.Context) error {
conditions.WithConditions(
infrav1.VNetReadyCondition,
infrav1.SecurityGroupsReadyCondition,
infrav1.RouteTablesReadyCondition,
infrav1.NetworkInfrastructureReadyCondition,
),
)

@@ -575,6 +582,8 @@ func (s *ClusterScope) PatchObject(ctx context.Context) error {
clusterv1.ReadyCondition,
infrav1.VNetReadyCondition,
infrav1.SecurityGroupsReadyCondition,
infrav1.RouteTablesReadyCondition,
infrav1.NetworkInfrastructureReadyCondition,
}})
}

102 changes: 87 additions & 15 deletions azure/services/routetables/client.go
Original file line number Diff line number Diff line change
@@ -21,16 +21,20 @@ import (

"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network"
"github.com/Azure/go-autorest/autorest"
azureautorest "github.com/Azure/go-autorest/autorest/azure"
"github.com/pkg/errors"

"sigs.k8s.io/cluster-api-provider-azure/azure"
"sigs.k8s.io/cluster-api-provider-azure/util/reconciler"
"sigs.k8s.io/cluster-api-provider-azure/util/tele"
)

// client wraps go-sdk.
type client interface {
Get(context.Context, string, string) (network.RouteTable, error)
CreateOrUpdate(context.Context, string, string, network.RouteTable) error
Delete(context.Context, string, string) error
CreateOrUpdateAsync(context.Context, azure.ResourceSpecGetter) (azureautorest.FutureAPI, error)
DeleteAsync(context.Context, azure.ResourceSpecGetter) (azureautorest.FutureAPI, error)
IsDone(context.Context, azureautorest.FutureAPI) (bool, error)
}

// azureClient contains the Azure go-sdk Client.
@@ -61,36 +65,104 @@ func (ac *azureClient) Get(ctx context.Context, resourceGroupName, rtName string
return ac.routetables.Get(ctx, resourceGroupName, rtName, "")
}

// CreateOrUpdate create or updates a route table in a specified resource group.
func (ac *azureClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, rtName string, rt network.RouteTable) error {
ctx, span := tele.Tracer().Start(ctx, "routetables.AzureClient.CreateOrUpdate")
// CreateOrUpdateAsync creates or updates a route table asynchronously.
// It sends a PUT request to Azure and if accepted without error, the func will return a Future which can be used to track the ongoing
// progress of the operation.
func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter) (azureautorest.FutureAPI, error) {
ctx, span := tele.Tracer().Start(ctx, "routetables.AzureClient.CreateOrUpdateAsync")
defer span.End()

future, err := ac.routetables.CreateOrUpdate(ctx, resourceGroupName, rtName, rt)
rt, err := ac.RouteTableParams(ctx, spec)
if err != nil {
return err
return nil, errors.Wrapf(err, "failed to get desired parameters for route table %s", spec.ResourceName())
} else if rt == nil {
// nothing to do here.
return nil, nil
}

future, err := ac.routetables.CreateOrUpdate(ctx, spec.ResourceGroupName(), spec.ResourceName(), *rt)
if err != nil {
return nil, err
}

ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout)
defer cancel()

err = future.WaitForCompletionRef(ctx, ac.routetables.Client)
if err != nil {
return err
// if an error occurs, return the future.
// this means the long-running operation didn't finish in the specified timeout.
return &future, err
}
_, err = future.Result(ac.routetables)
return err
// if the operation completed, return a nil future
return nil, err
}

// Delete deletes the specified route table.
func (ac *azureClient) Delete(ctx context.Context, resourceGroupName, rtName string) error {
// DeleteAsync deletes a route table asynchronously. DeleteAsync sends a DELETE
// request to Azure and if accepted without error, the func will return a Future which can be used to track the ongoing
// progress of the operation.
func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter) (azureautorest.FutureAPI, error) {
ctx, span := tele.Tracer().Start(ctx, "routetables.AzureClient.Delete")
defer span.End()

future, err := ac.routetables.Delete(ctx, resourceGroupName, rtName)
future, err := ac.routetables.Delete(ctx, spec.ResourceGroupName(), spec.ResourceName())
if err != nil {
return err
return nil, err
}

ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout)
defer cancel()

err = future.WaitForCompletionRef(ctx, ac.routetables.Client)
if err != nil {
return err
// if an error occurs, return the future.
// this means the long-running operation didn't finish in the specified timeout.
return &future, err
}
_, err = future.Result(ac.routetables)
return err
// if the operation completed, return a nil future.
return nil, err
}

// IsDone returns true if the long-running operation has completed.
func (ac *azureClient) IsDone(ctx context.Context, future azureautorest.FutureAPI) (bool, error) {
ctx, span := tele.Tracer().Start(ctx, "routetables.AzureClient.IsDone")
defer span.End()

done, err := future.DoneWithContext(ctx, ac.routetables)
if err != nil {
return false, errors.Wrap(err, "failed checking if the operation was complete")
}

return done, nil
}

// RouteTableParams creates a RouteTable object from the given spec.
func (ac *azureClient) RouteTableParams(ctx context.Context, spec azure.ResourceSpecGetter) (*network.RouteTable, error) {
var params interface{}
var existing interface{}

if existingRT, err := ac.Get(ctx, spec.ResourceGroupName(), spec.ResourceName()); err != nil && !azure.ResourceNotFound(err) {
return nil, errors.Wrapf(err, "failed to get route table %s in %s", spec.ResourceName(), spec.ResourceGroupName())
} else if err == nil {
// route table already exists
existing = existingRT
}

params, err := spec.Parameters(existing)
if err != nil {
return nil, err
}

rt, ok := params.(network.RouteTable)
if !ok {
if params == nil {
// nothing to do here.
return nil, nil
}
return nil, errors.Errorf("%T is not a network.RouteTable", params)
}

return &rt, nil
}
51 changes: 35 additions & 16 deletions azure/services/routetables/mock_routetables/client_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9121e36

Please # to comment.