Skip to content

Commit

Permalink
Specify security groups by id when creating servers
Browse files Browse the repository at this point in the history
  • Loading branch information
databus23 authored and BugRoger committed Dec 15, 2017
1 parent 93b015e commit ea5e99f
Show file tree
Hide file tree
Showing 15 changed files with 807 additions and 7 deletions.
3 changes: 3 additions & 0 deletions pkg/api/models/openstack_spec.go

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

3 changes: 3 additions & 0 deletions pkg/api/spec/embedded_spec.go

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

50 changes: 43 additions & 7 deletions pkg/client/openstack/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
"github.com/gophercloud/gophercloud/openstack/identity/v3/users"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers"
securitygroups "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups"
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
Expand All @@ -26,6 +27,7 @@ import (

"github.com/sapcc/kubernikus/pkg/api/models"
kubernikus_v1 "github.com/sapcc/kubernikus/pkg/apis/kubernikus/v1"
"github.com/sapcc/kubernikus/pkg/client/openstack/compute"
"github.com/sapcc/kubernikus/pkg/client/openstack/domains"
"github.com/sapcc/kubernikus/pkg/client/openstack/roles"
)
Expand Down Expand Up @@ -60,6 +62,7 @@ type Client interface {
DeleteUser(username, domainID string) error
CreateKlusterServiceUser(username, password, domain, defaultProjectID string) error
GetKubernikusCatalogEntry() (string, error)
GetSecurityGroupID(project_id, name string) (string, error)
}

