Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 1823487: Add ServerGroupName to OpenstackProviderSpec #97

Merged
merged 1 commit into from
May 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion pkg/apis/openstackproviderconfig/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,14 @@ type OpenstackProviderSpec struct {
// The volume metadata to boot from
RootVolume *RootVolume `json:"rootVolume,omitempty"`

// The server group to assign the machine to
// The server group to assign the machine to.
ServerGroupID string `json:"serverGroupID,omitempty"`

// The server group to assign the machine to. A server group with that
// name will be created if it does not exist. If both ServerGroupID and
// ServerGroupName are non-empty, they must refer to the same OpenStack
// resource.
ServerGroupName string `json:"serverGroupName,omitempty"`
}

type SecurityGroupParam struct {
Expand Down
84 changes: 83 additions & 1 deletion pkg/cloud/openstack/clients/machineservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups"
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
Expand Down Expand Up @@ -395,7 +396,9 @@ func getImageID(is *InstanceService, imageName string) (string, error) {
}
}

// InstanceCreate creates a compute instance
// InstanceCreate creates a compute instance.
// If ServerGroupName is nonempty and no server group exists with that name,
// then InstanceCreate creates a server group with that name.
func (is *InstanceService) InstanceCreate(clusterName string, name string, clusterSpec *openstackconfigv1.OpenstackClusterProviderSpec, config *openstackconfigv1.OpenstackProviderSpec, cmd string, keyName string, configClient configclient.ConfigV1Interface) (instance *Instance, err error) {
if config == nil {
return nil, fmt.Errorf("create Options need be specified to create instace")
Expand Down Expand Up @@ -671,6 +674,49 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust

}

// The Machine spec accepts both a server group ID and a server group
// name. If both are present, assert that they are consistent, else
// fail. If only the name is present, create the server group.
//
// This block validates or populates config.ServerGroupID.
if config.ServerGroupName != "" {
existingServerGroups, err := getServerGroupsByName(is.computeClient, config.ServerGroupName)
if err != nil {
return nil, fmt.Errorf("retrieving existing server groups: %v", err)
}

if config.ServerGroupID == "" {
switch len(existingServerGroups) {
case 0:
sg, err := createServerGroup(is.computeClient, config.ServerGroupName)
if err != nil {
return nil, fmt.Errorf("creating the server group: %v", err)
}
config.ServerGroupID = sg.ID
case 1:
config.ServerGroupID = existingServerGroups[0].ID
default:
return nil, fmt.Errorf("multiple server groups found with the same ServerGroupName")
}
} else {
switch len(existingServerGroups) {
case 0:
return nil, fmt.Errorf("incompatible ServerGroupID and ServerGroupName")
default:
var found bool
for _, existingServerGroup := range existingServerGroups {
if existingServerGroup.ID == config.ServerGroupID {
found = true
break
}
}
if !found {
return nil, fmt.Errorf("incompatible ServerGroupID and ServerGroupName")
}
}
}
}

// If the spec sets a server group, then add scheduler hint
if config.ServerGroupID != "" {
serverCreateOpts = schedulerhints.CreateOptsExt{
Expand All @@ -693,6 +739,42 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust
return serverToInstance(server), nil
}

func createServerGroup(computeClient *gophercloud.ServiceClient, name string) (*servergroups.ServerGroup, error) {
// Microversion "2.15" is the first that supports "soft"-anti-affinity.
// Microversions starting from "2.64" accept policies as a string
// instead of an array.
defer func(microversion string) {
computeClient.Microversion = microversion
}(computeClient.Microversion)
computeClient.Microversion = "2.15"

return servergroups.Create(computeClient, &servergroups.CreateOpts{
Name: name,
Policies: []string{"soft-anti-affinity"},
}).Extract()
}

func getServerGroupsByName(computeClient *gophercloud.ServiceClient, name string) ([]servergroups.ServerGroup, error) {
pages, err := servergroups.List(computeClient).AllPages()
if err != nil {
return nil, err
}

allServerGroups, err := servergroups.ExtractServerGroups(pages)
if err != nil {
return nil, err
}

serverGroups := make([]servergroups.ServerGroup, 0, len(allServerGroups))
for _, serverGroup := range allServerGroups {
if serverGroup.Name == name {
serverGroups = append(serverGroups, serverGroup)
}
}

return serverGroups, nil
}

func (is *InstanceService) deleteInstancePorts(id string) error {
// get instance port id
allInterfaces, err := attachinterfaces.List(is.computeClient, id).AllPages()
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading