Skip to content

Commit

Permalink
Added databricks_cluster_policy resource
Browse files Browse the repository at this point in the history
  • Loading branch information
nfx committed Jun 22, 2020
1 parent c343db6 commit b1831ac
Show file tree
Hide file tree
Showing 7 changed files with 445 additions and 0 deletions.
84 changes: 84 additions & 0 deletions client/model/cluster_policies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package model

import (
"encoding/json"
"fmt"

"github.com/pkg/errors"
)

// AttributePolicy defines JSON mapping for attribute policy
type AttributePolicy struct {
Path *string `json:"-"`
Type string `json:"type"`
Value interface{} `json:"value,omitempty"`
DefaultValue interface{} `json:"defaultValue,omitempty"`
Values []interface{} `json:"values,omitempty"`
Hidden bool `json:"hidden,omitempty"`
IsOptional bool `json:"isOptional,omitempty"`
Pattern string `json:"pattern,omitempty"`
MinValue int `json:"minValue,omitempty"`
MaxValue int `json:"maxValue,omitempty"`
}

// ClusterPolicy defines cluster policy
type ClusterPolicy struct {
PolicyID string `json:"policy_id,omitempty"`
Name string `json:"name"`
Definition string `json:"definition"`
CreatedAtTimeStamp int64 `json:"created_at_timestamp"`

Attributes map[string]*AttributePolicy
}

// ParseDefinition parses policy definition
func (clusterPolicy *ClusterPolicy) ParseDefinition(definition string) error {
clusterPolicy.Definition = definition

err := json.Unmarshal([]byte(definition), &clusterPolicy.Attributes)
if err != nil {
return err
}

return nil
}

// ClusterPolicyCreate is the endity used for request
type ClusterPolicyCreate struct {
Name string `json:"name"`
Definition string `json:"definition"`
}

// // Prepare sets definition from attributes
// func (clusterPolicy *ClusterPolicy) Prepare() ([]byte, error) {
// policyJSONBytes, err := json.Marshal(clusterPolicy.attributes)
// if err != nil {
// return nil, errors.Wrapf(err, "Problem serializing %s policy", clusterPolicy.Name)
// }
// clusterPolicy.Definition = string(policyJSONBytes)
// }

// MarshalJSON is called when json.Marshal is invoked
func (clusterPolicy *ClusterPolicy) MarshalJSON() ([]byte, error) {
policyJSONBytes, err := json.Marshal(clusterPolicy.Attributes)
if err != nil {
return nil, errors.Wrapf(err, "Problem serializing %s policy", clusterPolicy.Name)
}
clusterPolicy.Definition = string(policyJSONBytes)
return json.Marshal(&struct {
PolicyID string `json:"policy_id,omitempty"`
Name string `json:"name"`
Definition string `json:"definition"`
}{
clusterPolicy.PolicyID, clusterPolicy.Name, clusterPolicy.Definition,
})
}

// ToString returns debug JSON, ignoring errors
func (clusterPolicy *ClusterPolicy) ToString() string {
j, err := clusterPolicy.MarshalJSON()
if err != nil {
return ""
}
return fmt.Sprintf("%s", j)
}
5 changes: 5 additions & 0 deletions client/service/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ func (c *DBApiClient) Clusters() ClustersAPI {
return ClustersAPI{Client: c}
}

// ClusterPolicies returns an instance of ClusterPoliciesAPI
func (c *DBApiClient) ClusterPolicies() ClusterPoliciesAPI {
return ClusterPoliciesAPI{Client: c}
}

