Skip to content

Commit

Permalink
Merge pull request #670 from weaveworks/move-nodegroup-filters
Browse files Browse the repository at this point in the history
Move nodegroup filters
  • Loading branch information
errordeveloper authored Mar 27, 2019
2 parents 90e1e79 + 5ed31a5 commit 2e54319
Show file tree
Hide file tree
Showing 8 changed files with 529 additions and 439 deletions.
134 changes: 134 additions & 0 deletions pkg/ctl/cmdutils/nodegroup_filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package cmdutils

import (
"fmt"
"strings"

"github.com/gobwas/glob"
"github.com/kris-nova/logger"
"github.com/pkg/errors"

"k8s.io/apimachinery/pkg/util/sets"

api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha4"
"github.com/weaveworks/eksctl/pkg/cfn/manager"
)

// NodeGroupFilter holds filter configuration
type NodeGroupFilter struct {
IgnoreAllExisting bool

existing sets.String
only []glob.Glob
onlySpec string
}

// NewNodeGroupFilter create new NodeGroupFilter instance
func NewNodeGroupFilter() *NodeGroupFilter {
return &NodeGroupFilter{
IgnoreAllExisting: true,

existing: sets.NewString(),
}
}

// ApplyOnlyFilter parses given globs for exclusive filtering
func (f *NodeGroupFilter) ApplyOnlyFilter(globExprs []string, cfg *api.ClusterConfig) error {
for _, expr := range globExprs {
compiledExpr, err := glob.Compile(expr)
if err != nil {
return errors.Wrapf(err, "parsing glob filter %q", expr)
}
f.only = append(f.only, compiledExpr)
}
f.onlySpec = strings.Join(globExprs, ",")
return f.onlyFilterMatchesAnything(cfg)
}

func (f *NodeGroupFilter) onlyFilterMatchesAnything(cfg *api.ClusterConfig) error {
if len(f.only) == 0 {
return nil
}
for _, ng := range cfg.NodeGroups {
for _, compiledExpr := range f.only {
if compiledExpr.Match(ng.Name) {
return nil
}
}
}
return fmt.Errorf("no nodegroups match filter specification: %q", f.onlySpec)
}

// ApplyExistingFilter uses stackManager to list existing nodegroup stacks and configures
// the filter accordingly
func (f *NodeGroupFilter) ApplyExistingFilter(stackManager *manager.StackCollection) error {
if !f.IgnoreAllExisting {
return nil
}

existing, err := stackManager.ListNodeGroupStacks()
if err != nil {
return err
}

f.existing.Insert(existing...)

return nil
}

// Match checks given nodegroup against the filter
func (f *NodeGroupFilter) Match(ng *api.NodeGroup) bool {
if f.IgnoreAllExisting && f.existing.Has(ng.Name) {
return false
}

for _, compiledExpr := range f.only {
if compiledExpr.Match(ng.Name) {
return true // return first match
}
}

// if no globs were given, match everything,
// if false - we haven't matched anything so far
return len(f.only) == 0
}

// MatchAll checks all nodegroups against the filter and returns all of
// matching names as set
func (f *NodeGroupFilter) MatchAll(cfg *api.ClusterConfig) sets.String {
names := sets.NewString()
for _, ng := range cfg.NodeGroups {
if f.Match(ng) {
names.Insert(ng.Name)
}
}
return names
}

// LogInfo prints out a user-friendly message about how filter was applied
func (f *NodeGroupFilter) LogInfo(cfg *api.ClusterConfig) {
count := f.MatchAll(cfg).Len()
filteredOutCount := len(cfg.NodeGroups) - count
if filteredOutCount > 0 {
reasons := []string{}
if f.onlySpec != "" {
reasons = append(reasons, fmt.Sprintf("--only=%q was given", f.onlySpec))
}
if existingCount := f.existing.Len(); existingCount > 0 {
reasons = append(reasons, fmt.Sprintf("%d nodegroup(s) (%s) already exist", existingCount, strings.Join(f.existing.List(), ", ")))
}
logger.Info("%d nodegroup(s) were filtered out: %s", filteredOutCount, strings.Join(reasons, ", "))
}
}

// CheckEachNodeGroup iterates over each nodegroup and calls check function if it matches the filter
func (f *NodeGroupFilter) CheckEachNodeGroup(nodeGroups []*api.NodeGroup, check func(i int, ng *api.NodeGroup) error) error {
for i, ng := range nodeGroups {
if f.Match(ng) {
if err := check(i, ng); err != nil {
return err
}
}
}
return nil
}
130 changes: 130 additions & 0 deletions pkg/ctl/cmdutils/nodegroup_filter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package cmdutils_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha4"

