Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions azure/scope/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"sigs.k8s.io/cluster-api-provider-azure/azure/services/loadbalancers"
"sigs.k8s.io/cluster-api-provider-azure/azure/services/natgateways"
"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/subnets"
"sigs.k8s.io/cluster-api-provider-azure/azure/services/virtualnetworks"
"sigs.k8s.io/cluster-api-provider-azure/azure/services/vnetpeerings"
Expand Down Expand Up @@ -277,12 +278,14 @@ func (s *ClusterScope) NatGatewaySpecs() []azure.ResourceSpecGetter {
}

// NSGSpecs returns the security group specs.
func (s *ClusterScope) NSGSpecs() []azure.NSGSpec {
nsgspecs := make([]azure.NSGSpec, len(s.AzureCluster.Spec.NetworkSpec.Subnets))
func (s *ClusterScope) NSGSpecs() []azure.ResourceSpecGetter {
nsgspecs := make([]azure.ResourceSpecGetter, len(s.AzureCluster.Spec.NetworkSpec.Subnets))
for i, subnet := range s.AzureCluster.Spec.NetworkSpec.Subnets {
nsgspecs[i] = azure.NSGSpec{
nsgspecs[i] = &securitygroups.NSGSpec{
Name: subnet.SecurityGroup.Name,
SecurityRules: subnet.SecurityGroup.SecurityRules,
ResourceGroup: s.ResourceGroup(),
Location: s.Location(),
}
}

Expand Down Expand Up @@ -696,6 +699,7 @@ func (s *ClusterScope) PatchObject(ctx context.Context) error {
infrav1.BastionHostReadyCondition,
infrav1.VNetReadyCondition,
infrav1.SubnetsReadyCondition,
infrav1.SecurityGroupsReadyCondition,
}})
}

Expand Down
130 changes: 97 additions & 33 deletions azure/services/securitygroups/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,23 @@ package securitygroups

import (
"context"
"encoding/json"

"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"
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
"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.SecurityGroup, error)
CreateOrUpdate(context.Context, string, string, network.SecurityGroup) error
Delete(context.Context, string, string) error
}

// azureClient contains the Azure go-sdk Client.
type azureClient struct {
securitygroups network.SecurityGroupsClient
}

var _ client = (*azureClient)(nil)

