Skip to content

Commit

Permalink
Deprecate Whitelist for IBM-cloud-databases. Introduce allowlisting (#…
Browse files Browse the repository at this point in the history
…3852)

* works with local vendor changes.

* working using cloud databases v5 now

* updated deprecation message

* data_source_ibm_database and some tests

* modified the rest of the resource tests

* fixed calling d.getOK for computed variable

* potential import issue fix

* added migration test

* fixed migration bug

* fixed allowlist removal bug

* setting import state verify to false due to terraform bug

* removed extra logs

* updated docs
  • Loading branch information
omaraibrahim authored Nov 3, 2022
1 parent b44c380 commit ccf0ae0
Show file tree
Hide file tree
Showing 16 changed files with 464 additions and 102 deletions.
27 changes: 27 additions & 0 deletions ibm/flex/structures.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/IBM-Cloud/bluemix-go/models"
"github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1"
"github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns"
"github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5"
"github.com/IBM/go-sdk-core/v5/core"
"github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1"
"github.com/IBM/ibm-cos-sdk-go/service/s3"
Expand Down Expand Up @@ -1652,6 +1653,19 @@ func ExpandWhitelist(whiteList *schema.Set) (whitelist []icdv4.WhitelistEntry) {
return
}

// IBM Cloud Databases
func ExpandAllowlist(allowList *schema.Set) (allowlist []clouddatabasesv5.AllowlistEntry) {
for _, iface := range allowList.List() {
alItem := iface.(map[string]interface{})
alEntry := &clouddatabasesv5.AllowlistEntry{
Address: core.StringPtr(alItem["address"].(string)),
Description: core.StringPtr(alItem["description"].(string)),
}
allowlist = append(allowlist, *alEntry)
}
return
}

// Cloud Internet Services
func FlattenWhitelist(whitelist icdv4.Whitelist) []map[string]interface{} {
entries := make([]map[string]interface{}, len(whitelist.WhitelistEntrys), len(whitelist.WhitelistEntrys))
Expand All @@ -1665,6 +1679,19 @@ func FlattenWhitelist(whitelist icdv4.Whitelist) []map[string]interface{} {
return entries
}

// Cloud Internet Services
func FlattenGetAllowlist(allowlist clouddatabasesv5.GetAllowlistResponse) []map[string]interface{} {
entries := make([]map[string]interface{}, len(allowlist.IPAddresses), len(allowlist.IPAddresses))
for i, allowlistEntry := range allowlist.IPAddresses {
l := map[string]interface{}{
"address": allowlistEntry.Address,
"description": allowlistEntry.Description,
}
entries[i] = l
}
return entries
}

func ExpandPlatformOptions(platformOptions icdv4.PlatformOptions) []map[string]interface{} {
pltOptions := make([]map[string]interface{}, 0, 1)
pltOption := make(map[string]interface{})
Expand Down
33 changes: 33 additions & 0 deletions ibm/service/database/data_source_ibm_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/url"
"path/filepath"

"github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/IBM-Cloud/bluemix-go/api/icd/icdv4"
Expand Down Expand Up @@ -258,6 +259,25 @@ func DataSourceIBMDatabaseInstance() *schema.Resource {
},
},
},
Deprecated: "The whitelist field is deprecated please use allowlist",
},
"allowlist": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"address": {
Description: "Allowlist IP address in CIDR notation",
Type: schema.TypeString,
Computed: true,
},
"description": {
Description: "Unique white list description",
Type: schema.TypeString,
Computed: true,
},
},
},
},
"groups": {
Type: schema.TypeList,
Expand Down Expand Up @@ -763,6 +783,19 @@ func dataSourceIBMDatabaseInstanceRead(d *schema.ResourceData, meta interface{})
}
d.Set("whitelist", flex.FlattenWhitelist(whitelist))

cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5()
alEntry := &clouddatabasesv5.GetAllowlistOptions{
ID: &instance.ID,
}

allowlist, _, err := cloudDatabasesClient.GetAllowlist(alEntry)

if err != nil {
return fmt.Errorf("[ERROR] Error getting database allowlist: %s", err)
}

d.Set("allowlist", flex.FlattenGetAllowlist(*allowlist))