. "github.com/weaveworks/eksctl/pkg/ctl/cmdutils"
)

var _ = Describe("nodegroup filter", func() {

Context("CheckEachNodeGroup", func() {

It("should iterate over unique nodegroups", func() {
cfg := newClusterConfig()
addGroupA(cfg)

filter := NewNodeGroupFilter()
names := []string{}

filter.CheckEachNodeGroup(cfg.NodeGroups, func(i int, nodeGroup *api.NodeGroup) error {
Expect(nodeGroup).To(Equal(cfg.NodeGroups[i]))
names = append(names, nodeGroup.Name)
return nil
})
Expect(names).To(Equal([]string{"test-ng1a", "test-ng2a", "test-ng3a"}))

names = []string{}
cfg.NodeGroups[0].Name = "ng-x0"
cfg.NodeGroups[1].Name = "ng-x1"
cfg.NodeGroups[2].Name = "ng-x2"

filter.CheckEachNodeGroup(cfg.NodeGroups, func(i int, nodeGroup *api.NodeGroup) error {
Expect(nodeGroup).To(Equal(cfg.NodeGroups[i]))
names = append(names, nodeGroup.Name)
return nil
})
Expect(names).To(Equal([]string{"ng-x0", "ng-x1", "ng-x2"}))
})

It("should iterate over unique nodegroups and filter some out", func() {
cfg := newClusterConfig()
addGroupA(cfg)
addGroupB(cfg)

filter := NewNodeGroupFilter()
names := []string{}

filter.CheckEachNodeGroup(cfg.NodeGroups, func(i int, nodeGroup *api.NodeGroup) error {
Expect(nodeGroup).To(Equal(cfg.NodeGroups[i]))
names = append(names, nodeGroup.Name)
return nil
})
Expect(names).To(Equal([]string{"test-ng1a", "test-ng2a", "test-ng3a", "test-ng1b", "test-ng2b", "test-ng3b"}))

names = []string{}

err := filter.ApplyOnlyFilter([]string{"t?xyz?", "ab*z123?"}, cfg)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal(`no nodegroups match filter specification: "t?xyz?,ab*z123?"`))

err = filter.ApplyOnlyFilter([]string{"test-ng1?", "te*-ng3?"}, cfg)
Expect(err).ToNot(HaveOccurred())
filter.CheckEachNodeGroup(cfg.NodeGroups, func(i int, nodeGroup *api.NodeGroup) error {
Expect(nodeGroup).To(Equal(cfg.NodeGroups[i]))
names = append(names, nodeGroup.Name)
return nil
})
Expect(names).To(Equal([]string{"test-ng1a", "test-ng3a", "test-ng1b", "test-ng3b"}))
})
})
})

func newClusterConfig() *api.ClusterConfig {
cfg := api.NewClusterConfig()

cfg.Metadata.Name = "test-3x3-ngs"
cfg.Metadata.Region = "eu-central-1"

return cfg
}

func addGroupA(cfg *api.ClusterConfig) {
var ng *api.NodeGroup

ng = cfg.NewNodeGroup()
ng.Name = "test-ng1a"
ng.VolumeSize = 768
ng.VolumeType = "io1"
ng.IAM.AttachPolicyARNs = []string{"foo"}
ng.Labels = map[string]string{"group": "a", "seq": "1"}

ng = cfg.NewNodeGroup()
ng.Name = "test-ng2a"
ng.IAM.AttachPolicyARNs = []string{"bar"}
ng.Labels = map[string]string{"group": "a", "seq": "2"}

ng = cfg.NewNodeGroup()
ng.Name = "test-ng3a"
ng.ClusterDNS = "1.2.3.4"
ng.InstanceType = "m3.large"
ng.AllowSSH = true
ng.Labels = map[string]string{"group": "a", "seq": "3"}
}