// newClient creates a new VM client from subscription ID.
func newClient(auth azure.Authorizer) *azureClient {
c := newSecurityGroupsClient(auth.SubscriptionID(), auth.BaseURI(), auth.Authorizer())
Expand All @@ -53,58 +49,126 @@ func newSecurityGroupsClient(subscriptionID string, baseURI string, authorizer a
}

// Get gets the specified network security group.
func (ac *azureClient) Get(ctx context.Context, resourceGroupName, sgName string) (network.SecurityGroup, error) {
ctx, _, done := tele.StartSpanWithLogger(ctx, "securitygroups.AzureClient.Get")
func (ac *azureClient) Get(ctx context.Context, spec azure.ResourceSpecGetter) (result interface{}, err error) {
ctx, _, done := tele.StartSpanWithLogger(ctx, "securitygroups.azureClient.Get")
defer done()

return ac.securitygroups.Get(ctx, resourceGroupName, sgName, "")
return ac.securitygroups.Get(ctx, spec.ResourceGroupName(), spec.ResourceName(), "")
}

// CreateOrUpdate creates or updates a network security group in the specified resource group.
func (ac *azureClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, sgName string, sg network.SecurityGroup) error {
ctx, _, done := tele.StartSpanWithLogger(ctx, "securitygroups.AzureClient.CreateOrUpdate")
// CreateOrUpdateAsync creates or updates a network security group in the specified resource group.
// 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, parameters interface{}) (result interface{}, future azureautorest.FutureAPI, err error) {
ctx, _, done := tele.StartSpanWithLogger(ctx, "securitygroups.azureClient.CreateOrUpdate")
defer done()

sg, ok := parameters.(network.SecurityGroup)
if !ok {
return nil, nil, errors.Errorf("%T is not a network.SecurityGroup", parameters)
}

var etag string
if sg.Etag != nil {
etag = *sg.Etag
}
req, err := ac.securitygroups.CreateOrUpdatePreparer(ctx, resourceGroupName, sgName, sg)
req, err := ac.securitygroups.CreateOrUpdatePreparer(ctx, spec.ResourceGroupName(), spec.ResourceName(), sg)
if err != nil {
err = autorest.NewErrorWithError(err, "network.SecurityGroupsClient", "CreateOrUpdate", nil, "Failure preparing request")
return err
return nil, nil, err
}
if etag != "" {
req.Header.Add("If-Match", etag)
}

future, err := ac.securitygroups.CreateOrUpdateSender(req)
createFuture, err := ac.securitygroups.CreateOrUpdateSender(req)
if err != nil {
err = autorest.NewErrorWithError(err, "network.SecurityGroupsClient", "CreateOrUpdate", future.Response(), "Failure sending request")
return err
err = autorest.NewErrorWithError(err, "network.SecurityGroupsClient", "CreateOrUpdate", createFuture.Response(), "Failure sending request")
return nil, nil, err
}

err = future.WaitForCompletionRef(ctx, ac.securitygroups.Client)
ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout)
defer cancel()

err = createFuture.WaitForCompletionRef(ctx, ac.securitygroups.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 nil, &createFuture, err
}
_, err = future.Result(ac.securitygroups)
return err
result, err = createFuture.Result(ac.securitygroups)
// if the operation completed, return a nil future.
return result, nil, err
}

// Delete deletes the specified network security group.
func (ac *azureClient) Delete(ctx context.Context, resourceGroupName, sgName string) error {
ctx, _, done := tele.StartSpanWithLogger(ctx, "securitygroups.AzureClient.Delete")
// Delete deletes the specified network security group. 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) (future azureautorest.FutureAPI, err error) {
ctx, _, done := tele.StartSpanWithLogger(ctx, "securitygroups.azureClient.Delete")
defer done()

future, err := ac.securitygroups.Delete(ctx, resourceGroupName, sgName)
deleteFuture, err := ac.securitygroups.Delete(ctx, spec.ResourceGroupName(), spec.ResourceName())
if err != nil {
return err
return nil, err
}
err = future.WaitForCompletionRef(ctx, ac.securitygroups.Client)

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

err = deleteFuture.WaitForCompletionRef(ctx, ac.securitygroups.Client)
if err != nil {
// if an error occurs, return the future.
// this means the long-running operation didn't finish in the specified timeout.
return &deleteFuture, err
}
_, err = deleteFuture.Result(ac.securitygroups)
// 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) (isDone bool, err error) {
ctx, _, done := tele.StartSpanWithLogger(ctx, "securitygroups.azureClient.IsDone")
defer done()

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

return isDone, nil
}

// Result fetches the result of a long-running operation future.
func (ac *azureClient) Result(ctx context.Context, future azureautorest.FutureAPI, futureType string) (result interface{}, err error) {
_, _, done := tele.StartSpanWithLogger(ctx, "securitygroups.azureClient.Result")
defer done()

if future == nil {
return nil, errors.Errorf("cannot get result from nil future")
}

switch futureType {
case infrav1.PutFuture:
// Marshal and Unmarshal the future to put it into the correct future type so we can access the Result function.
// Unfortunately the FutureAPI can't be casted directly to SecurityGroupsCreateOrUpdateFuture because it is a azureautorest.Future, which doesn't implement the Result function. See PR #1686 for discussion on alternatives.
// It was converted back to a generic azureautorest.Future from the CAPZ infrav1.Future type stored in Status: https://github.com/kubernetes-sigs/cluster-api-provider-azure/blob/main/azure/converters/futures.go#L49.
var createFuture *network.SecurityGroupsCreateOrUpdateFuture
jsonData, err := future.MarshalJSON()
if err != nil {
return nil, errors.Wrap(err, "failed to marshal future")
}
if err := json.Unmarshal(jsonData, &createFuture); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal future data")
}
return createFuture.Result(ac.securitygroups)

case infrav1.DeleteFuture:
// Delete does not return a result security group.
return nil, nil

default:
return nil, errors.Errorf("unknown future type %q", futureType)
}
_, err = future.Result(ac.securitygroups)
return err
}
95 changes: 0 additions & 95 deletions azure/services/securitygroups/mock_securitygroups/client_mock.go

This file was deleted.

2 changes: 0 additions & 2 deletions azure/services/securitygroups/mock_securitygroups/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ limitations under the License.
*/

// Run go generate to regenerate this mock.
//go:generate ../../../../hack/tools/bin/mockgen -destination client_mock.go -package mock_securitygroups -source ../client.go Client
//go:generate ../../../../hack/tools/bin/mockgen -destination securitygroups_mock.go -package mock_securitygroups -source ../securitygroups.go NSGScope
//go:generate /usr/bin/env bash -c "cat ../../../../hack/boilerplate/boilerplate.generatego.txt client_mock.go > _client_mock.go && mv _client_mock.go client_mock.go"
//go:generate /usr/bin/env bash -c "cat ../../../../hack/boilerplate/boilerplate.generatego.txt securitygroups_mock.go > _securitygroups_mock.go && mv _securitygroups_mock.go securitygroups_mock.go"
package mock_securitygroups //nolint
Loading