-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #528 from tiffanyfay/cfgmap-ng-delete
Cfgmap ng delete
- Loading branch information
Showing
13 changed files
with
376 additions
and
178 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
package authconfigmap | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/kris-nova/logger" | ||
"github.com/pkg/errors" | ||
|
||
api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha4" | ||
|
||
yaml "gopkg.in/yaml.v2" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
kerr "k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
clientset "k8s.io/client-go/kubernetes" | ||
) | ||
|
||
type mapRolesData []map[string]interface{} | ||
|
||
const ( | ||
objectName = "aws-auth" | ||
objectNamespace = "kube-system" | ||
) | ||
|
||
// ObjectMeta constructs metadata for the configmap | ||
func ObjectMeta() metav1.ObjectMeta { | ||
return metav1.ObjectMeta{ | ||
Name: objectName, | ||
Namespace: objectNamespace, | ||
} | ||
} | ||
|
||
func makeMapRolesData() mapRolesData { return []map[string]interface{}{} } | ||
|
||
func appendNodeRole(mapRoles *mapRolesData, ngInstanceRoleARN string) { | ||
newEntry := map[string]interface{}{ | ||
"rolearn": ngInstanceRoleARN, | ||
"username": "system:node:{{EC2PrivateDNSName}}", | ||
"groups": []string{ | ||
"system:bootstrappers", | ||
"system:nodes", | ||
}, | ||
} | ||
*mapRoles = append(*mapRoles, newEntry) | ||
} | ||
|
||
func new(mapRoles *mapRolesData) (*corev1.ConfigMap, error) { | ||
mapRolesBytes, err := yaml.Marshal(*mapRoles) | ||
if err != nil { | ||
return nil, err | ||
} | ||
cm := &corev1.ConfigMap{ | ||
ObjectMeta: ObjectMeta(), | ||
Data: map[string]string{ | ||
"mapRoles": string(mapRolesBytes), | ||
}, | ||
} | ||
return cm, nil | ||
} | ||
|
||
func update(cm *corev1.ConfigMap, mapRoles *mapRolesData) error { | ||
mapRolesBytes, err := yaml.Marshal(*mapRoles) | ||
if err != nil { | ||
return err | ||
} | ||
cm.Data["mapRoles"] = string(mapRolesBytes) | ||
return nil | ||
} | ||
|
||
// NewForRole creates ConfigMap with a single role ARN | ||
func NewForRole(arn string) (*corev1.ConfigMap, error) { | ||
mapRoles := makeMapRolesData() | ||
appendNodeRole(&mapRoles, arn) | ||
return new(&mapRoles) | ||
} | ||
|
||
// AddRole updates ConfigMap by appending a single nodegroup ARN | ||
func AddRole(cm *corev1.ConfigMap, arn string) error { | ||
mapRoles := makeMapRolesData() | ||
if err := yaml.Unmarshal([]byte(cm.Data["mapRoles"]), &mapRoles); err != nil { | ||
return err | ||
} | ||
appendNodeRole(&mapRoles, arn) | ||
return update(cm, &mapRoles) | ||
} | ||
|
||
// AddNodeGroup creates or adds a nodegroup IAM role in the auth config map for the given nodegroup | ||
func AddNodeGroup(clientSet *clientset.Clientset, ng *api.NodeGroup) error { | ||
cm := &corev1.ConfigMap{} | ||
client := clientSet.CoreV1().ConfigMaps(objectNamespace) | ||
create := false | ||
|
||
// check if object exists | ||
if existing, err := client.Get(objectName, metav1.GetOptions{}); err != nil { | ||
if kerr.IsNotFound(err) { | ||
create = true // doesn't exsits, will create | ||
} else { | ||
// something must have gone terribly wrong | ||
return errors.Wrapf(err, "getting auth ConfigMap") | ||
} | ||
} else { | ||
*cm = *existing // use existing object | ||
} | ||
|
||
if create { | ||
// build new object with the given role | ||
cm, err := NewForRole(ng.IAM.InstanceRoleARN) | ||
if err != nil { | ||
return errors.Wrap(err, "constructing auth ConfigMap") | ||
} | ||
// and create it in the cluster | ||
if _, err := client.Create(cm); err != nil { | ||
return errors.Wrap(err, "creating auth ConfigMap") | ||
} | ||
logger.Debug("created auth ConfigMap for %s", ng.Name) | ||
return nil | ||
} | ||
|
||
// in case we already have an onject, and the given role to it | ||
if err := AddRole(cm, ng.IAM.InstanceRoleARN); err != nil { | ||
return errors.Wrap(err, "creating an update for auth ConfigMap") | ||
} | ||
// and update it in the cluster | ||
if _, err := client.Update(cm); err != nil { | ||
return errors.Wrap(err, "updating auth ConfigMap") | ||
} | ||
logger.Debug("updated auth ConfigMap for %s", ng.Name) | ||
return nil | ||
} | ||
|
||
func doRemoveRole(mapRoles *mapRolesData, arn string) (mapRolesData, error) { | ||
found := false | ||
mapRolesUpdated := makeMapRolesData() | ||
|
||
for _, role := range *mapRoles { | ||
if role["rolearn"] == arn && !found { | ||
found = true | ||
logger.Info("removing %s from config map", arn) | ||
} else { | ||
mapRolesUpdated = append(mapRolesUpdated, role) | ||
} | ||
} | ||
|
||
if !found { | ||
return nil, fmt.Errorf("instance role ARN %s not found in config map", arn) | ||
} | ||
|
||
return mapRolesUpdated, nil | ||
} | ||
|
||
// RemoveRole removes a nodegroup's instance mapped role from the config map | ||
func RemoveRole(cm *corev1.ConfigMap, ngInstanceRoleARN string) error { | ||
if ngInstanceRoleARN == "" { | ||
return errors.New("config map is unchanged as the nodegroup instance ARN is not set") | ||
} | ||
mapRoles := makeMapRolesData() | ||
|
||
if err := yaml.Unmarshal([]byte(cm.Data["mapRoles"]), &mapRoles); err != nil { | ||
return err | ||
} | ||
mapRolesUpdated, err := doRemoveRole(&mapRoles, ngInstanceRoleARN) | ||
if err != nil { | ||
return err | ||
} | ||
return update(cm, &mapRolesUpdated) | ||
} | ||
|
||
// RemoveNodeGroup removes a nodegroup from the config map and does a client update | ||
func RemoveNodeGroup(clientSet *clientset.Clientset, ng *api.NodeGroup) error { | ||
client := clientSet.CoreV1().ConfigMaps(objectNamespace) | ||
|
||
cm, err := client.Get(objectName, metav1.GetOptions{}) | ||
if err != nil { | ||
return errors.Wrapf(err, "getting auth ConfigMap") | ||
} | ||
|
||
if err := RemoveRole(cm, ng.IAM.InstanceRoleARN); err != nil { | ||
return errors.Wrapf(err, "removing nodegroup from auth ConfigMap") | ||
} | ||
if _, err := client.Update(cm); err != nil { | ||
return errors.Wrap(err, "updating auth ConfigMap and removing instance role") | ||
} | ||
logger.Debug("updated auth ConfigMap for %s", ng.Name) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package authconfigmap_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/weaveworks/eksctl/pkg/testutils" | ||
) | ||
|
||
func TestSuite(t *testing.T) { | ||
testutils.RegisterAndRun(t) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package authconfigmap_test | ||
|
||
import ( | ||
"strings" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
|
||
. "github.com/weaveworks/eksctl/pkg/authconfigmap" | ||
) | ||
|
||
var _ = Describe("Auth ConfigMap", func() { | ||
Describe("create new ConfigMap", func() { | ||
|
||
cm, err := NewForRole("arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng1-p-NodeInstanceRole-NNH3ISP12CX") | ||
|
||
expected := []string{ | ||
`- username: 'system:node:{{EC2PrivateDNSName}}'`, | ||
` groups: [ 'system:bootstrappers', 'system:nodes' ]`, | ||
` rolearn: 'arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng1-p-NodeInstanceRole-NNH3ISP12CX'`, | ||
} | ||
|
||
It("should create correct configuration for a new nodegroup", func() { | ||
Expect(err).To(Not(HaveOccurred())) | ||
Expect(cm).To(Not(BeNil())) | ||
|
||
Expect(cm.ObjectMeta).To(Equal(ObjectMeta())) | ||
|
||
Expect(cm.Data).To(HaveKey("mapRoles")) | ||
Expect(cm.Data["mapRoles"]).To(MatchYAML(strings.Join(expected, "\n"))) | ||
}) | ||
It("should add a new node group ARN to the configmap", func() { | ||
err = AddRole(cm, "arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng2-p-NodeInstanceRole-1L35GCVYSTW4E") | ||
|
||
Expect(err).To(Not(HaveOccurred())) | ||
Expect(cm).To(Not(BeNil())) | ||
|
||
expected = append(expected, | ||
`- username: 'system:node:{{EC2PrivateDNSName}}'`, | ||
` groups: [ 'system:bootstrappers', 'system:nodes' ]`, | ||
` rolearn: 'arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng2-p-NodeInstanceRole-1L35GCVYSTW4E'`, | ||
) | ||
|
||
Expect(cm.ObjectMeta).To(Equal(ObjectMeta())) | ||
|
||
Expect(cm.Data).To(HaveKey("mapRoles")) | ||
Expect(cm.Data["mapRoles"]).To(MatchYAML(strings.Join(expected, "\n"))) | ||
}) | ||
|
||
It("should remove arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng2-p-NodeInstanceRole-1L35GCVYSTW4E from ConfigMap", func() { | ||
err = RemoveRole(cm, "arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng2-p-NodeInstanceRole-1L35GCVYSTW4E") | ||
|
||
Expect(err).To(Not(HaveOccurred())) | ||
Expect(cm).To(Not(BeNil())) | ||
|
||
expected = []string{ | ||
`- username: 'system:node:{{EC2PrivateDNSName}}'`, | ||
` groups: [ 'system:bootstrappers', 'system:nodes' ]`, | ||
` rolearn: 'arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng1-p-NodeInstanceRole-NNH3ISP12CX'`, | ||
} | ||
|
||
Expect(cm.ObjectMeta).To(Equal(ObjectMeta())) | ||
|
||
Expect(cm.Data).To(HaveKey("mapRoles")) | ||
Expect(cm.Data["mapRoles"]).To(MatchYAML(strings.Join(expected, "\n"))) | ||
}) | ||
|
||
It("should fail if an role ARN is is not in the config map", func() { | ||
err = RemoveRole(cm, "arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng1-p-NodeInstanceRole-ABCDEFGH'") | ||
|
||
Expect(err).To(HaveOccurred()) | ||
Expect(cm.Data["mapRoles"]).To(MatchYAML(strings.Join(expected, "\n"))) | ||
}) | ||
|
||
It("should remove arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng1-p-NodeInstanceRole-NNH3ISP12CX and make mapRoles be []", func() { | ||
err = RemoveRole(cm, "arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng1-p-NodeInstanceRole-NNH3ISP12CX") | ||
|
||
Expect(err).To(Not(HaveOccurred())) | ||
Expect(cm).To(Not(BeNil())) | ||
|
||
Expect(cm.ObjectMeta).To(Equal(ObjectMeta())) | ||
|
||
Expect(cm.Data).To(HaveKey("mapRoles")) | ||
Expect(cm.Data["mapRoles"]).To(MatchYAML("[]")) | ||
}) | ||
|
||
It("should fail if you try removing a role when the mapRole is empty", func() { | ||
err = RemoveRole(cm, "arn:aws:iam::122333:role/eksctl-cluster-5a-nodegroup-ng1-p-NodeInstanceRole-ABCDEFGH'") | ||
|
||
Expect(err).To(HaveOccurred()) | ||
Expect(cm.Data).To(HaveKey("mapRoles")) | ||
Expect(cm.Data["mapRoles"]).To(MatchYAML("[]")) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.