func addGroupB(cfg *api.ClusterConfig) {
var ng *api.NodeGroup

ng = cfg.NewNodeGroup()
ng.Name = "test-ng1b"
ng.AllowSSH = true
ng.Labels = map[string]string{"group": "b", "seq": "1"}

ng = cfg.NewNodeGroup()
ng.Name = "test-ng2b"
ng.ClusterDNS = "4.2.8.14"
ng.InstanceType = "m5.xlarge"
ng.SecurityGroups.AttachIDs = []string{"sg-1", "sg-2"}
ng.SecurityGroups.WithLocal = api.NewBoolFalse()
ng.Labels = map[string]string{"group": "b", "seq": "1"}

ng = cfg.NewNodeGroup()
ng.Name = "test-ng3b"
ng.VolumeSize = 192
ng.SecurityGroups.AttachIDs = []string{"sg-1", "sg-2"}
ng.SecurityGroups.WithLocal = api.NewBoolFalse()
ng.Labels = map[string]string{"group": "b", "seq": "1"}
}
File renamed without changes.
10 changes: 5 additions & 5 deletions pkg/ctl/create/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri
return err
}

ngFilter := NewNodeGroupFilter()
ngFilter := cmdutils.NewNodeGroupFilter()

if clusterConfigFile != "" {
if err := eks.LoadConfigFromFile(clusterConfigFile, cfg); err != nil {
Expand Down Expand Up @@ -295,7 +295,7 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri
return err
}

if err := checkEachNodeGroup(ngFilter, cfg.NodeGroups, canUseForPrivateNodeGroups); err != nil {
if err := ngFilter.CheckEachNodeGroup(cfg.NodeGroups, canUseForPrivateNodeGroups); err != nil {
return err
}

Expand All @@ -322,7 +322,7 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri
return err
}

if err := checkEachNodeGroup(ngFilter, cfg.NodeGroups, canUseForPrivateNodeGroups); err != nil {
if err := ngFilter.CheckEachNodeGroup(cfg.NodeGroups, canUseForPrivateNodeGroups); err != nil {
return err
}

Expand All @@ -335,7 +335,7 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri
return err
}

err := checkEachNodeGroup(ngFilter, cfg.NodeGroups, func(_ int, ng *api.NodeGroup) error {
err := ngFilter.CheckEachNodeGroup(cfg.NodeGroups, func(_ int, ng *api.NodeGroup) error {
// resolve AMI
if err := ctl.EnsureAMI(meta.Version, ng); err != nil {
return err
Expand Down Expand Up @@ -424,7 +424,7 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri
return err
}

err = checkEachNodeGroup(ngFilter, cfg.NodeGroups, func(_ int, ng *api.NodeGroup) error {
err = ngFilter.CheckEachNodeGroup(cfg.NodeGroups, func(_ int, ng *api.NodeGroup) error {
// authorise nodes to join
if err = authconfigmap.AddNodeGroup(clientSet, ng); err != nil {
return err
Expand Down
8 changes: 4 additions & 4 deletions pkg/ctl/create/nodegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func doCreateNodeGroups(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg s
return err
}

ngFilter := NewNodeGroupFilter()
ngFilter := cmdutils.NewNodeGroupFilter()

if clusterConfigFile != "" {
if err := eks.LoadConfigFromFile(clusterConfigFile, cfg); err != nil {
Expand Down Expand Up @@ -135,7 +135,7 @@ func doCreateNodeGroups(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg s
return err
}

if err := checkEachNodeGroup(ngFilter, cfg.NodeGroups, NewNodeGroupChecker); err != nil {
if err := ngFilter.CheckEachNodeGroup(cfg.NodeGroups, NewNodeGroupChecker); err != nil {
return err
}
} else {
Expand Down Expand Up @@ -191,7 +191,7 @@ func doCreateNodeGroups(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg s
return err
}

err := checkEachNodeGroup(ngFilter, cfg.NodeGroups, func(_ int, ng *api.NodeGroup) error {
err := ngFilter.CheckEachNodeGroup(cfg.NodeGroups, func(_ int, ng *api.NodeGroup) error {
// resolve AMI
if err := ctl.EnsureAMI(meta.Version, ng); err != nil {
return err
Expand Down Expand Up @@ -251,7 +251,7 @@ func doCreateNodeGroups(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg s
return err
}

err = checkEachNodeGroup(ngFilter, cfg.NodeGroups, func(_ int, ng *api.NodeGroup) error {
err = ngFilter.CheckEachNodeGroup(cfg.NodeGroups, func(_ int, ng *api.NodeGroup) error {
if updateAuthConfigMap {
// authorise nodes to join
if err = authconfigmap.AddNodeGroup(clientSet, ng); err != nil {
Expand Down
Loading

0 comments on commit 2e54319

Please sign in to comment.