diff --git a/Dockerfile b/Dockerfile index a390c23db4..d376f04d03 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,6 @@ COPY . . RUN go build -o ./machine-controller-manager ./cmd/manager -FROM registry.ci.openshift.org/openshift/origin-v4.7:base +FROM registry.ci.openshift.org/origin/4.8:base COPY --from=builder /go/src/sigs.k8s.io/cluster-api-provider-openstack/machine-controller-manager / diff --git a/pkg/apis/openstackproviderconfig/v1alpha1/types.go b/pkg/apis/openstackproviderconfig/v1alpha1/types.go index faa96ec31b..6832d05376 100644 --- a/pkg/apis/openstackproviderconfig/v1alpha1/types.go +++ b/pkg/apis/openstackproviderconfig/v1alpha1/types.go @@ -134,7 +134,18 @@ type NetworkParam struct { 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"` - VNICType string `json:"vnicType,omitempty"` + // VNICType specifies the nic type of the ports created on this network + // Default: nova default + // +optional + VNICType string `json:"vnicType,omitempty"` + // PortCount is a positive, non-zero, integer representing the number of ports in this network to attach to each node + // Default: 1 + // +optional + PortCount uint `json:"portCount,omitempty"` + // PortSecurity is a boolean value that indicates whether security is enabled on ports created for this subnet + // Default: Nova default + // +optional + PortSecurity *bool `json:"portSecurity,omitempty"` } type Filter struct { @@ -165,6 +176,16 @@ type SubnetParam struct { // PortTags are tags that are added to ports created on this subnet PortTags []string `json:"portTags,omitempty"` + + // PortCount is a positive, non-zero, intiger representing the number of ports in this subnet to attach to each node + // Default: 1 + // +optional + PortCount uint `json:"portCount,omitempty"` + + // PortSecurity is a boolean value that indicates whether security is enabled on ports created for this subnet + // Default: Nova default + // +optional + PortSecurity *bool `json:"portSecurity,omitempty"` } type SubnetFilter struct { diff --git a/pkg/cloud/openstack/clients/machineservice.go b/pkg/cloud/openstack/clients/machineservice.go index 47e8332146..237ea654ef 100644 --- a/pkg/cloud/openstack/clients/machineservice.go +++ b/pkg/cloud/openstack/clients/machineservice.go @@ -43,6 +43,7 @@ import ( netext "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/attributestags" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/trunks" "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" @@ -95,11 +96,26 @@ type Instance struct { } type ServerNetwork struct { - networkID string - subnetID string - portTags []string - vnicType string + networkID string + subnetID string + portTags []string + vnicType string + portSecurity *bool + portName string } + +// for geting vnic type when listing ports +type portWithPortsbinding struct { + ports.Port + portsbinding.PortsBindingExt +} + +// for updating port security +var portWithPortSecurityExtensions struct { + ports.Port + portsecurity.PortSecurityExt +} + type InstanceListOpts struct { // Name of the image in URL format. Image string `q:"image"` @@ -421,16 +437,28 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust if err != nil { return nil, err } + + // Set default number of ports created per network to 1 + portCount := 1 + if net.PortCount > 1 { + portCount = int(net.PortCount) + } + for _, netID := range ids { if net.NoAllowedAddressPairs { netsWithoutAllowedAddressPairs[netID] = struct{}{} } if net.Subnets == nil { - nets = append(nets, ServerNetwork{ - networkID: netID, - portTags: net.PortTags, - vnicType: net.VNICType, - }) + // Create one NIC per count + for i := 0; i < portCount; i++ { + nets = append(nets, ServerNetwork{ + networkID: netID, + portTags: net.PortTags, + vnicType: net.VNICType, + portSecurity: net.PortSecurity, + portName: fmt.Sprintf("%s-%d", name, i), + }) + } } for _, snetParam := range net.Subnets { @@ -438,18 +466,32 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust sopts.ID = snetParam.UUID sopts.NetworkID = netID + // inherit port security settings from network if not set on subnet + portSecurity := net.PortSecurity + if snetParam.PortSecurity != nil { + portSecurity = snetParam.PortSecurity + } + + if snetParam.PortCount > 0 { + portCount = int(snetParam.PortCount) + } + // Query for all subnets that match filters snetResults, err := getSubnetsByFilter(is, &sopts) if err != nil { return nil, err } for _, snet := range snetResults { - nets = append(nets, ServerNetwork{ - networkID: snet.NetworkID, - subnetID: snet.ID, - portTags: append(net.PortTags, snetParam.PortTags...), - vnicType: net.VNICType, - }) + for i := 0; i < portCount; i++ { + nets = append(nets, ServerNetwork{ + networkID: snet.NetworkID, + subnetID: snet.ID, + portTags: append(net.PortTags, snetParam.PortTags...), + vnicType: net.VNICType, + portSecurity: portSecurity, + portName: fmt.Sprintf("%s-%d", name, i), + }) + } } } } @@ -478,40 +520,41 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust } } + // Convert nets list into a list of servers.Network to be passed as NICs for instance create userData := base64.StdEncoding.EncodeToString([]byte(cmd)) var ports_list []servers.Network for _, net := range nets { if net.networkID == "" { return nil, fmt.Errorf("No network was found or provided. Please check your machine configuration and try again") } - allPages, err := ports.List(is.networkClient, ports.ListOpts{ - Name: name, - NetworkID: net.networkID, - }).AllPages() - if err != nil { - return nil, fmt.Errorf("Searching for existing port for server err: %v", err) + var port ports.Port + secGroups := &securityGroups + addrPairs := &allowedAddressPairs + if net.portSecurity != nil && *net.portSecurity == false { + secGroups = &[]string{} + addrPairs = &[]ports.AddressPair{} } - portList, err := ports.ExtractPorts(allPages) + if _, ok := netsWithoutAllowedAddressPairs[net.networkID]; ok { + addrPairs = &[]ports.AddressPair{} + } + + port, err = CreatePort(is, net.portName, net, secGroups, addrPairs) if err != nil { - return nil, fmt.Errorf("Searching for existing port for server err: %v", err) + return nil, fmt.Errorf("Failed to create port err: %v", err) } - var port ports.Port - if len(portList) == 0 { - // create server port - if _, ok := netsWithoutAllowedAddressPairs[net.networkID]; ok { - // create ports without address pairs - port, err = CreatePort(is, name, net, &securityGroups, &[]ports.AddressPair{}) - } else { - port, err = CreatePort(is, name, net, &securityGroups, &allowedAddressPairs) - } - if err != nil { - return nil, fmt.Errorf("Failed to create port err: %v", err) - } - } else { - port = portList[0] + + // Update the port with the correct port security settings + // TODO(egarcia): figure out if possible to make this part of the prior create and update api calls + updateOpts := portsecurity.PortUpdateOptsExt{ + UpdateOptsBuilder: ports.UpdateOpts{}, + PortSecurityEnabled: net.portSecurity, + } + err = ports.Update(is.networkClient, port.ID, updateOpts).ExtractInto(&portWithPortSecurityExtensions) + if err != nil { + return nil, fmt.Errorf("Failed to update port security on port %s: %v", port.ID, err) } - portTags := deduplicateList(append(machineTags, port.Tags...)) + portTags := deduplicateList(append(machineTags, net.portTags...)) _, err = attributestags.ReplaceAll(is.networkClient, "ports", port.ID, attributestags.ReplaceAllOpts{ Tags: portTags}).Extract() if err != nil { @@ -522,31 +565,13 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust }) if config.Trunk == true { - allPages, err := trunks.List(is.networkClient, trunks.ListOpts{ + trunkCreateOpts := trunks.CreateOpts{ Name: name, PortID: port.ID, - }).AllPages() - if err != nil { - return nil, fmt.Errorf("Searching for existing trunk for server err: %v", err) } - trunkList, err := trunks.ExtractTrunks(allPages) + trunk, err := trunks.Create(is.networkClient, trunkCreateOpts).Extract() if err != nil { - return nil, fmt.Errorf("Searching for existing trunk for server err: %v", err) - } - var trunk trunks.Trunk - if len(trunkList) == 0 { - // create trunk with the previous port as parent - trunkCreateOpts := trunks.CreateOpts{ - Name: name, - PortID: port.ID, - } - newTrunk, err := trunks.Create(is.networkClient, trunkCreateOpts).Extract() - if err != nil { - return nil, fmt.Errorf("Create trunk for server err: %v", err) - } - trunk = *newTrunk - } else { - trunk = trunkList[0] + return nil, fmt.Errorf("Create trunk for server err: %v", err) } _, err = attributestags.ReplaceAll(is.networkClient, "trunks", trunk.ID, attributestags.ReplaceAllOpts{ diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/doc.go new file mode 100644 index 0000000000..2b9a391681 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/doc.go @@ -0,0 +1,145 @@ +/* +Package portsecurity provides information and interaction with the port +security extension for the OpenStack Networking service. + +Example to List Networks with Port Security Information + + type NetworkWithPortSecurityExt struct { + networks.Network + portsecurity.PortSecurityExt + } + + var allNetworks []NetworkWithPortSecurityExt + + listOpts := networks.ListOpts{ + Name: "network_1", + } + + allPages, err := networks.List(networkClient, listOpts).AllPages() + if err != nil { + panic(err) + } + + err = networks.ExtractNetworksInto(allPages, &allNetworks) + if err != nil { + panic(err) + } + + for _, network := range allNetworks { + fmt.Println("%+v\n", network) + } + +Example to Create a Network without Port Security + + var networkWithPortSecurityExt struct { + networks.Network + portsecurity.PortSecurityExt + } + + networkCreateOpts := networks.CreateOpts{ + Name: "private", + } + + iFalse := false + createOpts := portsecurity.NetworkCreateOptsExt{ + CreateOptsBuilder: networkCreateOpts, + PortSecurityEnabled: &iFalse, + } + + err := networks.Create(networkClient, createOpts).ExtractInto(&networkWithPortSecurityExt) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", networkWithPortSecurityExt) + +Example to Disable Port Security on an Existing Network + + var networkWithPortSecurityExt struct { + networks.Network + portsecurity.PortSecurityExt + } + + iFalse := false + networkID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + networkUpdateOpts := networks.UpdateOpts{} + updateOpts := portsecurity.NetworkUpdateOptsExt{ + UpdateOptsBuilder: networkUpdateOpts, + PortSecurityEnabled: &iFalse, + } + + err := networks.Update(networkClient, networkID, updateOpts).ExtractInto(&networkWithPortSecurityExt) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", networkWithPortSecurityExt) + +Example to Get a Port with Port Security Information + + var portWithPortSecurityExtensions struct { + ports.Port + portsecurity.PortSecurityExt + } + + portID := "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2" + + err := ports.Get(networkingClient, portID).ExtractInto(&portWithPortSecurityExtensions) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", portWithPortSecurityExtensions) + +Example to Create a Port Without Port Security + + var portWithPortSecurityExtensions struct { + ports.Port + portsecurity.PortSecurityExt + } + + iFalse := false + networkID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + subnetID := "a87cc70a-3e15-4acf-8205-9b711a3531b7" + + portCreateOpts := ports.CreateOpts{ + NetworkID: networkID, + FixedIPs: []ports.IP{ports.IP{SubnetID: subnetID}}, + } + + createOpts := portsecurity.PortCreateOptsExt{ + CreateOptsBuilder: portCreateOpts, + PortSecurityEnabled: &iFalse, + } + + err := ports.Create(networkingClient, createOpts).ExtractInto(&portWithPortSecurityExtensions) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", portWithPortSecurityExtensions) + +Example to Disable Port Security on an Existing Port + + var portWithPortSecurityExtensions struct { + ports.Port + portsecurity.PortSecurityExt + } + + iFalse := false + portID := "65c0ee9f-d634-4522-8954-51021b570b0d" + + portUpdateOpts := ports.UpdateOpts{} + updateOpts := portsecurity.PortUpdateOptsExt{ + UpdateOptsBuilder: portUpdateOpts, + PortSecurityEnabled: &iFalse, + } + + err := ports.Update(networkingClient, portID, updateOpts).ExtractInto(&portWithPortSecurityExtensions) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", portWithPortSecurityExtensions) +*/ +package portsecurity diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/requests.go new file mode 100644 index 0000000000..c80f47cf61 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/requests.go @@ -0,0 +1,104 @@ +package portsecurity + +import ( + "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" + "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" +) + +// PortCreateOptsExt adds port security options to the base ports.CreateOpts. +type PortCreateOptsExt struct { + ports.CreateOptsBuilder + + // PortSecurityEnabled toggles port security on a port. + PortSecurityEnabled *bool `json:"port_security_enabled,omitempty"` +} + +// ToPortCreateMap casts a CreateOpts struct to a map. +func (opts PortCreateOptsExt) ToPortCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToPortCreateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]interface{}) + + if opts.PortSecurityEnabled != nil { + port["port_security_enabled"] = &opts.PortSecurityEnabled + } + + return base, nil +} + +// PortUpdateOptsExt adds port security options to the base ports.UpdateOpts. +type PortUpdateOptsExt struct { + ports.UpdateOptsBuilder + + // PortSecurityEnabled toggles port security on a port. + PortSecurityEnabled *bool `json:"port_security_enabled,omitempty"` +} + +// ToPortUpdateMap casts a UpdateOpts struct to a map. +func (opts PortUpdateOptsExt) ToPortUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToPortUpdateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]interface{}) + + if opts.PortSecurityEnabled != nil { + port["port_security_enabled"] = &opts.PortSecurityEnabled + } + + return base, nil +} + +// NetworkCreateOptsExt adds port security options to the base +// networks.CreateOpts. +type NetworkCreateOptsExt struct { + networks.CreateOptsBuilder + + // PortSecurityEnabled toggles port security on a port. + PortSecurityEnabled *bool `json:"port_security_enabled,omitempty"` +} + +// ToNetworkCreateMap casts a CreateOpts struct to a map. +func (opts NetworkCreateOptsExt) ToNetworkCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToNetworkCreateMap() + if err != nil { + return nil, err + } + + network := base["network"].(map[string]interface{}) + + if opts.PortSecurityEnabled != nil { + network["port_security_enabled"] = &opts.PortSecurityEnabled + } + + return base, nil +} + +// NetworkUpdateOptsExt adds port security options to the base +// networks.UpdateOpts. +type NetworkUpdateOptsExt struct { + networks.UpdateOptsBuilder + + // PortSecurityEnabled toggles port security on a port. + PortSecurityEnabled *bool `json:"port_security_enabled,omitempty"` +} + +// ToNetworkUpdateMap casts a UpdateOpts struct to a map. +func (opts NetworkUpdateOptsExt) ToNetworkUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToNetworkUpdateMap() + if err != nil { + return nil, err + } + + network := base["network"].(map[string]interface{}) + + if opts.PortSecurityEnabled != nil { + network["port_security_enabled"] = &opts.PortSecurityEnabled + } + + return base, nil +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/results.go new file mode 100644 index 0000000000..7b3482a405 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/results.go @@ -0,0 +1,7 @@ +package portsecurity + +type PortSecurityExt struct { + // PortSecurityEnabled specifies whether port security is enabled or + // disabled. + PortSecurityEnabled bool `json:"port_security_enabled"` +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 7956f3ccde..35a3dd28b4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -123,6 +123,7 @@ github.com/gophercloud/gophercloud/openstack/networking/v2/extensions github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/attributestags github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding +github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/trunks