diff --git a/docs/config.md b/docs/config.md index 32e1b71cd4..6afc41eb10 100644 --- a/docs/config.md +++ b/docs/config.md @@ -137,4 +137,78 @@ securityGroups: We don't currently have specific version requriements, and so the choice is yours. However, we do require that you have either a ubuntu image or a centos image available in your cluster. For this step, we would like to refer you to the following doccumentation, https://docs.openstack.org/image-guide/obtain-images.html. -You can reference which operating system image you want to use in the machines.yaml script where it says ``. If you are using ubuntu, then replace `` in machines.yaml with `ubuntu`. If you are using centos, then replace `` in machines.yaml with `centos`. +You can reference which operating system image you want to use in the machines.yaml script where it says ``. If you are using ubuntu, then replace `` in machines.yaml with `ubuntu`. If you are using centos, then replace `` in machines.yaml with `centos`. + +## Subnets +Rather than just using a network, you have the option of specifying a specific subnet to connect your server to. The following is an example of how to specify a specific subnet of a network to use for a server. + +```yaml +- apiVersion: "cluster.k8s.io/v1alpha1" + kind: Machine + metadata: + generateName: openstack-node- + labels: + set: node + spec: + providerSpec: + value: + networks: + - subnet_id: < subnet id > +``` + +## Network Filters +If you have a complex query that you want to use to lookup a network, then you can do this by using a network filter. The filter will allow you to look up a network by the following network features: + - status + - name + - admin_state_up + - tenant_id + - project_id + - shared + - id + - marker + - limit + - sort_key + - sort_dir + - tags + - tags-any + - not-tags + - not-tags-any + +By using filters to look up a network, please note that it is possible to get multiple networks as a result. This should not be a problem, however please test your filters with `openstack network list` to be certian that it returns the networks you want. Please refer to the following usage example: + +```yaml +- apiVersion: "cluster.k8s.io/v1alpha1" + kind: Machine + metadata: + generateName: openstack-node- + labels: + set: node + spec: + providerSpec: + value: + networks: + - filters: + name: myNetwork + tags: myTag +``` + +## Multiple Networks +You can specify multiple networks (or subnets) to connect your server to. To do this, simply add another entry in the networks array. The following example connects the server to 3 different networks using all of the ways to connect discussed above: + +```yaml +- apiVersion: "cluster.k8s.io/v1alpha1" + kind: Machine + metadata: + generateName: openstack-node- + labels: + set: node + spec: + providerSpec: + value: + networks: + - filters: + name: myNetwork + tags: myTag + - uuid: your_network_id + - subnet_id: your_subnet_id +``` diff --git a/pkg/apis/openstackproviderconfig/v1alpha1/types.go b/pkg/apis/openstackproviderconfig/v1alpha1/types.go index 43b1ea0464..bd48669ef8 100644 --- a/pkg/apis/openstackproviderconfig/v1alpha1/types.go +++ b/pkg/apis/openstackproviderconfig/v1alpha1/types.go @@ -78,6 +78,8 @@ type NetworkParam struct { FixedIp string `json:"fixed_ip,omitempty"` // Filters for optional network query Filter Filter `json:"filter,omitempty"` + // Subnet within a network to use + SubnetID string `json:"subnet_id,omitempty"` } type Filter struct { diff --git a/pkg/cloud/openstack/clients/machineservice.go b/pkg/cloud/openstack/clients/machineservice.go index ae09893a83..09b1338cba 100644 --- a/pkg/cloud/openstack/clients/machineservice.go +++ b/pkg/cloud/openstack/clients/machineservice.go @@ -37,6 +37,7 @@ import ( "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" + "github.com/gophercloud/gophercloud/openstack/networking/v2/subnets" "github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/utils/openstack/clientconfig" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -67,6 +68,10 @@ type Instance struct { servers.Server } +type ServerNetwork struct { + networkID string + subnetID string +} type InstanceListOpts struct { // Name of the image in URL format. Image string `q:"image"` @@ -254,6 +259,22 @@ func getNetworkIDsByFilter(is *InstanceService, opts *networks.ListOpts) ([]stri return uuids, nil } +func CreatePort(is *InstanceService, name string, net ServerNetwork, securityGroups *[]string) (ports.Port, error) { + portCreateOpts := ports.CreateOpts{ + Name: name, + NetworkID: net.networkID, + SecurityGroups: securityGroups, + } + if net.subnetID != "" { + portCreateOpts.FixedIPs = []ports.IP{{SubnetID: net.subnetID}} + } + newPort, err := ports.Create(is.networkClient, portCreateOpts).Extract() + if err != nil { + return ports.Port{}, fmt.Errorf("Create port for server err: %v", err) + } + return *newPort, nil +} + func (is *InstanceService) InstanceCreate(clusterName string, name string, config *openstackconfigv1.OpenstackProviderSpec, cmd string, keyName string) (instance *Instance, err error) { if config == nil { return nil, fmt.Errorf("create Options need be specified to create instace") @@ -271,22 +292,33 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, confi "cluster-api-provider-openstack", clusterName, } - var nets []servers.Network + // Get all network UUIDs + var nets []ServerNetwork for _, net := range config.Networks { - if net.UUID == "" { + if net.UUID == "" && net.SubnetID == "" { opts := networks.ListOpts(net.Filter) ids, err := getNetworkIDsByFilter(is, &opts) if err != nil { return nil, err } for _, netID := range ids { - nets = append(nets, servers.Network{ - UUID: netID, + nets = append(nets, ServerNetwork{ + networkID: netID, }) } + } else if net.UUID == "" && net.SubnetID != "" { + subnet, err := subnets.Get(is.networkClient, net.SubnetID).Extract() + if err != nil { + return nil, err + } + nets = append(nets, ServerNetwork{ + networkID: subnet.NetworkID, + subnetID: net.SubnetID, + }) } else { - nets = append(nets, servers.Network{ - UUID: net.UUID, + nets = append(nets, ServerNetwork{ + networkID: net.UUID, + subnetID: net.SubnetID, }) } if len(net.Filter.Tags) > 0 { @@ -296,9 +328,12 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, confi 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.UUID, + NetworkID: net.networkID, }).AllPages() if err != nil { return nil, fmt.Errorf("Searching for existing port for server err: %v", err) @@ -310,16 +345,10 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, confi var port ports.Port if len(portList) == 0 { // create server port - portCreateOpts := ports.CreateOpts{ - Name: name, - NetworkID: net.UUID, - SecurityGroups: &config.SecurityGroups, - } - newPort, err := ports.Create(is.networkClient, portCreateOpts).Extract() + port, err = CreatePort(is, name, net, &config.SecurityGroups) if err != nil { - return nil, fmt.Errorf("Create port for server err: %v", err) + return nil, fmt.Errorf("Failed to create port err: %v", err) } - port = *newPort } else { port = portList[0] }