Skip to content

Commit

Permalink
Merge pull request #653 from weaveworks/create-ng-ignore-existing
Browse files Browse the repository at this point in the history
ignore existing nodegroups when creating with config file
  • Loading branch information
errordeveloper authored Mar 25, 2019
2 parents f4737a5 + 5b512da commit 5df021d
Show file tree
Hide file tree
Showing 8 changed files with 688 additions and 192 deletions.
12 changes: 3 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,20 +342,14 @@ Get the list of old nodegroups:
old_nodegroups="$(eksctl get ng --cluster=<clusterName> --output=json | jq -r '.[].Name')"
```

Edit config file to add new nodegroups.
Edit config file to add new nodegroups. You can remove old nodegroups from the config file now
or do it later.

If you have removed the definition of old nodegroups from the config file, then you can run:
To create all of new nodegroups defined in the config file, run:
```
eksctl create nodegroup --config-file=<path>
```

Alternatively, you can keep the old definitions in the config file and pass `--only` with a list of the new nodegroup
names that you want to add (you can use glob expressions, or list specific names - see ['Managing
nodegroup'](#managing-nodegroups) for details):
```
eksctl create nodegroup --config-file=<path> --only=<list>
```

Once you have new nodegroups in place, you can delete old ones:
```
for ng in $old_nodegroups ; do eksctl delete nodegroup --cluster=<clusterName> --name=$ng ; done
Expand Down
14 changes: 14 additions & 0 deletions pkg/cfn/manager/nodegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,20 @@ func (c *StackCollection) DescribeNodeGroupStacks() ([]*Stack, error) {
return nodeGroupStacks, nil
}

// ListNodeGroupStacks calls DescribeNodeGroupStacks and returns only nodegroup names
func (c *StackCollection) ListNodeGroupStacks() ([]string, error) {
stacks, err := c.DescribeNodeGroupStacks()
if err != nil {
return nil, err
}

names := []string{}
for _, s := range stacks {
names = append(names, getNodeGroupName(s))
}
return names, nil
}