type Project struct {
Expand Down Expand Up @@ -550,13 +553,16 @@ func (c *client) CreateNode(kluster *kubernikus_v1.Kluster, pool *models.NodePoo
name := v1.SimpleNameGenerator.GenerateName(fmt.Sprintf("%v-%v-", kluster.Spec.Name, pool.Name))
glog.V(5).Infof("Creating node %v", name)

server, err := servers.Create(client, servers.CreateOpts{
Name: name,
FlavorName: pool.Flavor,
ImageName: pool.Image,
Networks: []servers.Network{servers.Network{UUID: kluster.Spec.Openstack.NetworkID}},
UserData: userData,
ServiceClient: client,
server, err := servers.Create(client, compute.CreateOpts{
CreateOpts: servers.CreateOpts{
Name: name,
FlavorName: pool.Flavor,
ImageName: pool.Image,
Networks: []servers.Network{servers.Network{UUID: kluster.Spec.Openstack.NetworkID}},
UserData: userData,
ServiceClient: client,
SecurityGroups: []string{kluster.Spec.Openstack.SecurityGroupID},
},
}).Extract()

if err != nil {
Expand Down Expand Up @@ -680,3 +686,33 @@ func (c *client) GetKubernikusCatalogEntry() (string, error) {

return "", err
}
func (c *client) GetSecurityGroupID(project_id string, name string) (string, error) {

provider, err := c.adminClient()
if err != nil {
return "", err
}
networkClient, err := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{})
if err != nil {
return "", err
}

var group securitygroups.SecGroup

err = securitygroups.List(networkClient, securitygroups.ListOpts{Name: name, TenantID: project_id}).EachPage(func(page pagination.Page) (bool, error) {
groups, err := securitygroups.ExtractGroups(page)
if err != nil {
return false, err
}
switch len(groups) {
case 0:
return false, errors.New("Security group not found")
case 1:
group = groups[0]
return false, nil
default:
return false, errors.New("Multiple security groups with the same name found")
}
})
return group.ID, err
}
32 changes: 32 additions & 0 deletions pkg/client/openstack/compute/create_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package compute

import (
"errors"

"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
)

type CreateOpts struct {
servers.CreateOpts
}

func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
data, err := opts.CreateOpts.ToServerCreateMap()
if err != nil {
return nil, err
}
if _, ok := data["server"]; !ok {
return nil, errors.New("Expected field `server` not found")
}

serverData, ok := data["server"].(map[string]interface{})
if !ok {
return nil, errors.New("Field `server` not of expected type")
}
securityGroups := make([]map[string]interface{}, len(opts.SecurityGroups))
for i, groupID := range opts.SecurityGroups {
securityGroups[i] = map[string]interface{}{"id": groupID}
}
serverData["security_groups"] = securityGroups
return data, nil
}
27 changes: 27 additions & 0 deletions pkg/client/openstack/compute/create_options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package compute

import (
"testing"

"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
"github.com/stretchr/testify/assert"
)

func TestCreateOpts(t *testing.T) {
opts := CreateOpts{
CreateOpts: servers.CreateOpts{
Name: "nase",
FlavorRef: "flavor",
SecurityGroups: []string{"id1", "id2"},
}}

data, err := opts.ToServerCreateMap()
assert.NoError(t, err)
serverData := data["server"].(map[string]interface{})
expected := []map[string]interface{}{
map[string]interface{}{"id": opts.SecurityGroups[0]},
map[string]interface{}{"id": opts.SecurityGroups[1]},
}
assert.Equal(t, expected, serverData["security_groups"])
assert.Equal(t, opts.Name, serverData["name"])
}
35 changes: 35 additions & 0 deletions pkg/controller/ground.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ func (op *GroundControl) handler(key string) error {
metrics.SetMetricKlusterInfo(kluster.GetNamespace(), kluster.GetName(), kluster.Status.Version, kluster.Spec.Openstack.ProjectID, kluster.GetAnnotations(), kluster.GetLabels())
metrics.SetMetricKlusterStatusPhase(kluster.GetName(), kluster.Status.Phase)

//TODO: remove ASAP, this is just a poor mans migration, adding the sec group id to existing klusters
if err := op.ensureSecurityGroupID(kluster); err != nil {
op.Recorder.Eventf(kluster, api_v1.EventTypeWarning, ConfigurationError, "Failed to add default security grop id to kluster: %s", err)
}

switch phase := kluster.Status.Phase; phase {
case models.KlusterPhasePending:
{
Expand Down Expand Up @@ -477,10 +482,40 @@ func (op *GroundControl) discoverOpenstackInfo(kluster *v1.Kluster) error {
}
}

if securityGroupID := copy.Spec.Openstack.SecurityGroupID; securityGroupID != "" {
//TODO: Validate that the securitygroup id exists

} else {
id, err := op.Clients.Openstack.GetSecurityGroupID(kluster.Account(), "default")
if err != nil {
return fmt.Errorf("Failed to get id for default securitygroup in project %s: %s", err, kluster.Account())
}
glog.V(5).Infof("[%v] Setting SecurityGroupID to %v", kluster.Name, copy.Spec.Openstack.SecurityGroupID)
copy.Spec.Openstack.SecurityGroupID = id
}

_, err = op.Clients.Kubernikus.Kubernikus().Klusters(kluster.Namespace).Update(copy)
return err
}

//TODO: remove this after it has been deployed once everywhere, this is a poor mans migration
func (op *GroundControl) ensureSecurityGroupID(kluster *v1.Kluster) error {
if kluster.Spec.Openstack.SecurityGroupID == "" {
copy, err := op.Clients.Kubernikus.Kubernikus().Klusters(kluster.Namespace).Get(kluster.Name, metav1.GetOptions{})
if err != nil {
return err
}
id, err := op.Clients.Openstack.GetSecurityGroupID(kluster.Account(), "default")
if err != nil {
return fmt.Errorf("Failed to get id for default securitygroup in project %s: %s", err, kluster.Account())
}
copy.Spec.Openstack.SecurityGroupID = id
_, err = op.Clients.Kubernikus.Kubernikus().Klusters(kluster.Namespace).Update(copy)
return err
}
return nil
}

func (op *GroundControl) podAdd(obj interface{}) {
pod := obj.(*api_v1.Pod)

Expand Down
2 changes: 2 additions & 0 deletions swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ definitions:
lbSubnetID:
x-go-name: LBSubnetID
type: string
securityGroupID:
type: string
NodePool:
x-nullable: false
type: object
Expand Down

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

Loading

0 comments on commit ea5e99f

Please sign in to comment.