Skip to content

Commit

Permalink
Add support for ClusterRoleBinding
Browse files Browse the repository at this point in the history
  • Loading branch information
micahhausler committed Oct 3, 2017
1 parent 6bbc5bc commit 27b29cc
Show file tree
Hide file tree
Showing 7 changed files with 584 additions and 0 deletions.
1 change: 1 addition & 0 deletions kubernetes/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ func Provider() terraform.ResourceProvider {
"kubernetes_service": resourceKubernetesService(),
"kubernetes_service_account": resourceKubernetesServiceAccount(),
"kubernetes_storage_class": resourceKubernetesStorageClass(),
"kubernetes_cluster_role_binding": resourceKubernetesClusterRoleBinding(),
},
ConfigureFunc: providerConfigure,
}
Expand Down
158 changes: 158 additions & 0 deletions kubernetes/resource_kubernetes_cluster_role_binding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package kubernetes

import (
"fmt"
"log"

"github.com/hashicorp/terraform/helper/schema"
"k8s.io/apimachinery/pkg/api/errors"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pkgApi "k8s.io/apimachinery/pkg/types"
api "k8s.io/kubernetes/pkg/apis/rbac/v1"
kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)

func resourceKubernetesClusterRoleBinding() *schema.Resource {
return &schema.Resource{
Create: resourceKubernetesClusterRoleBindingCreate,
Read: resourceKubernetesClusterRoleBindingRead,
Exists: resourceKubernetesClusterRoleBindingExists,
Update: resourceKubernetesClusterRoleBindingUpdate,
Delete: resourceKubernetesClusterRoleBindingDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"metadata": metadataSchema("clusterRoleBinding", false),
"role_ref": {
Type: schema.TypeMap,
Description: "RoleRef references the Cluster Role for this binding",
Required: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: rbacRoleRefSchema("ClusterRole"),
},
},
"subject": {
Type: schema.TypeList,
Description: "Subjects defines the entities to bind a ClusterRole to.",
Required: true,
MinItems: 1,
Elem: &schema.Resource{
Schema: rbacSubjectSchema(),
},
},
},
}
}

func resourceKubernetesClusterRoleBindingCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*kubernetes.Clientset)

metadata := expandMetadata(d.Get("metadata").([]interface{}))
binding := &api.ClusterRoleBinding{
ObjectMeta: metadata,
RoleRef: expandRBACRoleRef(d.Get("role_ref").(interface{})),
Subjects: expandRBACSubjects(d.Get("subject").([]interface{})),
}
log.Printf("[INFO] Creating new ClusterRoleBinding: %#v", binding)
binding, err := conn.Rbac().ClusterRoleBindings().Create(binding)

if err != nil {
return err
}
log.Printf("[INFO] Submitted new ClusterRoleBinding: %#v", binding)
d.SetId(metadata.Name)

return resourceKubernetesClusterRoleBindingRead(d, meta)
}

func resourceKubernetesClusterRoleBindingRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*kubernetes.Clientset)

name := d.Id()
log.Printf("[INFO] Reading ClusterRoleBinding %s", name)
binding, err := conn.Rbac().ClusterRoleBindings().Get(name, meta_v1.GetOptions{})
if err != nil {
log.Printf("[DEBUG] Received error: %#v", err)
return err
}

log.Printf("[INFO] Received ClusterRoleBinding: %#v", binding)
err = d.Set("metadata", flattenMetadata(binding.ObjectMeta))
if err != nil {
return err
}

flattenedRef := flattenRBACRoleRef(binding.RoleRef)
log.Printf("[DEBUG] Flattened ClusterRoleBinding roleRef: %#v", flattenedRef)
err = d.Set("role_ref", flattenedRef)
if err != nil {
return err
}

flattenedSubjects := flattenRBACSubjects(binding.Subjects)
log.Printf("[DEBUG] Flattened ClusterRoleBinding subjects: %#v", flattenedSubjects)
err = d.Set("subject", flattenedSubjects)
if err != nil {
return err
}

return nil
}

func resourceKubernetesClusterRoleBindingUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*kubernetes.Clientset)

name := d.Id()

ops := patchMetadata("metadata.0.", "/metadata/", d)
if d.HasChange("subject") {
diffOps := patchRbacSubject(d)
ops = append(ops, diffOps...)
}
data, err := ops.MarshalJSON()
if err != nil {
return fmt.Errorf("Failed to marshal update operations: %s", err)
}
log.Printf("[INFO] Updating ClusterRoleBinding %q: %v", name, string(data))
out, err := conn.Rbac().ClusterRoleBindings().Patch(name, pkgApi.JSONPatchType, data)
if err != nil {
return fmt.Errorf("Failed to update ClusterRoleBinding: %s", err)
}
log.Printf("[INFO] Submitted updated ClusterRoleBinding: %#v", out)
d.SetId(out.ObjectMeta.Name)

return resourceKubernetesClusterRoleBindingRead(d, meta)
}

func resourceKubernetesClusterRoleBindingDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*kubernetes.Clientset)

name := d.Id()
log.Printf("[INFO] Deleting ClusterRoleBinding: %#v", name)
err := conn.Rbac().ClusterRoleBindings().Delete(name, &meta_v1.DeleteOptions{})
if err != nil {
return err
}
log.Printf("[INFO] ClusterRoleBinding %s deleted", name)

d.SetId("")
return nil
}

