Skip to content

Commit 323d169

Browse files
committed
Added exporter for IP Access Lists
1 parent c6acf4c commit 323d169

File tree

6 files changed

+172
-31
lines changed

6 files changed

+172
-31
lines changed

access/resource_ipaccesslist.go

+13-14
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
1010
)
1111

12-
type listIPAccessListsResponse struct {
13-
ListIPAccessListsResponse []ipAccessListStatus `json:"ip_access_lists,omitempty"`
12+
type ListIPAccessListsResponse struct {
13+
ListIPAccessListsResponse []IpAccessListStatus `json:"ip_access_lists,omitempty"`
1414
}
1515

1616
type createIPAccessListRequest struct {
@@ -19,7 +19,7 @@ type createIPAccessListRequest struct {
1919
IPAddresses []string `json:"ip_addresses"`
2020
}
2121

22-
type ipAccessListStatus struct {
22+
type IpAccessListStatus struct {
2323
ListID string `json:"list_id"`
2424
Label string `json:"label"`
2525
ListType string `json:"list_type"`
@@ -32,15 +32,15 @@ type ipAccessListStatus struct {
3232
Enabled bool `json:"enabled,omitempty"`
3333
}
3434

35-
type ipAccessListStatusWrapper struct {
36-
IPAccessList ipAccessListStatus `json:"ip_access_list,omitempty"`
35+
type IpAccessListStatusWrapper struct {
36+
IPAccessList IpAccessListStatus `json:"ip_access_list,omitempty"`
3737
}
3838

3939
type ipAccessListUpdateRequest struct {
4040
Label string `json:"label"`
4141
ListType string `json:"list_type"`
4242
IPAddresses []string `json:"ip_addresses"`
43-
Enabled bool `json:"enabled,omitempty"`
43+
Enabled bool `json:"enabled,omitempty" tf:"default:true"`
4444
}
4545

4646
// Preview feature: https://docs.databricks.com/security/network/ip-access-list.html
@@ -59,8 +59,8 @@ func NewIPAccessListsAPI(ctx context.Context, m interface{}) ipAccessListsAPI {
5959
}
6060

6161
// Create creates the IP Access List to given the instance pool configuration
62-
func (a ipAccessListsAPI) Create(cr createIPAccessListRequest) (status ipAccessListStatus, err error) {
63-
wrapper := ipAccessListStatusWrapper{}
62+
func (a ipAccessListsAPI) Create(cr createIPAccessListRequest) (status IpAccessListStatus, err error) {
63+
wrapper := IpAccessListStatusWrapper{}
6464
err = a.client.Post(a.context, "/ip-access-lists", cr, &wrapper)
6565
if err != nil {
6666
return
@@ -78,16 +78,16 @@ func (a ipAccessListsAPI) Delete(objectID string) (err error) {
7878
return
7979
}
8080

81-
func (a ipAccessListsAPI) Read(objectID string) (status ipAccessListStatus, err error) {
82-
wrapper := ipAccessListStatusWrapper{}
81+
func (a ipAccessListsAPI) Read(objectID string) (status IpAccessListStatus, err error) {
82+
wrapper := IpAccessListStatusWrapper{}
8383
err = a.client.Get(a.context, "/ip-access-lists/"+objectID, nil, &wrapper)
8484
status = wrapper.IPAccessList
8585
return
8686
}
8787

88-
func (a ipAccessListsAPI) List() (listResponse listIPAccessListsResponse, err error) {
89-
listResponse = listIPAccessListsResponse{}
90-
err = a.client.Get(a.context, "/ip-access-lists", &listResponse, nil)
88+
func (a ipAccessListsAPI) List() (listResponse ListIPAccessListsResponse, err error) {
89+
listResponse = ListIPAccessListsResponse{}
90+
err = a.client.Get(a.context, "/ip-access-lists", nil, &listResponse)
9191
return
9292
}
9393

@@ -100,7 +100,6 @@ func ResourceIPAccessList() *schema.Resource {
100100
Type: schema.TypeString,
101101
ValidateFunc: validation.Any(validation.IsIPv4Address, validation.IsCIDR),
102102
}
103-
s["enabled"].Default = true
104103
return s
105104
})
106105
return common.Resource{

access/resource_ipaccesslist_test.go

+27-10
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ func TestIPACLCreate(t *testing.T) {
6666
ListType: TestingListType,
6767
IPAddresses: TestingIPAddresses,
6868
},
69-
Response: ipAccessListStatusWrapper{
70-
IPAccessList: ipAccessListStatus{
69+
Response: IpAccessListStatusWrapper{
70+
IPAccessList: IpAccessListStatus{
7171
ListID: TestingID,
7272
Label: TestingLabel,
7373
ListType: TestingListType,
@@ -84,8 +84,8 @@ func TestIPACLCreate(t *testing.T) {
8484
{
8585
Method: http.MethodGet,
8686
Resource: "/api/2.0/ip-access-lists/" + TestingID,
87-
Response: ipAccessListStatusWrapper{
88-
IPAccessList: ipAccessListStatus{
87+
Response: IpAccessListStatusWrapper{
88+
IPAccessList: IpAccessListStatus{
8989
ListID: TestingID,
9090
Label: TestingLabel,
9191
ListType: TestingListType,
@@ -148,8 +148,8 @@ func TestIPACLUpdate(t *testing.T) {
148148
{
149149
Method: http.MethodGet,
150150
Resource: "/api/2.0/ip-access-lists/" + TestingID,
151-
Response: ipAccessListStatusWrapper{
152-
IPAccessList: ipAccessListStatus{
151+
Response: IpAccessListStatusWrapper{
152+
IPAccessList: IpAccessListStatus{
153153
ListID: TestingID,
154154
Label: TestingLabel,
155155
ListType: TestingListType,
@@ -166,8 +166,8 @@ func TestIPACLUpdate(t *testing.T) {
166166
{
167167
Method: http.MethodPut,
168168
Resource: "/api/2.0/ip-access-lists/" + TestingID,
169-
Response: ipAccessListStatusWrapper{
170-
IPAccessList: ipAccessListStatus{
169+
Response: IpAccessListStatusWrapper{
170+
IPAccessList: IpAccessListStatus{
171171
ListID: TestingID,
172172
Label: TestingLabel,
173173
ListType: TestingListType,
@@ -225,8 +225,8 @@ func TestIPACLRead(t *testing.T) {
225225
{
226226
Method: http.MethodGet,
227227
Resource: "/api/2.0/ip-access-lists/" + TestingID,
228-
Response: ipAccessListStatusWrapper{
229-
IPAccessList: ipAccessListStatus{
228+
Response: IpAccessListStatusWrapper{
229+
IPAccessList: IpAccessListStatus{
230230
ListID: TestingID,
231231
Label: TestingLabel,
232232
ListType: TestingListType,
@@ -333,3 +333,20 @@ func TestIPACLDelete_Error(t *testing.T) {
333333
qa.AssertErrorStartsWith(t, err, "IP access list is not available in ")
334334
assert.Equal(t, TestingID, d.Id())
335335
}
336+
337+
func TestListIpAccessLists(t *testing.T) {
338+
client, server, err := qa.HttpFixtureClient(t, []qa.HTTPFixture{
339+
{
340+
Method: "GET",
341+
Resource: "/api/2.0/ip-access-lists",
342+
Response: map[string]interface{}{},
343+
},
344+
})
345+
defer server.Close()
346+
require.NoError(t, err)
347+
348+
ctx := context.Background()
349+
ipLists, err := NewIPAccessListsAPI(ctx, client).List()
350+
require.NoError(t, err)
351+
assert.Equal(t, len(ipLists.ListIPAccessListsResponse), 0)
352+
}

docs/resources/ip_access_list.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The following arguments are supported:
3232

3333
* `list_type` - Can only be "ALLOW" or "BLOCK"
3434
* `ip_addresses` - This is a field to allow the group to have instance pool create priviliges.
35-
* `label` - (Optional) This is the display name for the given IP ACL List.
35+
* `label` - This is the display name for the given IP ACL List.
3636
* `enabled` - (Optional) Boolean `true` or `false` indicating whether this list should be active. Defaults to `true`
3737

3838
## Attribute Reference

exporter/command.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func Run(args ...string) error {
6565
"Items with older than activity specified won't be imported.")
6666
flags.BoolVar(&ic.debug, "debug", false, "Print extra debug information.")
6767
flags.BoolVar(&ic.mounts, "mounts", false, "List DBFS mount points.")
68-
flags.BoolVar(&ic.generateDeclaration, "generateProviderDeclaration", false,
68+
flags.BoolVar(&ic.generateDeclaration, "generateProviderDeclaration", true,
6969
"Generate Databricks provider declaration (for Terraform >= 0.13).")
7070
services, listing := ic.allServicesAndListing()
7171
flags.StringVar(&ic.services, "services", services,

exporter/exporter_test.go

+75
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"testing"
1111
"time"
1212

13+
"github.com/databrickslabs/terraform-provider-databricks/access"
1314
"github.com/databrickslabs/terraform-provider-databricks/aws"
1415
"github.com/databrickslabs/terraform-provider-databricks/clusters"
1516
"github.com/databrickslabs/terraform-provider-databricks/commands"
@@ -210,12 +211,19 @@ var emptyGitCredentials = qa.HTTPFixture{
210211
Response: repos.GitCredentialList{},
211212
}
212213

214+
var emptyIpAccessLIst = qa.HTTPFixture{
215+
Method: http.MethodGet,
216+
Resource: "/api/2.0/ip-access-lists",
217+
Response: map[string]interface{}{},
218+
}
219+
213220
func TestImportingUsersGroupsSecretScopes(t *testing.T) {
214221
qa.HTTPFixturesApply(t,
215222
[]qa.HTTPFixture{
216223
meAdminFixture,
217224
repoListFixture,
218225
emptyGitCredentials,
226+
emptyIpAccessLIst,
219227
{
220228
Method: "GET",
221229
Resource: "/api/2.0/preview/scim/v2/Groups?",
@@ -375,6 +383,7 @@ func TestImportingNoResourcesError(t *testing.T) {
375383
Response: scim.GroupList{Resources: []scim.Group{}},
376384
},
377385
emptyGitCredentials,
386+
emptyIpAccessLIst,
378387
{
379388
Method: "GET",
380389
Resource: "/api/2.0/global-init-scripts",
@@ -1069,3 +1078,69 @@ func TestImportingGitCredentials_Error(t *testing.T) {
10691078
assert.Error(t, err)
10701079
})
10711080
}
1081+
1082+
func TestImportingIPAccessLists(t *testing.T) {
1083+
resp := access.IpAccessListStatus{
1084+
ListID: "123",
1085+
Label: "block_list",
1086+
ListType: "BLOCK",
1087+
IPAddresses: []string{"1.2.3.4"},
1088+
AddressCount: 2,
1089+
Enabled: true,
1090+
}
1091+
resp2 := resp
1092+
resp2.IPAddresses = []string{}
1093+
resp2.ListID = "124"
1094+
qa.HTTPFixturesApply(t,
1095+
[]qa.HTTPFixture{
1096+
meAdminFixture,
1097+
repoListFixture,
1098+
{
1099+
Method: "GET",
1100+
Resource: "/api/2.0/global-init-scripts",
1101+
Response: map[string]interface{}{},
1102+
},
1103+
{
1104+
Method: "GET",
1105+
Resource: "/api/2.0/ip-access-lists",
1106+
Response: access.ListIPAccessListsResponse{
1107+
ListIPAccessListsResponse: []access.IpAccessListStatus{resp, resp2},
1108+
},
1109+
},
1110+
{
1111+
Method: "GET",
1112+
Resource: "/api/2.0/ip-access-lists/123",
1113+
Response: access.IpAccessListStatusWrapper{
1114+
IPAccessList: resp,
1115+
},
1116+
},
1117+
{
1118+
Method: "GET",
1119+
Resource: "/api/2.0/ip-access-lists/124",
1120+
Response: access.IpAccessListStatusWrapper{
1121+
IPAccessList: resp2,
1122+
},
1123+
},
1124+
{
1125+
Method: "GET",
1126+
Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists%2CmaxTokenLifetimeDays%2CenableTokensConfig",
1127+
Response: map[string]interface{}{
1128+
"enableIpAccessLists": "true",
1129+
"maxTokenLifetimeDays": nil,
1130+
"enableTokensConfig": "true",
1131+
},
1132+
},
1133+
},
1134+
func(ctx context.Context, client *common.DatabricksClient) {
1135+
tmpDir := fmt.Sprintf("/tmp/tf-%s", qa.RandomName())
1136+
defer os.RemoveAll(tmpDir)
1137+
1138+
ic := newImportContext(client)
1139+
ic.Directory = tmpDir
1140+
ic.listing = "workspace,access"
1141+
ic.services = "workspace,access"
1142+
1143+
err := ic.Run()
1144+
assert.NoError(t, err)
1145+
})
1146+
}

exporter/importables.go

+55-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212
"time"
1313

14+
"github.com/databrickslabs/terraform-provider-databricks/access"
1415
"github.com/databrickslabs/terraform-provider-databricks/clusters"
1516
"github.com/databrickslabs/terraform-provider-databricks/common"
1617
"github.com/databrickslabs/terraform-provider-databricks/jobs"
@@ -28,11 +29,12 @@ import (
2829
)
2930

3031
var (
31-
adlsGen2Regex = regexp.MustCompile(`^(abfss?)://([^@]+)@([^.]+)\.(?:[^/]+)(/.*)?$`)
32-
adlsGen1Regex = regexp.MustCompile(`^(adls?)://([^.]+)\.(?:[^/]+)(/.*)?$`)
33-
wasbsRegex = regexp.MustCompile(`^(wasbs?)://([^@]+)@([^.]+)\.(?:[^/]+)(/.*)?$`)
34-
s3Regex = regexp.MustCompile(`^(s3a?)://([^/]+)(/.*)?$`)
35-
gsRegex = regexp.MustCompile(`^gs://([^/]+)(/.*)?$`)
32+
adlsGen2Regex = regexp.MustCompile(`^(abfss?)://([^@]+)@([^.]+)\.(?:[^/]+)(/.*)?$`)
33+
adlsGen1Regex = regexp.MustCompile(`^(adls?)://([^.]+)\.(?:[^/]+)(/.*)?$`)
34+
wasbsRegex = regexp.MustCompile(`^(wasbs?)://([^@]+)@([^.]+)\.(?:[^/]+)(/.*)?$`)
35+
s3Regex = regexp.MustCompile(`^(s3a?)://([^/]+)(/.*)?$`)
36+
gsRegex = regexp.MustCompile(`^gs://([^/]+)(/.*)?$`)
37+
globalWorkspaceConfName = "global_workspace_conf"
3638
)
3739

3840
func generateMountBody(ic *importContext, body *hclwrite.Body, r *resource) error {
@@ -846,4 +848,52 @@ var resourcesMap map[string]importable = map[string]importable{
846848
return nil
847849
},
848850
},
851+
"databricks_workspace_conf": {
852+
Service: "workspace",
853+
Name: func(d *schema.ResourceData) string {
854+
return globalWorkspaceConfName
855+
},
856+
Import: func(ic *importContext, r *resource) error {
857+
wsConfAPI := workspace.NewWorkspaceConfAPI(ic.Context, ic.Client)
858+
keys := map[string]interface{}{"enableIpAccessLists": false, "maxTokenLifetimeDays": 0, "enableTokensConfig": false}
859+
err := wsConfAPI.Read(&keys)
860+
if err != nil {
861+
return err
862+
}
863+
r.Data.Set("custom_config", keys)
864+
return nil
865+
},
866+
},
867+
"databricks_ip_access_list": {
868+
Service: "access",
869+
Name: func(d *schema.ResourceData) string {
870+
return d.Get("list_type").(string) + "_" + d.Get("label").(string)
871+
},
872+
List: func(ic *importContext) error {
873+
ipListsResp, err := access.NewIPAccessListsAPI(ic.Context, ic.Client).List()
874+
if err != nil {
875+
return err
876+
}
877+
ipLists := ipListsResp.ListIPAccessListsResponse
878+
for offset, ipList := range ipLists {
879+
ic.Emit(&resource{
880+
Resource: "databricks_ip_access_list",
881+
ID: ipList.ListID,
882+
})
883+
log.Printf("[INFO] Scanned %d of %d IP Access Lists", offset+1, len(ipLists))
884+
}
885+
if len(ipLists) > 0 {
886+
ic.Emit(&resource{
887+
Resource: "databricks_workspace_conf",
888+
ID: globalWorkspaceConfName,
889+
Data: ic.Resources["databricks_workspace_conf"].Data(
890+
&terraform.InstanceState{
891+
ID: globalWorkspaceConfName,
892+
Attributes: map[string]string{},
893+
}),
894+
})
895+
}
896+
return nil
897+
},
898+
},
849899
}

0 commit comments

Comments
 (0)