Merge pull request #15221 from infonova/os-set-allowed-addresses

OpenStack: Allow setting allowed address pairs for ports
This commit is contained in:
Kubernetes Prow Robot 2023-03-26 23:35:56 -07:00 committed by GitHub
commit b202130d8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 937 additions and 17 deletions

View File

@ -218,6 +218,33 @@ spec:
insecureSkipVerify: true
```
## Advanced Instance Group config
### Adding allowed address pairs to ports
It is possible to make kOps provision and update the ports of the servers with allowed address pairs, which can be beneficial when needing to use for example VRRP for a custom loadbalancing solution.
To make use of this annotate an Instance Group configuration like so:
```yaml
kind: InstanceGroup
metadata:
annotations:
openstack.kops.io/allowedAddressPair/N: <IPAddress>(,<MACAddress>)
```
Where `N` can be an arbitrary identifier and the MACAddress is optional, for example:
```yaml
kind: InstanceGroup
metadata:
annotations:
openstack.kops.io/allowedAddressPair/0: 192.168.0.0/16
openstack.kops.io/allowedAddressPair/1: 10.123.0.0,12:34:56:78:90:AB
```
For more information about allowed address pairs refer to the [OpenStack Network API documentation](https://docs.openstack.org/api-ref/network/v2/#allowed-address-pairs).
## Next steps
Now that you have a working kOps cluster, read through the [recommendations for production setups guide](production.md) to learn more about how to configure kOps for production workloads.

View File

@ -22,6 +22,7 @@ import (
"sort"
"strings"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
"k8s.io/klog/v2"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/model"
@ -54,6 +55,32 @@ var TRUNCATE_OPT = truncate.TruncateStringOptions{
HashLength: 6,
}
func (b *ServerGroupModelBuilder) buildAllowedAddressPairs(annotations map[string]string) []ports.AddressPair {
keyPrefix := openstack.OS_ANNOTATION + openstack.ALLOWED_ADDRESS_PAIR + "/"
var allowedAddressPairs []ports.AddressPair
for key := range annotations {
if strings.HasPrefix(key, keyPrefix) {
ipAddress, macAddress, _ := strings.Cut(annotations[key], ",")
allowedAddressPair := ports.AddressPair{
IPAddress: ipAddress,
}
if macAddress != "" {
allowedAddressPair.MACAddress = macAddress
}
allowedAddressPairs = append(allowedAddressPairs, allowedAddressPair)
}
}
sort.Slice(allowedAddressPairs, func(i, j int) bool {
return allowedAddressPairs[i].IPAddress < allowedAddressPairs[j].IPAddress
})
return allowedAddressPairs
}
func (b *ServerGroupModelBuilder) buildInstances(c *fi.CloudupModelBuilderContext, sg *openstacktasks.ServerGroup, ig *kops.InstanceGroup) error {
sshKeyNameFull, err := b.SSHKeyName()
if err != nil {
@ -167,6 +194,7 @@ func (b *ServerGroupModelBuilder) buildInstances(c *fi.CloudupModelBuilderContex
SecurityGroups: securityGroups,
AdditionalSecurityGroups: ig.Spec.AdditionalSecurityGroups,
Subnets: subnets,
AllowedAddressPairs: b.buildAllowedAddressPairs(ig.ObjectMeta.Annotations),
Lifecycle: b.Lifecycle,
}
c.AddTask(portTask)

View File

@ -1356,6 +1356,56 @@ func getServerGroupModelBuilderTestInput() []serverGroupModelBuilderTestInput {
},
},
},
{
desc: "configures allowed address pairs with annotations",
cluster: &kops.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
},
Spec: kops.ClusterSpec{
API: kops.APISpec{
PublicName: "master-public-name",
},
CloudProvider: kops.CloudProviderSpec{
Openstack: &kops.OpenstackSpec{
Metadata: &kops.OpenstackMetadata{
ConfigDrive: fi.PtrTo(false),
},
},
},
KubernetesVersion: "1.24.0",
Networking: kops.NetworkingSpec{
Subnets: []kops.ClusterSubnetSpec{
{
Name: "subnet",
Type: kops.SubnetTypePublic,
Region: "region",
},
},
},
},
},
instanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{
Name: "node",
Annotations: map[string]string{
"openstack.kops.io/allowedAddressPair/0": "192.168.0.0/16",
"openstack.kops.io/allowedAddressPair/1": "10.123.0.1,12:34:56:78:90:AB",
},
},
Spec: kops.InstanceGroupSpec{
Role: kops.InstanceGroupRoleNode,
Image: "image-node",
MinSize: i32(1),
MaxSize: i32(1),
MachineType: "blc.2-4",
Subnets: []string{"subnet"},
Zones: []string{"zone-1"},
},
},
},
},
}
}

View File

@ -26,6 +26,7 @@ Name: node-1-cluster
Port:
AdditionalSecurityGroups:
- additional-sg
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -193,6 +194,7 @@ PublicACL: null
---
AdditionalSecurityGroups:
- additional-sg
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -26,6 +26,7 @@ Metadata:
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -191,6 +192,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -26,6 +26,7 @@ Metadata:
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -191,6 +192,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -0,0 +1,239 @@
Lifecycle: ""
Name: node
---
AvailabilityZone: zone-1
ConfigDrive: false
Flavor: blc.2-4
FloatingIP: null
ForAPIServer: false
GroupName: node
ID: null
Image: image-node
Lifecycle: Sync
Metadata:
KopsInstanceGroup: node
KopsName: node-1-cluster
KopsNetwork: cluster
KopsRole: Node
KubernetesCluster: cluster
cluster_generation: "0"
ig_generation: "0"
k8s: cluster
k8s.io_cluster-autoscaler_node-template_label_node-role.kubernetes.io_node: ""
k8s.io_role_node: "1"
kops.k8s.io_instancegroup: node
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs:
- ip_address: 10.123.0.1
mac_address: 12:34:56:78:90:AB
- ip_address: 192.168.0.0/16
ForAPIServer: false
ID: null
InstanceGroupName: node
Lifecycle: Sync
Name: port-node-1-cluster
Network:
AvailabilityZoneHints: null
ID: null
Lifecycle: ""
Name: cluster
Tag: null
SecurityGroups:
- Description: null
ID: null
Lifecycle: ""
Name: nodes.cluster
RemoveExtraRules: null
RemoveGroup: false
Subnets:
- CIDR: null
DNSServers: null
ID: null
Lifecycle: ""
Name: subnet.cluster
Network: null
Tag: null
Tags:
- KopsInstanceGroup=node
- KopsName=port-node-1
- KubernetesCluster=cluster
Region: region
Role: Node
SSHKey: kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1
SecurityGroups: null
ServerGroup:
ClusterName: cluster
ID: null
IGName: node
Lifecycle: Sync
MaxSize: 1
Name: cluster-node
Policies:
- anti-affinity
UserData:
task:
Lifecycle: ""
Name: node
---
Lifecycle: ""
Name: apiserver-aggregator-ca
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=apiserver-aggregator-ca
type: ca
---
Lifecycle: ""
Name: etcd-clients-ca
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=etcd-clients-ca
type: ca
---
Lifecycle: ""
Name: etcd-manager-ca-events
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=etcd-manager-ca-events
type: ca
---
Lifecycle: ""
Name: etcd-manager-ca-main
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=etcd-manager-ca-main
type: ca
---
Lifecycle: ""
Name: etcd-peers-ca-events
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=etcd-peers-ca-events
type: ca
---
Lifecycle: ""
Name: etcd-peers-ca-main
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=etcd-peers-ca-main
type: ca
---
Lifecycle: ""
Name: kube-proxy
Signer:
Lifecycle: ""
Name: kubernetes-ca
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=kubernetes
type: ca
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=kube-proxy
type: client
---
Lifecycle: ""
Name: kubelet
Signer:
Lifecycle: ""
Name: kubernetes-ca
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=kubernetes
type: ca
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=kubelet
type: client
---
Lifecycle: ""
Name: kubernetes-ca
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=kubernetes
type: ca
---
Lifecycle: ""
Name: service-account
Signer: null
alternateNames: null
issuer: ""
oldFormat: false
subject: cn=service-account
type: ca
---
Base: null
Contents:
task:
Lifecycle: ""
Name: node
Lifecycle: ""
Location: igconfig/node/node/nodeupconfig.yaml
Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs:
- ip_address: 10.123.0.1
mac_address: 12:34:56:78:90:AB
- ip_address: 192.168.0.0/16
ForAPIServer: false
ID: null
InstanceGroupName: node
Lifecycle: Sync
Name: port-node-1-cluster
Network:
AvailabilityZoneHints: null
ID: null
Lifecycle: ""
Name: cluster
Tag: null
SecurityGroups:
- Description: null
ID: null
Lifecycle: ""
Name: nodes.cluster
RemoveExtraRules: null
RemoveGroup: false
Subnets:
- CIDR: null
DNSServers: null
ID: null
Lifecycle: ""
Name: subnet.cluster
Network: null
Tag: null
Tags:
- KopsInstanceGroup=node
- KopsName=port-node-1
- KubernetesCluster=cluster
---
ClusterName: cluster
ID: null
IGName: node
Lifecycle: Sync
MaxSize: 1
Name: cluster-node
Policies:
- anti-affinity

View File

@ -25,6 +25,7 @@ Metadata:
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -190,6 +191,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -79,6 +79,7 @@ Metadata:
Name: master-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -166,6 +167,7 @@ Metadata:
Name: master-2-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -253,6 +255,7 @@ Metadata:
Name: master-3-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -337,6 +340,7 @@ Metadata:
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -415,6 +419,7 @@ Metadata:
Name: node-2-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -493,6 +498,7 @@ Metadata:
Name: node-3-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -668,6 +674,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -706,6 +713,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -744,6 +752,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -782,6 +791,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -814,6 +824,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -846,6 +857,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -64,6 +64,7 @@ Metadata:
Name: master-a-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: true
ID: null
InstanceGroupName: master-a
@ -139,6 +140,7 @@ Metadata:
Name: master-b-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: true
ID: null
InstanceGroupName: master-b
@ -214,6 +216,7 @@ Metadata:
Name: master-c-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: true
ID: null
InstanceGroupName: master-c
@ -286,6 +289,7 @@ Metadata:
Name: node-a-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-a
@ -358,6 +362,7 @@ Metadata:
Name: node-b-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-b
@ -430,6 +435,7 @@ Metadata:
Name: node-c-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-c
@ -832,6 +838,7 @@ Pool:
Name: api.cluster-https
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: true
ID: null
InstanceGroupName: master-a
@ -864,6 +871,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: true
ID: null
InstanceGroupName: master-b
@ -896,6 +904,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: true
ID: null
InstanceGroupName: master-c
@ -928,6 +937,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-a
@ -960,6 +970,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-b
@ -992,6 +1003,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-c

View File

@ -64,6 +64,7 @@ Metadata:
Name: master-a-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-a
@ -139,6 +140,7 @@ Metadata:
Name: master-b-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-b
@ -214,6 +216,7 @@ Metadata:
Name: master-c-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-c
@ -286,6 +289,7 @@ Metadata:
Name: node-a-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-a
@ -358,6 +362,7 @@ Metadata:
Name: node-b-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-b
@ -430,6 +435,7 @@ Metadata:
Name: node-c-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-c
@ -832,6 +838,7 @@ Pool:
Name: master-public-name-https
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-a
@ -864,6 +871,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-b
@ -896,6 +904,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-c
@ -928,6 +937,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-a
@ -960,6 +970,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-b
@ -992,6 +1003,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-c

View File

@ -91,6 +91,7 @@ Metadata:
Name: master-a-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-a
@ -178,6 +179,7 @@ Metadata:
Name: master-b-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-b
@ -265,6 +267,7 @@ Metadata:
Name: master-c-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-c
@ -349,6 +352,7 @@ Metadata:
Name: node-a-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-a
@ -427,6 +431,7 @@ Metadata:
Name: node-b-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-b
@ -505,6 +510,7 @@ Metadata:
Name: node-c-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-c
@ -720,6 +726,7 @@ Name: nodeupconfig-node-c
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-a
@ -758,6 +765,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-b
@ -796,6 +804,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-c
@ -834,6 +843,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-a
@ -866,6 +876,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-b
@ -898,6 +909,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-c

View File

@ -43,6 +43,7 @@ Metadata:
Name: master-a-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-a
@ -124,6 +125,7 @@ Metadata:
Name: master-b-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-b
@ -205,6 +207,7 @@ Metadata:
Name: master-c-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-c
@ -283,6 +286,7 @@ Metadata:
Name: node-a-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-a
@ -355,6 +359,7 @@ Metadata:
Name: node-b-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-b
@ -427,6 +432,7 @@ Metadata:
Name: node-c-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-c
@ -642,6 +648,7 @@ Name: nodeupconfig-node-c
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-a
@ -680,6 +687,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-b
@ -718,6 +726,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master-c
@ -756,6 +765,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-a
@ -788,6 +798,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-b
@ -820,6 +831,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node-c

View File

@ -30,6 +30,7 @@ Metadata:
Name: bastion-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: bastion
@ -105,6 +106,7 @@ Metadata:
Name: master-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -183,6 +185,7 @@ Metadata:
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -368,6 +371,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: bastion
@ -400,6 +404,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -438,6 +443,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -43,6 +43,7 @@ Metadata:
Name: bastion-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: bastion
@ -118,6 +119,7 @@ Metadata:
Name: master-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -196,6 +198,7 @@ Metadata:
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -381,6 +384,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: bastion
@ -413,6 +417,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -451,6 +456,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -31,6 +31,7 @@ Metadata:
Name: master-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -109,6 +110,7 @@ Metadata:
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -284,6 +286,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -322,6 +325,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -51,6 +51,7 @@ Metadata:
Name: master-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -135,6 +136,7 @@ Metadata:
Name: node-1-cluster
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -310,6 +312,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -348,6 +351,7 @@ Tags:
- KubernetesCluster=cluster
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -51,6 +51,7 @@ Metadata:
Name: master-1-tom-software-dev-playground-real33-k8s-local
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -135,6 +136,7 @@ Metadata:
Name: node-1-tom-software-dev-playground-real33-k8s-local
Port:
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -310,6 +312,7 @@ Name: nodeupconfig-node
PublicACL: null
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: master
@ -348,6 +351,7 @@ Tags:
- KubernetesCluster=tom-software-dev-playground-real33--kngu8l
---
AdditionalSecurityGroups: null
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -26,6 +26,7 @@ Name: node-1-cluster
Port:
AdditionalSecurityGroups:
- additional-sg
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -193,6 +194,7 @@ PublicACL: null
---
AdditionalSecurityGroups:
- additional-sg
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -26,6 +26,7 @@ Name: node-1-cluster
Port:
AdditionalSecurityGroups:
- additional-sg
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node
@ -193,6 +194,7 @@ PublicACL: null
---
AdditionalSecurityGroups:
- additional-sg
AllowedAddressPairs: null
ForAPIServer: false
ID: null
InstanceGroupName: node

View File

@ -44,6 +44,7 @@ const (
BOOT_FROM_VOLUME = "osVolumeBoot"
BOOT_VOLUME_SIZE = "osVolumeSize"
SERVER_GROUP_AFFINITY = "serverGroupAffinity"
ALLOWED_ADDRESS_PAIR = "allowedAddressPair"
defaultActiveTimeout = time.Second * 120
activeStatus = "ACTIVE"

View File

@ -40,6 +40,7 @@ type Port struct {
Lifecycle fi.Lifecycle
Tags []string
ForAPIServer bool
AllowedAddressPairs []ports.AddressPair
}
// GetDependencies returns the dependencies of the Port task
@ -85,6 +86,29 @@ func (s *Port) IsForAPIServer() bool {
return s.ForAPIServer
}
// getActualAllowedAddressPairs returns the actual allowed address pairs which kOps currently manages.
func getActualAllowedAddressPairs(port *ports.Port, find *Port) []ports.AddressPair {
if find == nil {
return port.AllowedAddressPairs
}
var allowedAddressPairs []ports.AddressPair
for _, portAddressPair := range port.AllowedAddressPairs {
// TODO: what if user set the macaddress in the config to the same one as the port?
if portAddressPair.MACAddress == port.MACAddress {
portAddressPair.MACAddress = ""
}
allowedAddressPairs = append(allowedAddressPairs, portAddressPair)
}
sort.Slice(allowedAddressPairs, func(i, j int) bool {
return allowedAddressPairs[i].IPAddress < allowedAddressPairs[j].IPAddress
})
return allowedAddressPairs
}
func newPortTaskFromCloud(cloud openstack.OpenstackCloud, lifecycle fi.Lifecycle, port *ports.Port, find *Port) (*Port, error) {
additionalSecurityGroupIDs := map[string]struct{}{}
if find != nil {
@ -150,14 +174,15 @@ func newPortTaskFromCloud(cloud openstack.OpenstackCloud, lifecycle fi.Lifecycle
}
actual := &Port{
ID: fi.PtrTo(port.ID),
InstanceGroupName: cloudInstanceGroupName,
Name: fi.PtrTo(port.Name),
Network: &Network{ID: fi.PtrTo(port.NetworkID)},
SecurityGroups: sgs,
Subnets: subnets,
Lifecycle: lifecycle,
Tags: tags,
ID: fi.PtrTo(port.ID),
InstanceGroupName: cloudInstanceGroupName,
Name: fi.PtrTo(port.Name),
Network: &Network{ID: fi.PtrTo(port.NetworkID)},
SecurityGroups: sgs,
Subnets: subnets,
Lifecycle: lifecycle,
Tags: tags,
AllowedAddressPairs: getActualAllowedAddressPairs(port, find),
}
if find != nil {
find.ID = actual.ID
@ -238,12 +263,23 @@ func (*Port) RenderOpenstack(t *openstack.OpenstackAPITarget, a, e, changes *Por
klog.V(2).Infof("Creating a new Openstack port, id=%s", v.ID)
return nil
}
if changes != nil && changes.Tags != nil {
klog.V(2).Infof("Updating tags for Port with name: %q", fi.ValueOf(e.Name))
for _, tag := range e.Tags {
err := t.Cloud.AppendTag(openstack.ResourceTypePort, fi.ValueOf(a.ID), tag)
if changes != nil {
if changes.Tags != nil {
klog.V(2).Infof("Updating tags for Port with name: %q", fi.ValueOf(e.Name))
for _, tag := range e.Tags {
err := t.Cloud.AppendTag(openstack.ResourceTypePort, fi.ValueOf(a.ID), tag)
if err != nil {
return fmt.Errorf("Error appending tag to port: %v", err)
}
}
}
if changes.AllowedAddressPairs != nil {
klog.V(2).Infof("Updating allowed address pairs for Port with name: %q", fi.ValueOf(e.Name))
_, err := t.Cloud.UpdatePort(fi.ValueOf(a.ID), ports.UpdateOpts{
AllowedAddressPairs: &e.AllowedAddressPairs,
})
if err != nil {
return fmt.Errorf("Error appending tag to port: %v", err)
return fmt.Errorf("error updating port: %v", err)
}
}
}
@ -278,9 +314,10 @@ func portCreateOptsFromPortTask(t *openstack.OpenstackAPITarget, a, e, changes *
}
return ports.CreateOpts{
Name: fi.ValueOf(e.Name),
NetworkID: fi.ValueOf(e.Network.ID),
SecurityGroups: &sgs,
FixedIPs: fixedIPs,
Name: fi.ValueOf(e.Name),
NetworkID: fi.ValueOf(e.Network.ID),
SecurityGroups: &sgs,
FixedIPs: fixedIPs,
AllowedAddressPairs: e.AllowedAddressPairs,
}, nil
}

View File

@ -30,6 +30,104 @@ import (
"k8s.io/kops/upup/pkg/fi/cloudup/openstack"
)
func Test_Port_GetActualAllowedAddressPairs_ReturnsPortAddressPairsWhenFindIsNil(t *testing.T) {
expected := []ports.AddressPair{
{
IPAddress: "10.123.0.0/16",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
}
port := ports.Port{
AllowedAddressPairs: expected,
}
actual := getActualAllowedAddressPairs(fi.PtrTo(port), nil)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Allowed address pairs differ:\n%v\n\tinstead of\n%v", actual, expected)
}
}
func Test_Port_GetAllowedAddressPairs_ReturnsModifiedPortAddressPairsWhenNoChanges(t *testing.T) {
expected := []ports.AddressPair{
{
IPAddress: "10.123.0.0/16",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
}
port := ports.Port{
MACAddress: "CA:FE:BA:BE:BE:EF",
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
MACAddress: "CA:FE:BA:BE:BE:EF",
},
{
IPAddress: "10.123.0.0/16",
MACAddress: "12:34:56:78:90:AB",
},
},
}
find := Port{
AllowedAddressPairs: expected,
}
actual := getActualAllowedAddressPairs(fi.PtrTo(port), fi.PtrTo(find))
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Allowed address pairs differ:\n%v\n\tinstead of\n%v", actual, expected)
}
}
func Test_Port_GetActualAllowedAddressPairs_ReturnsModifiedPortAddressPairsOnChanges(t *testing.T) {
expected := []ports.AddressPair{
{
IPAddress: "10.123.0.0/16",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
}
port := ports.Port{
MACAddress: "CA:FE:BA:BE:BE:EF",
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
MACAddress: "CA:FE:BA:BE:BE:EF",
},
{
IPAddress: "10.123.0.0/16",
MACAddress: "12:34:56:78:90:AB",
},
},
}
find := Port{
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
},
}
actual := getActualAllowedAddressPairs(fi.PtrTo(port), fi.PtrTo(find))
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Allowed address pairs differ:\n%v\n\tinstead of\n%v", actual, expected)
}
}
func Test_Port_GetDependencies(t *testing.T) {
tasks := map[string]fi.CloudupTask{
"foo": &SecurityGroup{Name: fi.PtrTo("security-group")},
@ -158,6 +256,15 @@ func Test_NewPortTaskFromCloud(t *testing.T) {
Tags: []string{
"cluster",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
foundPort: nil,
modifiedFoundPort: nil,
@ -177,6 +284,15 @@ func Test_NewPortTaskFromCloud(t *testing.T) {
Tags: []string{
"cluster",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
expectedError: nil,
},
@ -199,12 +315,30 @@ func Test_NewPortTaskFromCloud(t *testing.T) {
Tags: []string{
"KopsInstanceGroup=node-ig",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
foundPort: &Port{
InstanceGroupName: fi.PtrTo("node-ig"),
Tags: []string{
"KopsInstanceGroup=node-ig",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
},
},
modifiedFoundPort: &Port{
ID: fi.PtrTo("id"),
@ -212,6 +346,15 @@ func Test_NewPortTaskFromCloud(t *testing.T) {
Tags: []string{
"KopsInstanceGroup=node-ig",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
},
},
expectedPortTask: &Port{
ID: fi.PtrTo("id"),
@ -230,6 +373,15 @@ func Test_NewPortTaskFromCloud(t *testing.T) {
Tags: []string{
"KopsInstanceGroup=node-ig",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
},
},
expectedError: nil,
},
@ -253,6 +405,15 @@ func Test_NewPortTaskFromCloud(t *testing.T) {
"cluster",
"KopsInstanceGroup=node-ig",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
foundPort: nil,
modifiedFoundPort: nil,
@ -274,6 +435,15 @@ func Test_NewPortTaskFromCloud(t *testing.T) {
"cluster",
"KopsInstanceGroup=node-ig",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
expectedError: nil,
},
@ -338,6 +508,83 @@ func Test_NewPortTaskFromCloud(t *testing.T) {
},
expectedError: nil,
},
{
desc: "cloud port found port not nil honors allowed address pairs",
lifecycle: fi.LifecycleSync,
cloud: &portCloud{},
cloudPort: &ports.Port{
ID: "id",
Name: "name",
NetworkID: "networkID",
FixedIPs: []ports.IP{
{SubnetID: "subnet-a"},
},
SecurityGroups: []string{
"sg-1",
},
MACAddress: "CA:FE:BA:BE:BE:EF",
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.0.0.1",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "172.16.0.2",
},
},
},
foundPort: &Port{
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "10.0.0.1",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
},
},
modifiedFoundPort: &Port{
ID: fi.PtrTo("id"),
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "10.0.0.1",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
},
},
expectedPortTask: &Port{
ID: fi.PtrTo("id"),
Name: fi.PtrTo("name"),
Network: &Network{ID: fi.PtrTo("networkID")},
SecurityGroups: []*SecurityGroup{
{ID: fi.PtrTo("sg-1"), Lifecycle: fi.LifecycleSync},
},
Subnets: []*Subnet{
{ID: fi.PtrTo("subnet-a"), Lifecycle: fi.LifecycleSync},
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "10.0.0.1",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "172.16.0.2",
},
{
IPAddress: "192.168.0.0/16",
},
},
Lifecycle: fi.LifecycleSync,
},
expectedError: nil,
},
}
for _, testCase := range tests {
@ -543,6 +790,84 @@ func Test_Port_Find(t *testing.T) {
expectedPortTask: nil,
expectedError: fmt.Errorf("list error"),
},
{
desc: "port found with allowed address pairs",
context: &fi.CloudupContext{
T: fi.CloudupSubContext{
Cloud: &portCloud{
listPorts: []ports.Port{
{
ID: "id",
Name: "name",
NetworkID: "networkID",
FixedIPs: []ports.IP{
{SubnetID: "subnet-a"},
{SubnetID: "subnet-b"},
},
SecurityGroups: []string{
"sg-1",
"sg-2",
},
Tags: []string{"clusterName"},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
},
},
Cluster: &kops.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "clusterName",
},
},
},
},
port: &Port{
Name: fi.PtrTo("name"),
Lifecycle: fi.LifecycleSync,
Tags: []string{"clusterName"},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
expectedPortTask: &Port{
ID: fi.PtrTo("id"),
Name: fi.PtrTo("name"),
Network: &Network{ID: fi.PtrTo("networkID")},
SecurityGroups: []*SecurityGroup{
{ID: fi.PtrTo("sg-1"), Lifecycle: fi.LifecycleSync},
{ID: fi.PtrTo("sg-2"), Lifecycle: fi.LifecycleSync},
},
Subnets: []*Subnet{
{ID: fi.PtrTo("subnet-a"), Lifecycle: fi.LifecycleSync},
{ID: fi.PtrTo("subnet-b"), Lifecycle: fi.LifecycleSync},
},
Lifecycle: fi.LifecycleSync,
Tags: []string{"clusterName"},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
{
IPAddress: "192.168.0.0/16",
},
},
},
expectedError: nil,
},
}
for _, testCase := range tests {
@ -782,6 +1107,99 @@ func Test_Port_RenderOpenstack(t *testing.T) {
expectedCloudPort: nil,
expectedError: fmt.Errorf("Error creating port: port create error"),
},
{
desc: "changes in allowed address pairs success",
target: &openstack.OpenstackAPITarget{
Cloud: &portCloud{
updatePort: &ports.Port{
ID: "cloud-id",
Name: "name",
NetworkID: "networkID",
FixedIPs: []ports.IP{
{SubnetID: "subnet-a"},
},
SecurityGroups: []string{
"sg-1",
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
},
},
actual: &Port{
ID: fi.PtrTo("cloud-id"),
Name: fi.PtrTo("name"),
Network: &Network{ID: fi.PtrTo("networkID")},
SecurityGroups: []*SecurityGroup{
{ID: fi.PtrTo("sg-1")},
},
Subnets: []*Subnet{
{ID: fi.PtrTo("subnet-a")},
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
},
},
expected: &Port{
ID: fi.PtrTo("expected-id"),
Name: fi.PtrTo("name"),
Network: &Network{ID: fi.PtrTo("networkID")},
SecurityGroups: []*SecurityGroup{
{ID: fi.PtrTo("sg-1")},
},
Subnets: []*Subnet{
{ID: fi.PtrTo("subnet-a")},
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
changes: &Port{
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
expectedAfter: &Port{
ID: fi.PtrTo("cloud-id"),
Name: fi.PtrTo("name"),
Network: &Network{ID: fi.PtrTo("networkID")},
SecurityGroups: []*SecurityGroup{
{ID: fi.PtrTo("sg-1")},
},
Subnets: []*Subnet{
{ID: fi.PtrTo("subnet-a")},
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
expectedCloudPort: nil,
expectedError: nil,
},
}
for _, testCase := range tests {
@ -838,6 +1256,15 @@ func Test_Port_createOptsFromPortTask(t *testing.T) {
{ID: fi.PtrTo("subnet-a")},
{ID: fi.PtrTo("subnet-b")},
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
expectedCreateOpts: ports.CreateOpts{
Name: "name",
@ -852,6 +1279,15 @@ func Test_Port_createOptsFromPortTask(t *testing.T) {
{SubnetID: "subnet-a"},
{SubnetID: "subnet-b"},
},
AllowedAddressPairs: []ports.AddressPair{
{
IPAddress: "192.168.0.0/16",
},
{
IPAddress: "10.123.0.1",
MACAddress: "12:34:56:78:90:AB",
},
},
},
},
{
@ -904,6 +1340,8 @@ type portCloud struct {
listPortsError error
createPort *ports.Port
createPortError error
updatePort *ports.Port
updatePortError error
listSecurityGroups map[string][]sg.SecGroup
listSecurityGroupsError error
}
@ -920,6 +1358,10 @@ func (p *portCloud) ListSecurityGroups(opt sg.ListOpts) ([]sg.SecGroup, error) {
return p.listSecurityGroups[opt.Name], p.listSecurityGroupsError
}
func (p *portCloud) UpdatePort(id string, opt ports.UpdateOptsBuilder) (*ports.Port, error) {
return p.updatePort, p.updatePortError
}
type sortedTasks []fi.CloudupTask
func (s sortedTasks) Len() int { return len(s) }