diff --git a/pkg/apis/openstackproviderconfig/v1alpha1/types.go b/pkg/apis/openstackproviderconfig/v1alpha1/types.go index 6091075e6d..aab270bbe0 100644 --- a/pkg/apis/openstackproviderconfig/v1alpha1/types.go +++ b/pkg/apis/openstackproviderconfig/v1alpha1/types.go @@ -132,6 +132,8 @@ type NetworkParam struct { Subnets []SubnetParam `json:"subnets,omitempty"` // NoAllowedAddressPairs disables creation of allowed address pairs for the network ports NoAllowedAddressPairs bool `json:"noAllowedAddressPairs,omitempty"` + // PortTags allows users to specify a list of tags to add to ports created in a given network + PortTags []string `json:"portTags,omitempty"` } type Filter struct { @@ -159,6 +161,9 @@ type SubnetParam struct { // Filters for optional network query Filter SubnetFilter `json:"filter,omitempty"` + + // PortTags are tags that are added to ports created on this subnet + PortTags []string `json:"portTags,omitempty"` } type SubnetFilter struct { diff --git a/pkg/cloud/openstack/clients/machineservice.go b/pkg/cloud/openstack/clients/machineservice.go index 07316242f0..dca7cabdf6 100644 --- a/pkg/cloud/openstack/clients/machineservice.go +++ b/pkg/cloud/openstack/clients/machineservice.go @@ -96,6 +96,7 @@ type Instance struct { type ServerNetwork struct { networkID string subnetID string + portTags []string } type InstanceListOpts struct { // Name of the image in URL format. @@ -421,21 +422,25 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust if net.Subnets == nil { nets = append(nets, ServerNetwork{ networkID: netID, + portTags: net.PortTags, }) } - for _, snet := range net.Subnets { - sopts := subnets.ListOpts(snet.Filter) - sopts.ID = snet.UUID + for _, snetParam := range net.Subnets { + sopts := subnets.ListOpts(snetParam.Filter) + sopts.ID = snetParam.UUID sopts.NetworkID = netID - snets, err := getSubnetsByFilter(is, &sopts) + + // Query for all subnets that match filters + snetResults, err := getSubnetsByFilter(is, &sopts) if err != nil { return nil, err } - for _, snet := range snets { + for _, snet := range snetResults { nets = append(nets, ServerNetwork{ networkID: snet.NetworkID, subnetID: snet.ID, + portTags: append(net.PortTags, snetParam.PortTags...), }) } } @@ -498,8 +503,9 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust port = portList[0] } + portTags := deduplicateList(append(machineTags, port.Tags...)) _, err = attributestags.ReplaceAll(is.networkClient, "ports", port.ID, attributestags.ReplaceAllOpts{ - Tags: machineTags}).Extract() + Tags: portTags}).Extract() if err != nil { return nil, fmt.Errorf("Tagging port for server err: %v", err) } @@ -732,6 +738,24 @@ func createServerGroup(computeClient *gophercloud.ServiceClient, name string) (* }).Extract() } +// deduplicateList removes all duplicate entries from a slice of strings in place +func deduplicateList(list []string) []string { + m := map[string]bool{} + for _, element := range list { + if _, ok := m[element]; !ok { + m[element] = true + } + } + + dedupedList := make([]string, len(m)) + i := 0 + for k := range m { + dedupedList[i] = k + i++ + } + return dedupedList +} + func getServerGroupsByName(computeClient *gophercloud.ServiceClient, name string) ([]servergroups.ServerGroup, error) { pages, err := servergroups.List(computeClient).AllPages() if err != nil { diff --git a/pkg/cloud/openstack/clients/machineservice_test.go b/pkg/cloud/openstack/clients/machineservice_test.go index 757eadb83f..31d15f341c 100644 --- a/pkg/cloud/openstack/clients/machineservice_test.go +++ b/pkg/cloud/openstack/clients/machineservice_test.go @@ -27,3 +27,37 @@ func TestMachineServiceInstance(t *testing.T) { t.Errorf("Couldn't create instance service: %v", err) } } + +func TestDeduplicateLists(t *testing.T) { + list1 := []string{"1", "2", "3", "a", "b", "c"} + list2 := []string{"1", "c"} + + // Case 1: Lists with no duplicates has same elements + result := deduplicateList(list1) + if !equal(result, list1) { + t.Errorf("List with no duplicates should contain the same elements. \n\tExpected:%v\n\tGot:%v", list1, result) + } + + // Case 2: Lists with duplicates have coppies of elements removed + dupe1 := append(list1, list2...) + result = deduplicateList(dupe1) + if !equal(list1, result) { + t.Errorf("List with duplicates should have coppies of elements removed.\n\tExpected:%v\n\tGot:%v", list1, result) + } +} + +func equal(a, b []string) bool { + if len(a) != len(b) { + return false + } + m := map[string]bool{} + for _, v := range a { + m[v] = true + } + for _, v := range b { + if _, ok := m[v]; !ok { + return false + } + } + return true +}