connectionEndpoint := "public"
if instance.Parameters != nil {
if endpoint, ok := instance.Parameters["service-endpoints"]; ok {
Expand Down
1 change: 1 addition & 0 deletions ibm/service/database/data_source_ibm_database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func TestAccIBMDatabaseDataSource_basic(t *testing.T) {
resource.TestCheckResourceAttr(dataName, "members_memory_allocation_mb", "2048"),
resource.TestCheckResourceAttr(dataName, "members_disk_allocation_mb", "10240"),
resource.TestCheckResourceAttr(dataName, "whitelist.#", "0"),
resource.TestCheckResourceAttr(dataName, "allowlist.#", "0"),
resource.TestCheckResourceAttr(dataName, "connectionstrings.#", "1"),
resource.TestCheckResourceAttr(dataName, "connectionstrings.0.name", "admin"),
resource.TestCheckResourceAttr(dataName, "connectionstrings.0.hosts.#", "1"),
Expand Down
182 changes: 177 additions & 5 deletions ibm/service/database/resource_ibm_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,29 @@ func ResourceIBMDatabaseInstance() *schema.Resource {
},
},
},
Deprecated: "Whitelist is deprecated please use allowlist",
ConflictsWith: []string{"allowlist"},
},
"allowlist": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"address": {
Description: "Allowlist IP address in CIDR notation",
Type: schema.TypeString,
Optional: true,
ValidateFunc: validate.ValidateCIDR,
},
"description": {
Description: "Unique allow list description",
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(1, 32),
},
},
},
ConflictsWith: []string{"whitelist"},
},
"group": {
Type: schema.TypeSet,
Expand Down Expand Up @@ -1526,6 +1549,37 @@ func resourceIBMDatabaseInstanceCreate(context context.Context, d *schema.Resour
"[ERROR] Error waiting for update of database (%s) whitelist task to complete: %s", icdId, err))
}
}
} else if al, ok := d.GetOk("allowlist"); ok {
cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5()

if err != nil {
return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err))
}

add := flex.ExpandAllowlist(al.(*schema.Set))
for _, entry := range add {
holdEntry := &clouddatabasesv5.AllowlistEntry{
Address: core.StringPtr(*entry.Address),
Description: core.StringPtr(*entry.Description),
}
alEntry := &clouddatabasesv5.AddAllowlistEntryOptions{
ID: &instanceID,
IPAddress: holdEntry,
}
addAllowListResponse, _, err := cloudDatabasesClient.AddAllowlistEntry(alEntry)

if err != nil {
return diag.FromErr(fmt.Errorf(
"[ERROR] Error updating database allowlist entry: (%s)", err))
}

taskID := *addAllowListResponse.Task.ID
_, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.FromErr(fmt.Errorf(
"[ERROR] Error waiting for update of database (%s) allowlist task to complete: %s", instanceID, err))
}
}
}
if cpuRecord, ok := d.GetOk("auto_scaling.0.cpu"); ok {
params := icdv4.AutoscalingSetGroup{}
Expand Down Expand Up @@ -1764,11 +1818,24 @@ func resourceIBMDatabaseInstanceRead(context context.Context, d *schema.Resource
}
d.Set("auto_scaling", flattenICDAutoScalingGroup(autoSclaingGroup))

whitelist, err := icdClient.Whitelists().GetWhitelist(icdId)
if err != nil {
return diag.FromErr(fmt.Errorf("[ERROR] Error getting database whitelist: %s", err))
if _, ok := d.GetOk("whitelist"); ok {
whitelist, err := icdClient.Whitelists().GetWhitelist(icdId)
if err != nil {
return diag.FromErr(fmt.Errorf("[ERROR] Error getting database whitelist: %s", err))
}
d.Set("whitelist", flex.FlattenWhitelist(whitelist))
} else {
cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5()
alEntry := &clouddatabasesv5.GetAllowlistOptions{
ID: &instanceID,
}

allowlist, _, err := cloudDatabasesClient.GetAllowlist(alEntry)
if err != nil {
return diag.FromErr(fmt.Errorf("[ERROR] Error getting database allowlist: %s", err))
}
d.Set("allowlist", flex.FlattenGetAllowlist(*allowlist))
}
d.Set("whitelist", flex.FlattenWhitelist(whitelist))

var connectionStrings []flex.CsEntry
//ICD does not implement a GetUsers API. Users populated from tf configuration.
Expand Down Expand Up @@ -2105,16 +2172,33 @@ func resourceIBMDatabaseInstanceUpdate(context context.Context, d *schema.Resour
}
}

if d.HasChange("whitelist") {
_, whitelistExists := d.GetOk("whitelist")

if whitelistExists && d.HasChange("whitelist") {
oldList, newList := d.GetChange("whitelist")
oldAllowList, newAllowList := d.GetChange("allowlist")

if oldList == nil {
oldList = new(schema.Set)
}
if newList == nil {
newList = new(schema.Set)
}

os := oldList.(*schema.Set)
ns := newList.(*schema.Set)
osw := oldAllowList.(*schema.Set)
nsw := newAllowList.(*schema.Set)

// If the whitelist is empty but allowlist is not, that means
// we are migrating from whitelist to allowlist
if os.Len() == 0 && osw.Len() > 0 {
os = osw
}
if ns.Len() == 0 && nsw.Len() > 0 {
ns = nsw
}

remove := os.Difference(ns).List()
add := ns.Difference(os).List()

Expand Down Expand Up @@ -2160,6 +2244,94 @@ func resourceIBMDatabaseInstanceUpdate(context context.Context, d *schema.Resour
"[ERROR] Error waiting for database (%s) whitelist delete task to complete for ipAddress %s : %s", icdId, ipAddress, err))
}

}
}
} else if d.HasChange("allowlist") {
cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5()

if err != nil {
return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err))
}