func resourceKubernetesClusterRoleBindingExists(d *schema.ResourceData, meta interface{}) (bool, error) {
conn := meta.(*kubernetes.Clientset)

name := d.Id()
log.Printf("[INFO] Checking ClusterRoleBinding %s", name)
_, err := conn.Rbac().ClusterRoleBindings().Get(name, meta_v1.GetOptions{})
if err != nil {
if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
return false, nil
}
log.Printf("[DEBUG] Received error: %#v", err)
}
return true, err
}
179 changes: 179 additions & 0 deletions kubernetes/resource_kubernetes_cluster_role_binding_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package kubernetes

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "k8s.io/kubernetes/pkg/apis/rbac/v1"
kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)

func TestAccKubernetesClusterRoleBinding(t *testing.T) {
var conf api.ClusterRoleBinding
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: "kubernetes_cluster_role_binding.test",
Providers: testAccProviders,
CheckDestroy: testAccCheckKubernetesClusterRoleBindingDestroy,
Steps: []resource.TestStep{
{
Config: testAccKubernetesClusterRoleBindingConfig_basic(name),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckKubernetesClusterRoleBindingExists("kubernetes_cluster_role_binding.test", &conf),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "metadata.0.name", name),
resource.TestCheckResourceAttrSet("kubernetes_cluster_role_binding.test", "metadata.0.generation"),
resource.TestCheckResourceAttrSet("kubernetes_cluster_role_binding.test", "metadata.0.resource_version"),
resource.TestCheckResourceAttrSet("kubernetes_cluster_role_binding.test", "metadata.0.self_link"),
resource.TestCheckResourceAttrSet("kubernetes_cluster_role_binding.test", "metadata.0.uid"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "role_ref.%", "3"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "role_ref.api_group", "rbac.authorization.k8s.io"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "role_ref.kind", "ClusterRole"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "role_ref.name", "cluster-admin"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.#", "1"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.0.api_group", "rbac.authorization.k8s.io"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.0.name", "notauser"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.0.kind", "User"),
),
},
{
Config: testAccKubernetesClusterRoleBindingConfig_modified(name),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckKubernetesClusterRoleBindingExists("kubernetes_cluster_role_binding.test", &conf),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "metadata.0.name", name),
resource.TestCheckResourceAttrSet("kubernetes_cluster_role_binding.test", "metadata.0.generation"),
resource.TestCheckResourceAttrSet("kubernetes_cluster_role_binding.test", "metadata.0.resource_version"),
resource.TestCheckResourceAttrSet("kubernetes_cluster_role_binding.test", "metadata.0.self_link"),
resource.TestCheckResourceAttrSet("kubernetes_cluster_role_binding.test", "metadata.0.uid"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "role_ref.%", "3"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "role_ref.api_group", "rbac.authorization.k8s.io"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "role_ref.kind", "ClusterRole"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "role_ref.name", "cluster-admin"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.#", "3"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.0.api_group", "rbac.authorization.k8s.io"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.0.name", "notauser"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.0.kind", "User"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.1.namespace", "kube-system"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.1.name", "default"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.1.kind", "ServiceAccount"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.2.api_group", "rbac.authorization.k8s.io"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.2.name", "system:masters"),
resource.TestCheckResourceAttr("kubernetes_cluster_role_binding.test", "subject.2.kind", "Group"),
),
},
},
})
}

func TestAccKubernetesClusterRoleBinding_importBasic(t *testing.T) {
resourceName := "kubernetes_cluster_role_binding.test"
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckKubernetesClusterRoleBindingDestroy,
Steps: []resource.TestStep{
{
Config: testAccKubernetesClusterRoleBindingConfig_basic(name),
},

{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckKubernetesClusterRoleBindingDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*kubernetes.Clientset)

for _, rs := range s.RootModule().Resources {
if rs.Type != "kubernetes_cluster_role_binding" {
continue
}
name := rs.Primary.ID
resp, err := conn.Rbac().ClusterRoleBindings().Get(name, meta_v1.GetOptions{})
if err == nil {
if resp.Name == rs.Primary.ID {
return fmt.Errorf("ClusterRoleBinding still exists: %s", rs.Primary.ID)
}
}
}

return nil
}

func testAccCheckKubernetesClusterRoleBindingExists(n string, obj *api.ClusterRoleBinding) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

conn := testAccProvider.Meta().(*kubernetes.Clientset)
name := rs.Primary.ID
resp, err := conn.Rbac().ClusterRoleBindings().Get(name, meta_v1.GetOptions{})
if err != nil {
return err
}

*obj = *resp
return nil
}
}

func testAccKubernetesClusterRoleBindingConfig_basic(name string) string {
return fmt.Sprintf(`
resource "kubernetes_cluster_role_binding" "test" {
metadata {
name = "%s"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = "cluster-admin"
}
subject {
kind = "User"
name = "notauser"
api_group = "rbac.authorization.k8s.io"
}
}`, name)
}

func testAccKubernetesClusterRoleBindingConfig_modified(name string) string {
return fmt.Sprintf(`
resource "kubernetes_cluster_role_binding" "test" {
metadata {
name = "%s"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = "cluster-admin"
}
subject {
kind = "User"
name = "notauser"
api_group = "rbac.authorization.k8s.io"
}
subject {
kind = "ServiceAccount"
name = "default"
namespace = "kube-system"
}
subject {
kind = "Group"
name = "system:masters"
api_group = "rbac.authorization.k8s.io"
}
}`, name)
}

0 comments on commit 27b29cc

Please sign in to comment.