Merge pull request #15570 from hakman/azure_network_security

azure: Add support for network security groups
This commit is contained in:
Kubernetes Prow Robot 2023-07-01 06:54:48 -07:00 committed by GitHub
commit 49a6ed4188
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 629 additions and 62 deletions

View File

@ -17,8 +17,12 @@ limitations under the License.
package azuremodel package azuremodel
import ( import (
"fmt"
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-05-01/network"
"k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/azuretasks" "k8s.io/kops/upup/pkg/fi/cloudup/azuretasks"
"k8s.io/utils/net"
) )
// NetworkModelBuilder configures a Virtual Network and subnets. // NetworkModelBuilder configures a Virtual Network and subnets.
@ -41,12 +45,132 @@ func (b *NetworkModelBuilder) Build(c *fi.CloudupModelBuilderContext) error {
} }
c.AddTask(networkTask) c.AddTask(networkTask)
nsgTask := &azuretasks.NetworkSecurityGroup{
Name: fi.PtrTo(b.NameForVirtualNetwork()),
Lifecycle: b.Lifecycle,
ResourceGroup: b.LinkToResourceGroup(),
Tags: map[string]*string{},
}
var sshAccessIPv4, sshAccessIPv6 []string
for _, cidr := range b.Cluster.Spec.SSHAccess {
switch net.IPFamilyOfCIDRString(cidr) {
case net.IPv4:
sshAccessIPv4 = append(sshAccessIPv4, cidr)
case net.IPv6:
sshAccessIPv6 = append(sshAccessIPv6, cidr)
default:
return fmt.Errorf("unknown IP family for CIDR: %q", cidr)
}
}
if len(sshAccessIPv4) > 0 {
nsgTask.SecurityRules = append(nsgTask.SecurityRules, &azuretasks.NetworkSecurityRule{
Name: fi.PtrTo("AllowSSH"),
Priority: fi.PtrTo[int32](100),
Access: network.SecurityRuleAccessAllow,
Direction: network.SecurityRuleDirectionInbound,
Protocol: network.SecurityRuleProtocolTCP,
SourceAddressPrefixes: &sshAccessIPv4,
SourcePortRange: fi.PtrTo("*"),
DestinationAddressPrefix: fi.PtrTo("*"),
DestinationPortRange: fi.PtrTo("22"),
})
}
if len(sshAccessIPv6) > 0 {
nsgTask.SecurityRules = append(nsgTask.SecurityRules, &azuretasks.NetworkSecurityRule{
Name: fi.PtrTo("AllowSSH_v6"),
Priority: fi.PtrTo[int32](101),
Access: network.SecurityRuleAccessAllow,
Direction: network.SecurityRuleDirectionInbound,
Protocol: network.SecurityRuleProtocolTCP,
SourceAddressPrefixes: &sshAccessIPv6,
SourcePortRange: fi.PtrTo("*"),
DestinationAddressPrefix: fi.PtrTo("*"),
DestinationPortRange: fi.PtrTo("22"),
})
}
var k8sAccessIPv4, k8sAccessIPv6 []string
for _, cidr := range b.Cluster.Spec.API.Access {
switch net.IPFamilyOfCIDRString(cidr) {
case net.IPv4:
k8sAccessIPv4 = append(k8sAccessIPv4, cidr)
case net.IPv6:
k8sAccessIPv6 = append(k8sAccessIPv6, cidr)
default:
return fmt.Errorf("unknown IP family for CIDR: %q", cidr)
}
}
if len(k8sAccessIPv4) > 0 {
nsgTask.SecurityRules = append(nsgTask.SecurityRules, &azuretasks.NetworkSecurityRule{
Name: fi.PtrTo("AllowKubernetesAPI"),
Priority: fi.PtrTo[int32](200),
Access: network.SecurityRuleAccessAllow,
Direction: network.SecurityRuleDirectionInbound,
Protocol: network.SecurityRuleProtocolTCP,
SourceAddressPrefixes: &k8sAccessIPv4,
SourcePortRange: fi.PtrTo("*"),
DestinationAddressPrefix: fi.PtrTo("*"),
DestinationPortRange: fi.PtrTo("443"),
})
}
if len(k8sAccessIPv6) > 0 {
nsgTask.SecurityRules = append(nsgTask.SecurityRules, &azuretasks.NetworkSecurityRule{
Name: fi.PtrTo("AllowKubernetesAPI_v6"),
Priority: fi.PtrTo[int32](201),
Access: network.SecurityRuleAccessAllow,
Direction: network.SecurityRuleDirectionInbound,
Protocol: network.SecurityRuleProtocolTCP,
SourceAddressPrefixes: &k8sAccessIPv6,
SourcePortRange: fi.PtrTo("*"),
DestinationAddressPrefix: fi.PtrTo("*"),
DestinationPortRange: fi.PtrTo("443"),
})
}
var nodePortAccessIPv4, nodePortAccessIPv6 []string
for _, cidr := range b.Cluster.Spec.NodePortAccess {
switch net.IPFamilyOfCIDRString(cidr) {
case net.IPv4:
nodePortAccessIPv4 = append(nodePortAccessIPv4, cidr)
case net.IPv6:
nodePortAccessIPv6 = append(nodePortAccessIPv6, cidr)
default:
return fmt.Errorf("unknown IP family for CIDR: %q", cidr)
}
}
if len(nodePortAccessIPv4) > 0 {
nsgTask.SecurityRules = append(nsgTask.SecurityRules, &azuretasks.NetworkSecurityRule{
Name: fi.PtrTo("AllowNodePort"),
Priority: fi.PtrTo[int32](300),
Access: network.SecurityRuleAccessAllow,
Direction: network.SecurityRuleDirectionInbound,
Protocol: network.SecurityRuleProtocolTCP,
SourceAddressPrefixes: &nodePortAccessIPv4,
SourcePortRange: fi.PtrTo("*"),
DestinationAddressPrefix: fi.PtrTo("*"),
DestinationPortRange: fi.PtrTo("443"),
})
}
if len(nodePortAccessIPv6) > 0 {
nsgTask.SecurityRules = append(nsgTask.SecurityRules, &azuretasks.NetworkSecurityRule{
Name: fi.PtrTo("AllowNodePort_v6"),
Priority: fi.PtrTo[int32](301),
Access: network.SecurityRuleAccessAllow,
Direction: network.SecurityRuleDirectionInbound,
Protocol: network.SecurityRuleProtocolTCP,
SourceAddressPrefixes: &nodePortAccessIPv6,
SourcePortRange: fi.PtrTo("*"),
DestinationAddressPrefix: fi.PtrTo("*"),
DestinationPortRange: fi.PtrTo("443"),
})
}
c.AddTask(nsgTask)
for _, subnetSpec := range b.Cluster.Spec.Networking.Subnets { for _, subnetSpec := range b.Cluster.Spec.Networking.Subnets {
subnetTask := &azuretasks.Subnet{ subnetTask := &azuretasks.Subnet{
Name: fi.PtrTo(subnetSpec.Name), Name: fi.PtrTo(subnetSpec.Name),
Lifecycle: b.Lifecycle, Lifecycle: b.Lifecycle,
ResourceGroup: b.LinkToResourceGroup(), ResourceGroup: b.LinkToResourceGroup(),
VirtualNetwork: b.LinkToVirtualNetwork(), VirtualNetwork: b.LinkToVirtualNetwork(),
NetworkSecurityGroup: nsgTask,
CIDR: fi.PtrTo(subnetSpec.CIDR), CIDR: fi.PtrTo(subnetSpec.CIDR),
Shared: fi.PtrTo(b.Cluster.SharedVPC()), Shared: fi.PtrTo(b.Cluster.SharedVPC()),
} }

View File

@ -33,6 +33,7 @@ import (
const ( const (
typeResourceGroup = "ResourceGroup" typeResourceGroup = "ResourceGroup"
typeVirtualNetwork = "VirtualNetwork" typeVirtualNetwork = "VirtualNetwork"
typeNetworkSecurityGroup = "NetworkSecurityGroup"
typeSubnet = "Subnet" typeSubnet = "Subnet"
typeRouteTable = "RouteTable" typeRouteTable = "RouteTable"
typeVMScaleSet = "VMScaleSet" typeVMScaleSet = "VMScaleSet"
@ -85,6 +86,7 @@ func (g *resourceGetter) listAll() ([]*resources.Resource, error) {
fns := []func(ctx context.Context) ([]*resources.Resource, error){ fns := []func(ctx context.Context) ([]*resources.Resource, error){
g.listResourceGroups, g.listResourceGroups,
g.listVirtualNetworksAndSubnets, g.listVirtualNetworksAndSubnets,
g.listNetworkSecurityGroups,
g.listRouteTables, g.listRouteTables,
g.listVMScaleSetsAndRoleAssignments, g.listVMScaleSetsAndRoleAssignments,
g.listDisks, g.listDisks,
@ -209,6 +211,39 @@ func (g *resourceGetter) deleteSubnet(vnetName string, r *resources.Resource) er
return g.cloud.Subnet().Delete(context.TODO(), g.resourceGroupName(), vnetName, r.Name) return g.cloud.Subnet().Delete(context.TODO(), g.resourceGroupName(), vnetName, r.Name)
} }
func (g *resourceGetter) listNetworkSecurityGroups(ctx context.Context) ([]*resources.Resource, error) {
NetworkSecurityGroups, err := g.cloud.NetworkSecurityGroup().List(ctx, g.resourceGroupName())
if err != nil {
return nil, err
}
var rs []*resources.Resource
for i := range NetworkSecurityGroups {
rs = append(rs, g.toNetworkSecurityGroupResource(&NetworkSecurityGroups[i]))
}
return rs, nil
}
func (g *resourceGetter) toNetworkSecurityGroupResource(NetworkSecurityGroup *network.SecurityGroup) *resources.Resource {
return &resources.Resource{
Obj: NetworkSecurityGroup,
Type: typeNetworkSecurityGroup,
ID: *NetworkSecurityGroup.Name,
Name: *NetworkSecurityGroup.Name,
Deleter: func(_ fi.Cloud, r *resources.Resource) error {
return g.deleteNetworkSecurityGroup(r)
},
Blocks: []string{
toKey(typeResourceGroup, g.resourceGroupName()),
},
Shared: g.clusterInfo.AzureNetworkShared,
}
}
func (g *resourceGetter) deleteNetworkSecurityGroup(r *resources.Resource) error {
return g.cloud.NetworkSecurityGroup().Delete(context.TODO(), g.resourceGroupName(), r.Name)
}
func (g *resourceGetter) listRouteTables(ctx context.Context) ([]*resources.Resource, error) { func (g *resourceGetter) listRouteTables(ctx context.Context) ([]*resources.Resource, error) {
rts, err := g.cloud.RouteTable().List(ctx, g.resourceGroupName()) rts, err := g.cloud.RouteTable().List(ctx, g.resourceGroupName())
if err != nil { if err != nil {

View File

@ -49,6 +49,7 @@ type AzureCloud interface {
VirtualNetwork() VirtualNetworksClient VirtualNetwork() VirtualNetworksClient
Subnet() SubnetsClient Subnet() SubnetsClient
RouteTable() RouteTablesClient RouteTable() RouteTablesClient
NetworkSecurityGroup() NetworkSecurityGroupsClient
VMScaleSet() VMScaleSetsClient VMScaleSet() VMScaleSetsClient
VMScaleSetVM() VMScaleSetVMsClient VMScaleSetVM() VMScaleSetVMsClient
Disk() DisksClient Disk() DisksClient
@ -63,6 +64,7 @@ type azureCloudImplementation struct {
location string location string
tags map[string]string tags map[string]string
resourceGroupsClient ResourceGroupsClient resourceGroupsClient ResourceGroupsClient
networkSecurityGroupsClient NetworkSecurityGroupsClient
vnetsClient VirtualNetworksClient vnetsClient VirtualNetworksClient
subnetsClient SubnetsClient subnetsClient SubnetsClient
routeTablesClient RouteTablesClient routeTablesClient RouteTablesClient
@ -92,6 +94,7 @@ func NewAzureCloud(subscriptionID, location string, tags map[string]string) (Azu
vnetsClient: newVirtualNetworksClientImpl(subscriptionID, authorizer), vnetsClient: newVirtualNetworksClientImpl(subscriptionID, authorizer),
subnetsClient: newSubnetsClientImpl(subscriptionID, authorizer), subnetsClient: newSubnetsClientImpl(subscriptionID, authorizer),
routeTablesClient: newRouteTablesClientImpl(subscriptionID, authorizer), routeTablesClient: newRouteTablesClientImpl(subscriptionID, authorizer),
networkSecurityGroupsClient: newNetworkSecurityGroupsClientImpl(subscriptionID, authorizer),
vmscaleSetsClient: newVMScaleSetsClientImpl(subscriptionID, authorizer), vmscaleSetsClient: newVMScaleSetsClientImpl(subscriptionID, authorizer),
vmscaleSetVMsClient: newVMScaleSetVMsClientImpl(subscriptionID, authorizer), vmscaleSetVMsClient: newVMScaleSetVMsClientImpl(subscriptionID, authorizer),
disksClient: newDisksClientImpl(subscriptionID, authorizer), disksClient: newDisksClientImpl(subscriptionID, authorizer),
@ -286,6 +289,10 @@ func (c *azureCloudImplementation) RouteTable() RouteTablesClient {
return c.routeTablesClient return c.routeTablesClient
} }
func (c *azureCloudImplementation) NetworkSecurityGroup() NetworkSecurityGroupsClient {
return c.networkSecurityGroupsClient
}
func (c *azureCloudImplementation) VMScaleSet() VMScaleSetsClient { func (c *azureCloudImplementation) VMScaleSet() VMScaleSetsClient {
return c.vmscaleSetsClient return c.vmscaleSetsClient
} }

View File

@ -0,0 +1,83 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package azure
import (
"context"
"fmt"
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-05-01/network"
"github.com/Azure/go-autorest/autorest"
)
// NetworkSecurityGroupsClient is a client for managing Network Security Groups.
type NetworkSecurityGroupsClient interface {
CreateOrUpdate(ctx context.Context, resourceGroupName, NetworkSecurityGroupName string, parameters network.SecurityGroup) (*network.SecurityGroup, error)
List(ctx context.Context, resourceGroupName string) ([]network.SecurityGroup, error)
Delete(ctx context.Context, resourceGroupName, NetworkSecurityGroupName string) error
}
type NetworkSecurityGroupsClientImpl struct {
c *network.SecurityGroupsClient
}
var _ NetworkSecurityGroupsClient = &NetworkSecurityGroupsClientImpl{}
func (c *NetworkSecurityGroupsClientImpl) CreateOrUpdate(ctx context.Context, resourceGroupName, NetworkSecurityGroupName string, parameters network.SecurityGroup) (*network.SecurityGroup, error) {
future, err := c.c.CreateOrUpdate(ctx, resourceGroupName, NetworkSecurityGroupName, parameters)
if err != nil {
return nil, fmt.Errorf("error creating/updating Network Security Group: %w", err)
}
if err := future.WaitForCompletionRef(ctx, c.c.Client); err != nil {
return nil, fmt.Errorf("error waiting for Network Security Group create/update completion: %w", err)
}
asg, err := future.Result(*c.c)
if err != nil {
return nil, fmt.Errorf("error obtaining result for Network Security Group create/update: %w", err)
}
return &asg, err
}
func (c *NetworkSecurityGroupsClientImpl) List(ctx context.Context, resourceGroupName string) ([]network.SecurityGroup, error) {
var l []network.SecurityGroup
for iter, err := c.c.ListComplete(ctx, resourceGroupName); iter.NotDone(); err = iter.NextWithContext(ctx) {
if err != nil {
return nil, err
}
l = append(l, iter.Value())
}
return l, nil
}
func (c *NetworkSecurityGroupsClientImpl) Delete(ctx context.Context, resourceGroupName, NetworkSecurityGroupName string) error {
future, err := c.c.Delete(ctx, resourceGroupName, NetworkSecurityGroupName)
if err != nil {
return fmt.Errorf("error deleting Network Security Group: %w", err)
}
if err := future.WaitForCompletionRef(ctx, c.c.Client); err != nil {
return fmt.Errorf("error waiting for Network Security Group deletion completion: %w", err)
}
return nil
}
func newNetworkSecurityGroupsClientImpl(subscriptionID string, authorizer autorest.Authorizer) *NetworkSecurityGroupsClientImpl {
c := network.NewSecurityGroupsClient(subscriptionID)
c.Authorizer = authorizer
return &NetworkSecurityGroupsClientImpl{
c: &c,
}
}

View File

@ -0,0 +1,197 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package azuretasks
import (
"context"
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-05-01/network"
"github.com/Azure/go-autorest/autorest/to"
"k8s.io/klog/v2"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/azure"
)
// NetworkSecurityGroup is an Azure Cloud Network Security Group
// +kops:fitask
type NetworkSecurityGroup struct {
Name *string
ID *string
Lifecycle fi.Lifecycle
ResourceGroup *ResourceGroup
SecurityRules []*NetworkSecurityRule
Tags map[string]*string
}
var (
_ fi.CloudupTask = &NetworkSecurityGroup{}
_ fi.CompareWithID = &NetworkSecurityGroup{}
_ fi.CloudupTaskNormalize = &NetworkSecurityGroup{}
)
// CompareWithID returns the Name of the Network Security Group
func (nsg *NetworkSecurityGroup) CompareWithID() *string {
return nsg.ID
}
// Find discovers the Network Security Group in the cloud provider
func (nsg *NetworkSecurityGroup) Find(c *fi.CloudupContext) (*NetworkSecurityGroup, error) {
cloud := c.T.Cloud.(azure.AzureCloud)
l, err := cloud.NetworkSecurityGroup().List(context.TODO(), *nsg.ResourceGroup.Name)
if err != nil {
return nil, err
}
var found *network.SecurityGroup
for _, v := range l {
if *v.Name == *nsg.Name {
found = &v
break
}
}
if found == nil {
return nil, nil
}
actual := &NetworkSecurityGroup{
Name: nsg.Name,
Lifecycle: nsg.Lifecycle,
ResourceGroup: &ResourceGroup{
Name: nsg.ResourceGroup.Name,
},
ID: found.ID,
Tags: found.Tags,
}
for _, rule := range *found.SecurityRules {
nsr := &NetworkSecurityRule{
Name: rule.Name,
Priority: rule.Priority,
Access: rule.Access,
Direction: rule.Direction,
Protocol: rule.Protocol,
SourceAddressPrefix: rule.SourceAddressPrefix,
SourceAddressPrefixes: rule.SourceAddressPrefixes,
SourcePortRange: rule.SourcePortRange,
DestinationAddressPrefix: rule.DestinationAddressPrefix,
DestinationAddressPrefixes: rule.DestinationAddressPrefixes,
DestinationPortRange: rule.DestinationPortRange,
}
actual.SecurityRules = append(actual.SecurityRules, nsr)
}
nsg.ID = found.ID
return actual, nil
}
func (nsg *NetworkSecurityGroup) Normalize(c *fi.CloudupContext) error {
c.T.Cloud.(azure.AzureCloud).AddClusterTags(nsg.Tags)
return nil
}
// Run implements fi.Task.Run.
func (nsg *NetworkSecurityGroup) Run(c *fi.CloudupContext) error {
return fi.CloudupDefaultDeltaRunMethod(nsg, c)
}
// CheckChanges returns an error if a change is not allowed.
func (*NetworkSecurityGroup) CheckChanges(a, e, changes *NetworkSecurityGroup) error {
if a == nil {
// Check if required fields are set when a new resource is created.
if e.Name == nil {
return fi.RequiredField("Name")
}
return nil
}
// Check if unchangeable fields won't be changed.
if changes.Name != nil {
return fi.CannotChangeField("Name")
}
return nil
}
// RenderAzure creates or updates a Network Security Group.
func (*NetworkSecurityGroup) RenderAzure(t *azure.AzureAPITarget, a, e, changes *NetworkSecurityGroup) error {
if a == nil {
klog.Infof("Creating a new Network Security Group with name: %s", fi.ValueOf(e.Name))
} else {
klog.Infof("Updating a Network Security Group with name: %s", fi.ValueOf(e.Name))
}
p := network.SecurityGroup{
SecurityGroupPropertiesFormat: &network.SecurityGroupPropertiesFormat{
SecurityRules: &[]network.SecurityRule{},
},
Location: to.StringPtr(t.Cloud.Region()),
Name: to.StringPtr(*e.Name),
Tags: e.Tags,
}
for _, nsr := range e.SecurityRules {
securityRule := network.SecurityRule{
Name: nsr.Name,
SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
Priority: nsr.Priority,
Access: nsr.Access,
Direction: nsr.Direction,
Protocol: nsr.Protocol,
SourceAddressPrefix: nsr.SourceAddressPrefix,
SourceAddressPrefixes: nsr.SourceAddressPrefixes,
SourcePortRange: nsr.SourcePortRange,
DestinationAddressPrefix: nsr.DestinationAddressPrefix,
DestinationAddressPrefixes: nsr.DestinationAddressPrefixes,
DestinationPortRange: nsr.DestinationPortRange,
},
}
*p.SecurityRules = append(*p.SecurityRules, securityRule)
}
nsg, err := t.Cloud.NetworkSecurityGroup().CreateOrUpdate(
context.TODO(),
*e.ResourceGroup.Name,
*e.Name,
p)
if err != nil {
return err
}
e.ID = nsg.ID
return nil
}
// NetworkSecurityRule represents a NetworkSecurityGroup rule.
type NetworkSecurityRule struct {
Name *string
Priority *int32
Access network.SecurityRuleAccess
Direction network.SecurityRuleDirection
Protocol network.SecurityRuleProtocol
SourceAddressPrefix *string
SourceAddressPrefixes *[]string
SourcePortRange *string
DestinationAddressPrefixes *[]string
DestinationAddressPrefix *string
DestinationPortRange *string
}
var _ fi.CloudupHasDependencies = &NetworkSecurityRule{}
func (e *NetworkSecurityRule) GetDependencies(tasks map[string]fi.CloudupTask) []fi.CloudupTask {
return nil
}

View File

@ -0,0 +1,52 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by fitask. DO NOT EDIT.
package azuretasks
import (
"k8s.io/kops/upup/pkg/fi"
)
// NetworkSecurityGroup
var _ fi.HasLifecycle = &NetworkSecurityGroup{}
// GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
func (o *NetworkSecurityGroup) GetLifecycle() fi.Lifecycle {
return o.Lifecycle
}
// SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
func (o *NetworkSecurityGroup) SetLifecycle(lifecycle fi.Lifecycle) {
o.Lifecycle = lifecycle
}
var _ fi.HasName = &NetworkSecurityGroup{}
// GetName returns the Name of the object, implementing fi.HasName
func (o *NetworkSecurityGroup) GetName() *string {
return o.Name
}
// String is the stringer function for the task, producing readable output using fi.TaskAsString
func (o *NetworkSecurityGroup) String() string {
return fi.CloudupTaskAsString(o)
}

View File

@ -33,6 +33,8 @@ type Subnet struct {
ResourceGroup *ResourceGroup ResourceGroup *ResourceGroup
VirtualNetwork *VirtualNetwork VirtualNetwork *VirtualNetwork
NetworkSecurityGroup *NetworkSecurityGroup
CIDR *string CIDR *string
Shared *bool Shared *bool
} }
@ -65,7 +67,7 @@ func (s *Subnet) Find(c *fi.CloudupContext) (*Subnet, error) {
return nil, nil return nil, nil
} }
return &Subnet{ fs := &Subnet{
Name: s.Name, Name: s.Name,
Lifecycle: s.Lifecycle, Lifecycle: s.Lifecycle,
Shared: s.Shared, Shared: s.Shared,
@ -76,7 +78,14 @@ func (s *Subnet) Find(c *fi.CloudupContext) (*Subnet, error) {
Name: s.VirtualNetwork.Name, Name: s.VirtualNetwork.Name,
}, },
CIDR: found.AddressPrefix, CIDR: found.AddressPrefix,
}, nil }
if found.NetworkSecurityGroup != nil {
fs.NetworkSecurityGroup = &NetworkSecurityGroup{
ID: found.NetworkSecurityGroup.ID,
}
}
return fs, nil
} }
// Run implements fi.Task.Run. // Run implements fi.Task.Run.
@ -109,12 +118,17 @@ func (*Subnet) RenderAzure(t *azure.AzureAPITarget, a, e, changes *Subnet) error
klog.Infof("Updating a Subnet with name: %s", fi.ValueOf(e.Name)) klog.Infof("Updating a Subnet with name: %s", fi.ValueOf(e.Name))
} }
// TODO(kenji): Be able to specify security groups.
subnet := network.Subnet{ subnet := network.Subnet{
SubnetPropertiesFormat: &network.SubnetPropertiesFormat{ SubnetPropertiesFormat: &network.SubnetPropertiesFormat{
AddressPrefix: e.CIDR, AddressPrefix: e.CIDR,
}, },
} }
if e.NetworkSecurityGroup != nil {
subnet.NetworkSecurityGroup = &network.SecurityGroup{
ID: e.NetworkSecurityGroup.ID,
}
}
return t.Cloud.Subnet().CreateOrUpdate( return t.Cloud.Subnet().CreateOrUpdate(
context.TODO(), context.TODO(),
*e.ResourceGroup.Name, *e.ResourceGroup.Name,

View File

@ -51,6 +51,7 @@ type MockAzureCloud struct {
VirtualNetworksClient *MockVirtualNetworksClient VirtualNetworksClient *MockVirtualNetworksClient
SubnetsClient *MockSubnetsClient SubnetsClient *MockSubnetsClient
RouteTablesClient *MockRouteTablesClient RouteTablesClient *MockRouteTablesClient
NetworkSecurityGroupsClient *MockNetworkSecurityGroupsClient
VMScaleSetsClient *MockVMScaleSetsClient VMScaleSetsClient *MockVMScaleSetsClient
VMScaleSetVMsClient *MockVMScaleSetVMsClient VMScaleSetVMsClient *MockVMScaleSetVMsClient
DisksClient *MockDisksClient DisksClient *MockDisksClient
@ -78,6 +79,9 @@ func NewMockAzureCloud(location string) *MockAzureCloud {
RouteTablesClient: &MockRouteTablesClient{ RouteTablesClient: &MockRouteTablesClient{
RTs: map[string]network.RouteTable{}, RTs: map[string]network.RouteTable{},
}, },
NetworkSecurityGroupsClient: &MockNetworkSecurityGroupsClient{
NSGs: map[string]network.SecurityGroup{},
},
VMScaleSetsClient: &MockVMScaleSetsClient{ VMScaleSetsClient: &MockVMScaleSetsClient{
VMSSes: map[string]compute.VirtualMachineScaleSet{}, VMSSes: map[string]compute.VirtualMachineScaleSet{},
}, },
@ -195,6 +199,11 @@ func (c *MockAzureCloud) RouteTable() azure.RouteTablesClient {
return c.RouteTablesClient return c.RouteTablesClient
} }
// NetworkSecurityGroup returns the VM Scale Set client.
func (c *MockAzureCloud) NetworkSecurityGroup() azure.NetworkSecurityGroupsClient {
return c.NetworkSecurityGroupsClient
}
// VMScaleSet returns the VM Scale Set client. // VMScaleSet returns the VM Scale Set client.
func (c *MockAzureCloud) VMScaleSet() azure.VMScaleSetsClient { func (c *MockAzureCloud) VMScaleSet() azure.VMScaleSetsClient {
return c.VMScaleSetsClient return c.VMScaleSetsClient
@ -612,3 +621,49 @@ func (c *MockPublicIPAddressesClient) Delete(ctx context.Context, scope, publicI
delete(c.PubIPs, publicIPAddressName) delete(c.PubIPs, publicIPAddressName)
return nil return nil
} }
// MockNetworkSecurityGroupsClient is a mock implementation of Network Security Group client.
type MockNetworkSecurityGroupsClient struct {
NSGs map[string]network.SecurityGroup
}
var _ azure.NetworkSecurityGroupsClient = &MockNetworkSecurityGroupsClient{}
// CreateOrUpdate creates or updates a Network Security Group.
func (c *MockNetworkSecurityGroupsClient) CreateOrUpdate(ctx context.Context, resourceGroupName, asgName string, parameters network.SecurityGroup) (*network.SecurityGroup, error) {
// Ignore resourceGroupName for simplicity.
if _, ok := c.NSGs[asgName]; ok {
return nil, fmt.Errorf("update not supported")
}
parameters.Name = &asgName
c.NSGs[asgName] = parameters
return &parameters, nil
}
// List returns a slice of Network Security Groups.
func (c *MockNetworkSecurityGroupsClient) List(ctx context.Context, resourceGroupName string) ([]network.SecurityGroup, error) {
var l []network.SecurityGroup
for _, nsg := range c.NSGs {
l = append(l, nsg)
}
return l, nil
}
// Get Returns a specified Network Security Group.
func (c *MockNetworkSecurityGroupsClient) Get(ctx context.Context, resourceGroupName string, nsgName string) (*network.SecurityGroup, error) {
asg, ok := c.NSGs[nsgName]
if !ok {
return nil, nil
}
return &asg, nil
}
// Delete deletes a specified Network Security Group.
func (c *MockNetworkSecurityGroupsClient) Delete(ctx context.Context, resourceGroupName, nsgName string) error {
// Ignore resourceGroupName for simplicity.
if _, ok := c.NSGs[nsgName]; !ok {
return fmt.Errorf("%s does not exist", nsgName)
}
delete(c.NSGs, nsgName)
return nil
}