oldList, newList := d.GetChange("allowlist")
oldWhiteList, newWhiteList := d.GetChange("whitelist")

if oldList == nil {
oldList = new(schema.Set)
}
if newList == nil {
newList = new(schema.Set)
}

// If the allowlist is empty but whitelist is not, that means
// we are migrating from allowlist to whitelist
os := oldList.(*schema.Set)
ns := newList.(*schema.Set)
osw := oldWhiteList.(*schema.Set)
nsw := newWhiteList.(*schema.Set)

if os.Len() == 0 && osw.Len() > 0 {
os = osw
}
if ns.Len() == 0 && nsw.Len() > 0 {
ns = nsw
}
remove := os.Difference(ns).List()
add := ns.Difference(os).List()

if len(add) > 0 {
for _, entry := range add {
newEntry := entry.(map[string]interface{})
holdEntry := &clouddatabasesv5.AllowlistEntry{
Address: core.StringPtr(newEntry["address"].(string)),
Description: core.StringPtr(newEntry["description"].(string)),
}
alEntry := &clouddatabasesv5.AddAllowlistEntryOptions{
ID: &instanceID,
IPAddress: holdEntry,
}
addAllowListResponse, response, err := cloudDatabasesClient.AddAllowlistEntry(alEntry)
if err != nil {
return diag.FromErr(fmt.Errorf(
"[ERROR] Error updating database allowlist entry (%s) failed %s\n%s", *addAllowListResponse.Task.Description, err, response))
}

taskID := *addAllowListResponse.Task.ID
_, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.FromErr(fmt.Errorf(
"[ERROR] Error waiting for database (%s) allowlist add task to complete for ipAddress %s : %s", instanceID, *addAllowListResponse.Task.Description, err))
}

}

}

if len(remove) > 0 {
for _, entry := range remove {
newEntry := entry.(map[string]interface{})
holdEntry := &clouddatabasesv5.AllowlistEntry{
Address: core.StringPtr(newEntry["address"].(string)),
Description: core.StringPtr(newEntry["description"].(string)),
}
alEntry := &clouddatabasesv5.DeleteAllowlistEntryOptions{
ID: &instanceID,
Ipaddress: holdEntry.Address,
}

deleteAllowListResponse, response, err := cloudDatabasesClient.DeleteAllowlistEntry(alEntry)
if err != nil {
return diag.FromErr(fmt.Errorf(
"[ERROR] DeleteAllowlistEntry (%s) failed %s\n%s", *deleteAllowListResponse.Task.Description, err, response))
}

taskID := *deleteAllowListResponse.Task.ID
_, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.FromErr(fmt.Errorf(
"[ERROR] Error waiting for database (%s) allowlist delete task to complete for ipAddress %s : %s", instanceID, *deleteAllowListResponse.Task.Description, err))
}

}
}
}
Expand Down
Loading

0 comments on commit ccf0ae0

Please sign in to comment.