// DescribeNodeGroupStacksAndResources calls DescribeNodeGroupStacks and fetches all resources,
// then returns it in a map by nodegroup name
func (c *StackCollection) DescribeNodeGroupStacksAndResources() (map[string]StackInfo, error) {
Expand Down
14 changes: 10 additions & 4 deletions pkg/cfn/manager/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package manager
import (
"sync"

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

"github.com/kris-nova/logger"

api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha4"
Expand Down Expand Up @@ -60,28 +62,32 @@ func (c *StackCollection) RunSingleTask(t Task) []error {
// the stacks (a cluster and one or more nodegroups); any errors
// will be returned as a slice as soon as one of the tasks or group
// of tasks is completed
func (c *StackCollection) CreateClusterWithNodeGroups() []error {
func (c *StackCollection) CreateClusterWithNodeGroups(onlySubset sets.String) []error {
if errs := c.RunSingleTask(Task{c.CreateCluster, nil}); len(errs) > 0 {
return errs
}

return c.CreateAllNodeGroups()
return c.CreateAllNodeGroups(onlySubset)
}

// CreateAllNodeGroups runs all tasks required to create the node groups;
// any errors will be returned as a slice as soon as one of the tasks
// or group of tasks is completed
func (c *StackCollection) CreateAllNodeGroups() []error {
func (c *StackCollection) CreateAllNodeGroups(onlySubset sets.String) []error {
errs := []error{}
appendErr := func(err error) {
errs = append(errs, err)
}

createAllNodeGroups := []Task{}
for i := range c.spec.NodeGroups {
ng := c.spec.NodeGroups[i]
if onlySubset != nil && !onlySubset.Has(ng.Name) {
continue
}
t := Task{
Call: c.CreateNodeGroup,
Data: c.spec.NodeGroups[i],
Data: ng,
}
createAllNodeGroups = append(createAllNodeGroups, t)
}
Expand Down
107 changes: 13 additions & 94 deletions pkg/ctl/create/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/weaveworks/eksctl/pkg/ami"
api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha4"
"github.com/weaveworks/eksctl/pkg/authconfigmap"
"github.com/weaveworks/eksctl/pkg/ctl/cmdutils"
Expand Down Expand Up @@ -103,89 +102,6 @@ func createClusterCmd(g *cmdutils.Grouping) *cobra.Command {
return cmd
}

// When passing the --without-nodegroup option, don't create nodegroups
func skipNodeGroupsIfRequested(cfg *api.ClusterConfig) {
if withoutNodeGroup {
cfg.NodeGroups = nil
logger.Warning("cluster will be created without an initial nodegroup")
}
}

// checkEachNodeGroup iterates over each nodegroup and calls check function
// (this is need to avoid common goroutine-for-loop pitfall)
func checkEachNodeGroup(cfg *api.ClusterConfig, check func(i int, ng *api.NodeGroup) error) error {
for i := range cfg.NodeGroups {
if err := check(i, cfg.NodeGroups[i]); err != nil {
return err
}
}
return nil
}

func newNodeGroupChecker(i int, ng *api.NodeGroup) error {
if err := api.ValidateNodeGroup(i, ng); err != nil {
return err
}

// apply defaults
if ng.InstanceType == "" {
ng.InstanceType = api.DefaultNodeType
}
if ng.AMIFamily == "" {
ng.AMIFamily = ami.ImageFamilyAmazonLinux2
}
if ng.AMI == "" {
ng.AMI = ami.ResolverStatic
}

if ng.SecurityGroups == nil {
ng.SecurityGroups = &api.NodeGroupSGs{
AttachIDs: []string{},
}
}
if ng.SecurityGroups.WithLocal == nil {
ng.SecurityGroups.WithLocal = api.NewBoolTrue()
}
if ng.SecurityGroups.WithShared == nil {
ng.SecurityGroups.WithShared = api.NewBoolTrue()
}

if ng.AllowSSH {
if ng.SSHPublicKeyPath == "" {
ng.SSHPublicKeyPath = defaultSSHPublicKey
}
}

if ng.VolumeSize > 0 {
if ng.VolumeType == "" {
ng.VolumeType = api.DefaultNodeVolumeType
}
}

if ng.IAM == nil {
ng.IAM = &api.NodeGroupIAM{}
}
if ng.IAM.WithAddonPolicies.ImageBuilder == nil {
ng.IAM.WithAddonPolicies.ImageBuilder = api.NewBoolFalse()
}
if ng.IAM.WithAddonPolicies.AutoScaler == nil {
ng.IAM.WithAddonPolicies.AutoScaler = api.NewBoolFalse()
}
if ng.IAM.WithAddonPolicies.ExternalDNS == nil {
ng.IAM.WithAddonPolicies.ExternalDNS = api.NewBoolFalse()
}

return nil
}

func checkSubnetsGiven(cfg *api.ClusterConfig) bool {
return cfg.VPC.Subnets != nil && len(cfg.VPC.Subnets.Private)+len(cfg.VPC.Subnets.Public) != 0
}

func checkSubnetsGivenAsFlags() bool {
return len(*subnets[api.SubnetTopologyPrivate])+len(*subnets[api.SubnetTopologyPublic]) != 0
}

func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg string, cmd *cobra.Command) error {
meta := cfg.Metadata

Expand All @@ -195,6 +111,8 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri
return err
}

ngFilter := NewNodeGroupFilter()

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

skipNodeGroupsIfRequested(cfg)

if err := checkEachNodeGroup(cfg, newNodeGroupChecker); err != nil {
if err := CheckEachNodeGroup(ngFilter, cfg, NewNodeGroupChecker); err != nil {
return err
}
} else {
Expand All @@ -276,7 +194,7 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri

skipNodeGroupsIfRequested(cfg)

err := checkEachNodeGroup(cfg, func(i int, ng *api.NodeGroup) error {
err := CheckEachNodeGroup(ngFilter, cfg, func(i int, ng *api.NodeGroup) error {
if ng.AllowSSH && ng.SSHPublicKeyPath == "" {
return fmt.Errorf("--ssh-public-key must be non-empty string")
}
Expand Down Expand Up @@ -387,7 +305,7 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri
return err
}

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

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

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

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

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

{ // core action
ngSubset := ngFilter.MatchAll(cfg)
stackManager := ctl.NewStackManager(cfg)
if len(cfg.NodeGroups) == 1 {
if ngCount := ngSubset.Len(); ngCount == 1 && clusterConfigFile == "" {
logger.Info("will create 2 separate CloudFormation stacks for cluster itself and the initial nodegroup")
} else {
logger.Info("will create a CloudFormation stack for cluster itself and %d nodegroup stack(s)", len(cfg.NodeGroups))

ngFilter.LogInfo(cfg)
logger.Info("will create a CloudFormation stack for cluster itself and %d nodegroup stack(s)", ngCount)
}
logger.Info("if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=%s --name=%s'", meta.Region, meta.Name)
errs := stackManager.CreateClusterWithNodeGroups()
errs := stackManager.CreateClusterWithNodeGroups(ngSubset)
// read any errors (it only gets non-nil errors)
if len(errs) > 0 {
logger.Info("%d error(s) occurred and cluster hasn't been created properly, you may wish to check CloudFormation console", len(errs))
Expand Down Expand Up @@ -515,7 +434,7 @@ func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, nameArg stri
return err
}

err = checkEachNodeGroup(cfg, func(_ int, ng *api.NodeGroup) error {
err = CheckEachNodeGroup(ngFilter, cfg, func(_ int, ng *api.NodeGroup) error {
// authorise nodes to join
if err = authconfigmap.AddNodeGroup(clientSet, ng); err != nil {
return err
Expand Down
11 changes: 11 additions & 0 deletions pkg/ctl/create/create_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package create_test

import (
"testing"

"github.com/weaveworks/eksctl/pkg/testutils"
)

func TestSuite(t *testing.T) {
testutils.RegisterAndRun(t)
}
Loading

0 comments on commit 5df021d

Please sign in to comment.