// Secrets returns an instance of SecretsAPI
func (c *DBApiClient) Secrets() SecretsAPI {
return SecretsAPI{Client: c}
Expand Down
59 changes: 59 additions & 0 deletions client/service/cluster_policies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package service

import (
"encoding/json"
"net/http"

"github.com/databrickslabs/databricks-terraform/client/model"
)

// ClusterPoliciesAPI allows you to create, list, and edit cluster policies.
//
// Creation and editing is available to admins only.
// Listing can be performed by any user and is limited to policies accessible by that user.
type ClusterPoliciesAPI struct {
Client *DBApiClient
}

type policyIDWrapper struct {
PolicyID string `json:"policy_id,omitempty" url:"policy_id,omitempty"`
}

// Create creates new cluster policy and sets PolicyID
func (a ClusterPoliciesAPI) Create(clusterPolicy *model.ClusterPolicy) error {
//clusterPolicyWrapper := &policyWrapper{clusterPolicy.Name, clusterPolicy.Definition}
resp, err := a.Client.performQuery(http.MethodPost, "/policies/clusters/create", "2.0", nil, clusterPolicy, nil)
if err != nil {
return err
}
var policyIDResponse = new(policyIDWrapper)
err = json.Unmarshal(resp, &policyIDResponse)
clusterPolicy.PolicyID = policyIDResponse.PolicyID
return err
}

// Edit will update an existing policy.
// This may make some clusters governed by this policy invalid.
// For such clusters the next cluster edit must provide a confirming configuration,
// but otherwise they can continue to run.
func (a ClusterPoliciesAPI) Edit(clusterPolicy *model.ClusterPolicy) error {
_, err := a.Client.performQuery(http.MethodPost, "/policies/clusters/edit", "2.0", nil, clusterPolicy, nil)
return err
}

// Get returns cluster policy
func (a ClusterPoliciesAPI) Get(policyID string) (*model.ClusterPolicy, error) {
var clusterPolicy model.ClusterPolicy
resp, err := a.Client.performQuery(http.MethodGet, "/policies/clusters/get", "2.0", nil, policyIDWrapper{policyID}, nil)
if err != nil {
return nil, err
}
err = json.Unmarshal(resp, &clusterPolicy)
return &clusterPolicy, err
}

// Delete removes cluster policy
func (a ClusterPoliciesAPI) Delete(policyID string) error {
_, err := a.Client.performQuery(http.MethodPost, "/policies/clusters/delete", "2.0", nil, policyIDWrapper{policyID}, nil)
return err
}
1 change: 1 addition & 0 deletions databricks/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func Provider(version string) terraform.ResourceProvider {
"databricks_group_member": resourceGroupMember(),
"databricks_notebook": resourceNotebook(),
"databricks_cluster": resourceCluster(),
"databricks_cluster_policy": resourceClusterPolicy(),
"databricks_job": resourceJob(),
"databricks_dbfs_file": resourceDBFSFile(),
"databricks_dbfs_file_sync": resourceDBFSFileSync(),
Expand Down
169 changes: 169 additions & 0 deletions databricks/resource_databricks_cluster_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package databricks

import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"

"github.com/databrickslabs/databricks-terraform/client/model"
"github.com/databrickslabs/databricks-terraform/client/service"
)

func parsePolicyFromData(d *schema.ResourceData) (*model.ClusterPolicy, error) {
clusterPolicy := new(model.ClusterPolicy)
clusterPolicy.PolicyID = d.Id()
if name, ok := d.GetOk("name"); ok {
clusterPolicy.Name = name.(string)
}
if data, ok := d.GetOk("definition"); ok {
err := clusterPolicy.ParseDefinition(data.(string))
if err != nil {
return nil, err
}
}
return clusterPolicy, nil
}

func resourceClusterPolicyCreate(d *schema.ResourceData, m interface{}) error {
client := m.(*service.DBApiClient)
clusterPolicy, err := parsePolicyFromData(d)
if err != nil {
return err
}
err = client.ClusterPolicies().Create(clusterPolicy)
if err != nil {
return err
}
d.SetId(clusterPolicy.PolicyID)
return resourceClusterPolicyRead(d, m)
}

func resourceClusterPolicyRead(d *schema.ResourceData, m interface{}) error {
client := m.(*service.DBApiClient)
clusterPolicy, err := client.ClusterPolicies().Get(d.Id())
if err != nil {
return err
}
err = d.Set("name", clusterPolicy.Name)
if err != nil {
return err
}

err = d.Set("definition", clusterPolicy.Definition)
if err != nil {
return err
}

// err = clusterPolicy.ParseDefinition(clusterPolicy.Definition)
// if err != nil {
// return err
// }
// policies := clusterPolicy.AttributePoliciesState()
// err = d.Set("attribute_policy", policies)
// if err != nil {
// return err
// }
// TODO: add definitions!!!

return nil
}

func resourceClusterPolicyUpdate(d *schema.ResourceData, m interface{}) error {
client := m.(*service.DBApiClient)
clusterPolicy, err := parsePolicyFromData(d)
if err != nil {
return err
}
err = client.ClusterPolicies().Edit(clusterPolicy)
if err != nil {
return err
}
return resourceClusterPolicyRead(d, m)
}

func resourceClusterPolicyDelete(d *schema.ResourceData, m interface{}) error {
id := d.Id()
client := m.(*service.DBApiClient)
return client.ClusterPolicies().Delete(id)
}

func resourceClusterPolicy() *schema.Resource {
return &schema.Resource{
Create: resourceClusterPolicyCreate,
Read: resourceClusterPolicyRead,
Update: resourceClusterPolicyUpdate,
Delete: resourceClusterPolicyDelete,

Schema: map[string]*schema.Schema{
"policy_id": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Required: true,
Description: "Cluster policy name. This must be unique.\n" +
"Length must be between 1 and 100 characters.",
},
"definition": {
Type: schema.TypeString,
Optional: true,
Description: "Policy definition JSON document expressed in\n" +
"Databricks Policy Definition Language.",
ConflictsWith: []string{"attribute_policy"},
},
"attribute_policy": {
Type: schema.TypeList,
Optional: true,
MinItems: 1,
ConflictsWith: []string{"definition"},
ConfigMode: schema.SchemaConfigModeAttr,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Required: true,
},
"path": {
Type: schema.TypeString,
Required: true,
},
"value": { // type: fixed
Type: schema.TypeString,
Optional: true,
},
"default_value": { // type: limiting
Type: schema.TypeString,
Optional: true,
},
"values": { // type: limiting
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"hidden": { // type: fixed
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"is_optional": { // type: limiting
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"pattern": { // type: regex
Type: schema.TypeString,
Optional: true,
},
"min_value": { // type: range
Type: schema.TypeInt,
Optional: true,
},
"max_value": { // type: range
Type: schema.TypeInt,
Optional: true,
},
},
},
},
},
}
}
Loading

0 comments on commit b1831ac

Please sign in to comment.