From eae525f47aff7150543afce3c63f79279fc9bac6 Mon Sep 17 00:00:00 2001 From: michaelkad Date: Wed, 14 Aug 2024 15:35:26 -0500 Subject: [PATCH] [D] Network Security Group [R] Add NSG [R] Add NSG Action [R] Add NSG Member [R] Add NSG Member test [R] Add NSG Rule Sync go.mod with master Update to 1.8.3 Add handle for 404 Add custom diff update custom diff update nil check fix conflicts --- ibm/acctest/acctest.go | 121 ++-- ibm/flex/structures.go | 16 + ibm/provider/provider.go | 6 + ...ta_source_ibm_pi_network_security_group.go | 316 ++++++++++ ...urce_ibm_pi_network_security_group_test.go | 37 ++ ...a_source_ibm_pi_network_security_groups.go | 266 ++++++++ ...rce_ibm_pi_network_security_groups_test.go | 35 ++ ibm/service/power/ibm_pi_constants.go | 40 ++ .../resource_ibm_pi_network_security_group.go | 384 +++++++++++ ...ce_ibm_pi_network_security_group_action.go | 198 ++++++ ...m_pi_network_security_group_action_test.go | 44 ++ ...ce_ibm_pi_network_security_group_member.go | 386 ++++++++++++ ...m_pi_network_security_group_member_test.go | 93 +++ ...urce_ibm_pi_network_security_group_rule.go | 595 ++++++++++++++++++ ...ibm_pi_network_security_group_rule_test.go | 191 ++++++ ...urce_ibm_pi_network_security_group_test.go | 106 ++++ .../d/pi_network_security_group.html.markdown | 89 +++ .../pi_network_security_groups.html.markdown | 87 +++ .../r/pi_network_security_group.html.markdown | 103 +++ ...etwork_security_group_action.html.markdown | 56 ++ ...etwork_security_group_member.html.markdown | 108 ++++ ..._network_security_group_rule.html.markdown | 154 +++++ 22 files changed, 3393 insertions(+), 38 deletions(-) create mode 100644 ibm/service/power/data_source_ibm_pi_network_security_group.go create mode 100644 ibm/service/power/data_source_ibm_pi_network_security_group_test.go create mode 100644 ibm/service/power/data_source_ibm_pi_network_security_groups.go create mode 100644 ibm/service/power/data_source_ibm_pi_network_security_groups_test.go create mode 100644 ibm/service/power/resource_ibm_pi_network_security_group.go create mode 100644 ibm/service/power/resource_ibm_pi_network_security_group_action.go create mode 100644 ibm/service/power/resource_ibm_pi_network_security_group_action_test.go create mode 100644 ibm/service/power/resource_ibm_pi_network_security_group_member.go create mode 100644 ibm/service/power/resource_ibm_pi_network_security_group_member_test.go create mode 100644 ibm/service/power/resource_ibm_pi_network_security_group_rule.go create mode 100644 ibm/service/power/resource_ibm_pi_network_security_group_rule_test.go create mode 100644 ibm/service/power/resource_ibm_pi_network_security_group_test.go create mode 100644 website/docs/d/pi_network_security_group.html.markdown create mode 100644 website/docs/d/pi_network_security_groups.html.markdown create mode 100644 website/docs/r/pi_network_security_group.html.markdown create mode 100644 website/docs/r/pi_network_security_group_action.html.markdown create mode 100644 website/docs/r/pi_network_security_group_member.html.markdown create mode 100644 website/docs/r/pi_network_security_group_rule.html.markdown diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index 6f72f22fd7..53a800f2c9 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -203,44 +203,48 @@ var ( // For Power Colo var ( - Pi_auxiliary_volume_name string - Pi_cloud_instance_id string - Pi_dhcp_id string - Pi_host_group_id string - Pi_host_id string - Pi_image string - Pi_image_bucket_access_key string - Pi_image_bucket_file_name string - Pi_image_bucket_name string - Pi_image_bucket_region string - Pi_image_bucket_secret_key string - Pi_image_id string - Pi_instance_name string - Pi_key_name string - Pi_network_address_group_id string - Pi_network_name string - Pi_network_id string - Pi_network_interface_id string - Pi_placement_group_name string - Pi_replication_volume_name string - Pi_resource_group_id string - Pi_sap_image string - Pi_shared_processor_pool_id string - Pi_snapshot_id string - Pi_spp_placement_group_id string - Pi_storage_connection string - Pi_target_storage_tier string - Pi_volume_clone_task_id string - Pi_volume_group_id string - Pi_volume_group_name string - Pi_volume_id string - Pi_volume_name string - Pi_volume_onboarding_id string - Pi_volume_onboarding_source_crn string - PiCloudConnectionName string - PiSAPProfileID string - PiStoragePool string - PiStorageType string + Pi_auxiliary_volume_name string + Pi_cloud_instance_id string + Pi_dhcp_id string + Pi_host_group_id string + Pi_host_id string + Pi_image string + Pi_image_bucket_access_key string + Pi_image_bucket_file_name string + Pi_image_bucket_name string + Pi_image_bucket_region string + Pi_image_bucket_secret_key string + Pi_image_id string + Pi_instance_name string + Pi_key_name string + Pi_network_address_group_id string + Pi_network_id string + Pi_network_interface_id string + Pi_network_name string + Pi_network_security_group_id string + Pi_network_security_group_rule_id string + Pi_placement_group_name string + Pi_remote_id string + Pi_remote_type string + Pi_replication_volume_name string + Pi_resource_group_id string + Pi_sap_image string + Pi_shared_processor_pool_id string + Pi_snapshot_id string + Pi_spp_placement_group_id string + Pi_storage_connection string + Pi_target_storage_tier string + Pi_volume_clone_task_id string + Pi_volume_group_id string + Pi_volume_group_name string + Pi_volume_id string + Pi_volume_name string + Pi_volume_onboarding_id string + Pi_volume_onboarding_source_crn string + PiCloudConnectionName string + PiSAPProfileID string + PiStoragePool string + PiStorageType string ) var ( @@ -1082,6 +1086,31 @@ func init() { Pi_network_interface_id = "terraform-test-power" fmt.Println("[INFO] Set the environment variable PI_NETWORK_INTERFACE_ID for testing ibm_pi_network_interface resource else it is set to default value 'terraform-test-power'") } + + Pi_network_security_group_id = os.Getenv("PI_NETWORK_SECURITY_GROUP_ID") + if Pi_network_security_group_id == "" { + Pi_network_security_group_id = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_NETWORK_SECURITY_GROUP_ID for testing ibm_pi_network_security_group resource else it is set to default value 'terraform-test-power'") + } + + Pi_network_security_group_rule_id = os.Getenv("PI_NETWORK_SECURITY_GROUP_RULE_ID") + if Pi_network_security_group_rule_id == "" { + Pi_network_security_group_rule_id = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_NETWORK_SECURITY_GROUP_RULE_ID for testing ibm_pi_network_security_group resource else it is set to default value 'terraform-test-power'") + } + + Pi_network_security_group_id = os.Getenv("PI_NETWORK_SECURITY_GROUP_ID") + if Pi_network_security_group_id == "" { + Pi_network_security_group_id = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_NETWORK_SECURITY_GROUP_ID for testing ibm_pi_network_security_group resource else it is set to default value 'terraform-test-power'") + } + + Pi_network_security_group_rule_id = os.Getenv("PI_NETWORK_SECURITY_GROUP_RULE_ID") + if Pi_network_security_group_rule_id == "" { + Pi_network_security_group_rule_id = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_NETWORK_SECURITY_GROUP_RULE_ID for testing ibm_pi_network_security_group resource else it is set to default value 'terraform-test-power'") + } + Pi_volume_name = os.Getenv("PI_VOLUME_NAME") if Pi_volume_name == "" { Pi_volume_name = "terraform-test-power" @@ -1171,21 +1200,37 @@ func init() { Pi_placement_group_name = "tf-pi-placement-group" fmt.Println("[WARN] Set the environment variable PI_PLACEMENT_GROUP_NAME for testing ibm_pi_placement_group resource else it is set to default value 'tf-pi-placement-group'") } + + Pi_remote_id = os.Getenv("PI_REMOTE_ID") + if Pi_remote_id == "" { + Pi_remote_id = "terraform-test-power" + fmt.Println("[WARN] Set the environment variable PI_REMOTE_ID for testing ibm_pi_network_security_group resource else it is set to default value 'terraform-test-power'") + } + + Pi_remote_type = os.Getenv("PI_REMOTE_TYPE") + if Pi_remote_type == "" { + Pi_remote_type = "terraform-test-power" + fmt.Println("[WARN] Set the environment variable PI_REMOTE_TYPE for testing ibm_pi_network_security_group resource else it is set to default value 'terraform-test-power'") + } + Pi_spp_placement_group_id = os.Getenv("PI_SPP_PLACEMENT_GROUP_ID") if Pi_spp_placement_group_id == "" { Pi_spp_placement_group_id = "tf-pi-spp-placement-group" fmt.Println("[WARN] Set the environment variable PI_SPP_PLACEMENT_GROUP_ID for testing ibm_pi_spp_placement_group resource else it is set to default value 'tf-pi-spp-placement-group'") } + PiStoragePool = os.Getenv("PI_STORAGE_POOL") if PiStoragePool == "" { PiStoragePool = "terraform-test-power" fmt.Println("[INFO] Set the environment variable PI_STORAGE_POOL for testing ibm_pi_storage_pool_capacity else it is set to default value 'terraform-test-power'") } + PiStorageType = os.Getenv("PI_STORAGE_TYPE") if PiStorageType == "" { PiStorageType = "terraform-test-power" fmt.Println("[INFO] Set the environment variable PI_STORAGE_TYPE for testing ibm_pi_storage_type_capacity else it is set to default value 'terraform-test-power'") } + // Added for resource capture instance testing Pi_capture_storage_image_path = os.Getenv("PI_CAPTURE_STORAGE_IMAGE_PATH") if Pi_capture_storage_image_path == "" { diff --git a/ibm/flex/structures.go b/ibm/flex/structures.go index 1164864179..5dd3d383fb 100644 --- a/ibm/flex/structures.go +++ b/ibm/flex/structures.go @@ -129,6 +129,22 @@ func FlattenIntList(list []int) []interface{} { return vs } +func ExpandInt64List(input []interface{}) []int64 { + vs := make([]int64, len(input)) + for i, v := range input { + vs[i] = v.(int64) + } + return vs +} + +func FlattenInt64List(list []int64) []interface{} { + vs := make([]interface{}, len(list)) + for i, v := range list { + vs[i] = v + } + return vs +} + func NewStringSet(f schema.SchemaSetFunc, in []string) *schema.Set { var out = make([]interface{}, len(in), len(in)) for i, v := range in { diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index fe229bdd4d..8f41c6fae1 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -661,6 +661,8 @@ func Provider() *schema.Provider { "ibm_pi_network_interface": power.DataSourceIBMPINetworkInterface(), "ibm_pi_network_interfaces": power.DataSourceIBMPINetworkInterfaces(), "ibm_pi_network_port": power.DataSourceIBMPINetworkPort(), + "ibm_pi_network_security_group": power.DataSourceIBMPINetworkSecurityGroup(), + "ibm_pi_network_security_groups": power.DataSourceIBMPINetworkSecurityGroups(), "ibm_pi_network": power.DataSourceIBMPINetwork(), "ibm_pi_networks": power.DataSourceIBMPINetworks(), "ibm_pi_placement_group": power.DataSourceIBMPIPlacementGroup(), @@ -1317,6 +1319,10 @@ func Provider() *schema.Provider { "ibm_pi_network_address_group": power.ResourceIBMPINetworkAddressGroup(), "ibm_pi_network_interface": power.ResourceIBMPINetworkInterface(), "ibm_pi_network_port_attach": power.ResourceIBMPINetworkPortAttach(), + "ibm_pi_network_security_group_action": power.ResourceIBMPINetworkSecurityGroupAction(), + "ibm_pi_network_security_group_member": power.ResourceIBMPINetworkSecurityGroupMember(), + "ibm_pi_network_security_group_rule": power.ResourceIBMPINetworkSecurityGroupRule(), + "ibm_pi_network_security_group": power.ResourceIBMPINetworkSecurityGroup(), "ibm_pi_network": power.ResourceIBMPINetwork(), "ibm_pi_placement_group": power.ResourceIBMPIPlacementGroup(), "ibm_pi_shared_processor_pool": power.ResourceIBMPISharedProcessorPool(), diff --git a/ibm/service/power/data_source_ibm_pi_network_security_group.go b/ibm/service/power/data_source_ibm_pi_network_security_group.go new file mode 100644 index 0000000000..323dda38fc --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_network_security_group.go @@ -0,0 +1,316 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceIBMPINetworkSecurityGroup() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPINetworkSecurityGroupRead, + + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_NetworkSecurityGroupID: { + Description: "network security group ID.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + // Attributes + Attr_CRN: { + Computed: true, + Description: "The network security group's crn.", + Type: schema.TypeString, + }, + Attr_Members: { + Computed: true, + Description: "The list of IPv4 addresses and, or network interfaces in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the member in a network security group.", + Type: schema.TypeString, + }, + Attr_MacAddress: { + Computed: true, + Description: "The mac address of a network interface included if the type is network-interface.", + Type: schema.TypeString, + }, + Attr_Target: { + Computed: true, + Description: "If ipv4-address type, then IPv4 address or if network-interface type, then network interface ID.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of member.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Name: { + Computed: true, + Description: "The name of the network security group.", + Type: schema.TypeString, + }, + Attr_Rules: { + Computed: true, + Description: "The list of rules in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Action: { + Computed: true, + Description: "The action to take if the rule matches network traffic.", + Type: schema.TypeString, + }, + Attr_DestinationPort: { + Computed: true, + Description: "The list of destination port.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_ID: { + Computed: true, + Description: "The ID of the rule in a network security group.", + Type: schema.TypeString, + }, + Attr_Protocol: { + Computed: true, + Description: "The list of protocol.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ICMPType: { + Computed: true, + Description: "If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched.", + Type: schema.TypeString, + }, + Attr_TCPFlags: { + Computed: true, + Description: "If tcp type, the list of TCP flags and if not present then all flags are matched.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Flag: { + Computed: true, + Description: "TCP flag.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Type: { + Computed: true, + Description: "The protocol of the network traffic.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Remote: { + Computed: true, + Description: "List of remote.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the remote Network Address Group or network security group the rules apply to. Not required for default-network-address-group.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of remote group the rules apply to.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_SourcePort: { + Computed: true, + Description: "List of source port", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_UserTags: { + Computed: true, + Description: "List of user tags attached to the resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Type: schema.TypeSet, + }, + }, + } +} + +func dataSourceIBMPINetworkSecurityGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + + networkSecurityGroup, err := nsgClient.Get(d.Get(Arg_NetworkSecurityGroupID).(string)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(*networkSecurityGroup.ID) + if networkSecurityGroup.Crn != nil { + d.Set(Attr_CRN, networkSecurityGroup.Crn) + userTags, err := flex.GetTagsUsingCRN(meta, string(*networkSecurityGroup.Crn)) + if err != nil { + log.Printf("Error on get of pi network security group (%s) user_tags: %s", *networkSecurityGroup.ID, err) + } + d.Set(Attr_UserTags, userTags) + } + + if len(networkSecurityGroup.Members) > 0 { + members := []map[string]interface{}{} + for _, mbr := range networkSecurityGroup.Members { + mbrMap := networkSecurityGroupMemberToMap(mbr) + members = append(members, mbrMap) + } + d.Set(Attr_Members, members) + } + + d.Set(Attr_Name, networkSecurityGroup.Name) + + if len(networkSecurityGroup.Rules) > 0 { + rules := []map[string]interface{}{} + for _, rule := range networkSecurityGroup.Rules { + ruleMap := networkSecurityGroupRuleToMap(rule) + rules = append(rules, ruleMap) + } + d.Set(Attr_Rules, rules) + } + + return nil +} + +func networkSecurityGroupMemberToMap(mbr *models.NetworkSecurityGroupMember) map[string]interface{} { + mbrMap := make(map[string]interface{}) + mbrMap[Attr_ID] = mbr.ID + if mbr.MacAddress != "" { + mbrMap[Attr_MacAddress] = mbr.MacAddress + } + mbrMap[Attr_Target] = mbr.Target + mbrMap[Attr_Type] = mbr.Type + return mbrMap +} + +func networkSecurityGroupRuleToMap(rule *models.NetworkSecurityGroupRule) map[string]interface{} { + ruleMap := make(map[string]interface{}) + ruleMap[Attr_Action] = rule.Action + if rule.DestinationPort != nil { + destinationPortMap := networkSecurityGroupRulePortToMap(rule.DestinationPort) + ruleMap[Attr_DestinationPort] = []map[string]interface{}{destinationPortMap} + } + + ruleMap[Attr_ID] = rule.ID + + protocolMap := networkSecurityGroupRuleProtocolToMap(rule.Protocol) + ruleMap[Attr_Protocol] = []map[string]interface{}{protocolMap} + + remoteMap := networkSecurityGroupRuleRemoteToMap(rule.Remote) + ruleMap[Attr_Remote] = []map[string]interface{}{remoteMap} + + if rule.SourcePort != nil { + sourcePortMap := networkSecurityGroupRulePortToMap(rule.SourcePort) + ruleMap[Attr_SourcePort] = []map[string]interface{}{sourcePortMap} + } + + return ruleMap +} + +func networkSecurityGroupRulePortToMap(port *models.NetworkSecurityGroupRulePort) map[string]interface{} { + portMap := make(map[string]interface{}) + portMap[Attr_Maximum] = port.Maximum + portMap[Attr_Minimum] = port.Minimum + return portMap +} + +func networkSecurityGroupRuleProtocolToMap(protocol *models.NetworkSecurityGroupRuleProtocol) map[string]interface{} { + protocolMap := make(map[string]interface{}) + if protocol.IcmpType != nil { + protocolMap[Attr_ICMPType] = protocol.IcmpType + } + if len(protocol.TCPFlags) > 0 { + tcpFlags := []map[string]interface{}{} + for _, tcpFlagsItem := range protocol.TCPFlags { + tcpFlagsItemMap := make(map[string]interface{}) + tcpFlagsItemMap[Attr_Flag] = tcpFlagsItem.Flag + tcpFlags = append(tcpFlags, tcpFlagsItemMap) + } + protocolMap[Attr_TCPFlags] = tcpFlags + } + if protocol.Type != "" { + protocolMap[Attr_Type] = protocol.Type + } + return protocolMap +} + +func networkSecurityGroupRuleRemoteToMap(remote *models.NetworkSecurityGroupRuleRemote) map[string]interface{} { + remoteMap := make(map[string]interface{}) + if remote.ID != "" { + remoteMap[Attr_ID] = remote.ID + } + if remote.Type != "" { + remoteMap[Attr_Type] = remote.Type + } + return remoteMap +} diff --git a/ibm/service/power/data_source_ibm_pi_network_security_group_test.go b/ibm/service/power/data_source_ibm_pi_network_security_group_test.go new file mode 100644 index 0000000000..4bb77b59d9 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_network_security_group_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMPINetworkSecurityGroupDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkSecurityGroupDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_network_security_group.network_security_group", "id"), + resource.TestCheckResourceAttrSet("data.ibm_pi_network_security_group.network_security_group", "name"), + ), + }, + }, + }) +} + +func testAccCheckIBMPINetworkSecurityGroupDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_pi_network_security_group" "network_security_group" { + pi_cloud_instance_id = "%s" + pi_network_security_group_id = "%s" + }`, acc.Pi_cloud_instance_id, acc.Pi_network_security_group_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_network_security_groups.go b/ibm/service/power/data_source_ibm_pi_network_security_groups.go new file mode 100644 index 0000000000..b79d24326f --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_network_security_groups.go @@ -0,0 +1,266 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceIBMPINetworkSecurityGroups() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPINetworkSecurityGroupsRead, + + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + // Attributes + Attr_NetworkSecurityGroups: { + Computed: true, + Description: "list of Network Security Groups.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_CRN: { + Computed: true, + Description: "The network security group's crn.", + Type: schema.TypeString, + }, + Attr_ID: { + Computed: true, + Description: "The ID of the network security group.", + Type: schema.TypeString, + }, + Attr_Members: { + Computed: true, + Description: "The list of IPv4 addresses and, or network interfaces in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the member in a network security group.", + Type: schema.TypeString, + }, + Attr_MacAddress: { + Computed: true, + Description: "The mac address of a network interface included if the type is network-interface.", + Type: schema.TypeString, + }, + Attr_Target: { + Computed: true, + Description: "If ipv4-address type, then IPv4 address or if network-interface type, then network interface ID.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of member.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Name: { + Computed: true, + Description: "The name of the network security group.", + Type: schema.TypeString, + }, + Attr_Rules: { + Computed: true, + Description: "The list of rules in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Action: { + Computed: true, + Description: "The action to take if the rule matches network traffic.", + Type: schema.TypeString, + }, + Attr_DestinationPort: { + Computed: true, + Description: "The list of destination port.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_ID: { + Computed: true, + Description: "The ID of the rule in a network security group.", + Type: schema.TypeString, + }, + Attr_Protocol: { + Computed: true, + Description: "The list of protocol.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ICMPType: { + Computed: true, + Description: "If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched.", + Type: schema.TypeString, + }, + Attr_TCPFlags: { + Computed: true, + Description: "If tcp type, the list of TCP flags and if not present then all flags are matched.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Flag: { + Computed: true, + Description: "TCP flag.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Type: { + Computed: true, + Description: "The protocol of the network traffic.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Remote: { + Computed: true, + Description: "List of remote.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the remote Network Address Group or network security group the rules apply to. Not required for default-network-address-group.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of remote group the rules apply to.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_SourcePort: { + Computed: true, + Description: "List of source port", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_UserTags: { + Computed: true, + Description: "List of user tags attached to the resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Type: schema.TypeSet, + }, + }, + }, + Type: schema.TypeList, + }, + }, + } +} + +func dataSourceIBMPINetworkSecurityGroupsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + nsgResp, err := nsgClient.GetAll() + if err != nil { + return diag.FromErr(err) + } + + var clientgenU, _ = uuid.GenerateUUID() + d.SetId(clientgenU) + + networkSecurityGroups := []map[string]interface{}{} + if len(nsgResp.NetworkSecurityGroups) > 0 { + for _, nsg := range nsgResp.NetworkSecurityGroups { + networkSecurityGroup := networkSecurityGroupToMap(nsg, meta) + networkSecurityGroups = append(networkSecurityGroups, networkSecurityGroup) + } + } + + d.Set(Attr_NetworkSecurityGroups, networkSecurityGroups) + + return nil +} + +func networkSecurityGroupToMap(nsg *models.NetworkSecurityGroup, meta interface{}) map[string]interface{} { + networkSecurityGroup := make(map[string]interface{}) + if nsg.Crn != nil { + networkSecurityGroup[Attr_CRN] = nsg.Crn + userTags, err := flex.GetTagsUsingCRN(meta, string(*nsg.Crn)) + if err != nil { + log.Printf("Error on get of pi network security group (%s) user_tags: %s", *nsg.ID, err) + } + networkSecurityGroup[Attr_UserTags] = userTags + } + + networkSecurityGroup[Attr_ID] = nsg.ID + if len(nsg.Members) > 0 { + members := []map[string]interface{}{} + for _, mbr := range nsg.Members { + mbrMap := networkSecurityGroupMemberToMap(mbr) + members = append(members, mbrMap) + } + networkSecurityGroup[Attr_Members] = members + } + networkSecurityGroup[Attr_Name] = nsg.Name + if len(nsg.Rules) > 0 { + rules := []map[string]interface{}{} + for _, rule := range nsg.Rules { + rulesItemMap := networkSecurityGroupRuleToMap(rule) + rules = append(rules, rulesItemMap) + } + networkSecurityGroup[Attr_Rules] = rules + } + return networkSecurityGroup +} diff --git a/ibm/service/power/data_source_ibm_pi_network_security_groups_test.go b/ibm/service/power/data_source_ibm_pi_network_security_groups_test.go new file mode 100644 index 0000000000..7d3c9abf05 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_network_security_groups_test.go @@ -0,0 +1,35 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMPINetworkSecurityGroupsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkSecurityGroupsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_network_security_groups.network_security_groups", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPINetworkSecurityGroupsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_pi_network_security_groups" "network_security_groups" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index 09d2b46a9d..aac2683c62 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -21,6 +21,7 @@ const ( Arg_DeploymentTarget = "pi_deployment_target" Arg_DeploymentType = "pi_deployment_type" Arg_Description = "pi_description" + Arg_DestinationPorts = "pi_destination_ports" Arg_DhcpID = "pi_dhcp_id" Arg_DhcpName = "pi_dhcp_name" Arg_DhcpSnatEnabled = "pi_dhcp_snat_enabled" @@ -53,6 +54,8 @@ const ( Arg_NetworkInterfaceID = "pi_network_interface_id" Arg_NetworkName = "pi_network_name" Arg_NetworkSecurityGroupID = "pi_network_security_group_id" + Arg_NetworkSecurityGroupMemberID = "pi_network_security_group_member_id" + Arg_NetworkSecurityGroupRuleID = "pi_network_security_group_rule_id" Arg_PinPolicy = "pi_pin_policy" Arg_PlacementGroupID = "pi_placement_group_id" Arg_PlacementGroupName = "pi_placement_group_name" @@ -60,9 +63,11 @@ const ( Arg_Plan = "pi_plan" Arg_Processors = "pi_processors" Arg_ProcType = "pi_proc_type" + Arg_Protocol = "pi_protocol" Arg_PVMInstanceActionType = "pi_action" Arg_PVMInstanceHealthStatus = "pi_health_status" Arg_PVMInstanceId = "pi_instance_id" + Arg_Remote = "pi_remote" Arg_Remove = "pi_remove" Arg_Replicants = "pi_replicants" Arg_ReplicationEnabled = "pi_replication_enabled" @@ -82,6 +87,7 @@ const ( Arg_SharedProcessorPoolReservedCores = "pi_shared_processor_pool_reserved_cores" Arg_SnapshotID = "pi_snapshot_id" Arg_SnapShotName = "pi_snap_shot_name" + Arg_SourcePorts = "pi_source_ports" Arg_SPPPlacementGroupID = "pi_spp_placement_group_id" Arg_SPPPlacementGroupName = "pi_spp_placement_group_name" Arg_SPPPlacementGroupPolicy = "pi_spp_placement_group_policy" @@ -91,7 +97,9 @@ const ( Arg_StoragePoolAffinity = "pi_storage_pool_affinity" Arg_StorageType = "pi_storage_type" Arg_SysType = "pi_sys_type" + Arg_Target = "pi_target" Arg_TargetStorageTier = "pi_target_storage_tier" + Arg_Type = "pi_type" Arg_UserData = "pi_user_data" Arg_UserTags = "pi_user_tags" Arg_VirtualCoresAssigned = "pi_virtual_cores_assigned" @@ -173,9 +181,11 @@ const ( Attr_DeleteOnTermination = "delete_on_termination" Attr_DeploymentType = "deployment_type" Attr_Description = "description" + Attr_DestinationPort = "destination_port" Attr_Details = "details" Attr_DhcpID = "dhcp_id" Attr_DhcpManaged = "dhcp_managed" + Attr_Direction = "direction" Attr_DisasterRecovery = "disaster_recovery" Attr_DisasterRecoveryLocations = "disaster_recovery_locations" Attr_DiskFormat = "disk_format" @@ -188,6 +198,7 @@ const ( Attr_FailureMessage = "failure_message" Attr_FailureReason = "failure_reason" Attr_Fault = "fault" + Attr_Flag = "flag" Attr_FlashCopyMappings = "flash_copy_mappings" Attr_FlashCopyName = "flash_copy_name" Attr_FreezeTime = "freeze_time" @@ -212,6 +223,7 @@ const ( Attr_IBMiPHA = "ibmi_pha" Attr_IBMiRDS = "ibmi_rds" Attr_IBMiRDSUsers = "ibmi_rds_users" + Attr_ICMPType = "icmp_type" Attr_ID = "id" Attr_ImageID = "image_id" Attr_ImageInfo = "image_info" @@ -252,6 +264,7 @@ const ( Attr_MaxAllocationSize = "max_allocation_size" Attr_MaxAvailable = "max_available" Attr_MaxCoresAvailable = "max_cores_available" + Attr_Maximum = "maximum" Attr_MaximumStorageAllocation = "max_storage_allocation" Attr_MaxMem = "maxmem" Attr_MaxMemory = "max_memory" @@ -265,6 +278,7 @@ const ( Attr_Metered = "metered" Attr_MigrationStatus = "migration_status" Attr_Min = "min" + Attr_Minimum = "minimum" Attr_MinMem = "minmem" Attr_MinMemory = "min_memory" Attr_MinProc = "minproc" @@ -282,6 +296,7 @@ const ( Attr_NetworkPorts = "network_ports" Attr_Networks = "networks" Attr_NetworkSecurityGroupID = "network_security_group_id" + Attr_NetworkSecurityGroupMemberID = "network_security_group_member_id" Attr_NetworkSecurityGroups = "network_security_groups" Attr_NumberOfVolumes = "number_of_volumes" Attr_Onboardings = "onboardings" @@ -305,12 +320,14 @@ const ( Attr_ProfileID = "profile_id" Attr_Profiles = "profiles" Attr_Progress = "progress" + Attr_Protocol = "protocol" Attr_PublicIP = "public_ip" Attr_PVMInstanceID = "pvm_instance_id" Attr_PVMInstances = "pvm_instances" Attr_PVMSnapshots = "pvm_snapshots" Attr_Region = "region" Attr_RegionStorageTiers = "region_storage_tiers" + Attr_Remote = "remote" Attr_RemoteCopyID = "remote_copy_id" Attr_RemoteCopyRelationshipNames = "remote_copy_relationship_names" Attr_RemoteCopyRelationships = "remote_copy_relationships" @@ -326,6 +343,7 @@ const ( Attr_ReservedMemory = "reserved_memory" Attr_ResultsOnboardedVolumes = "results_onboarded_volumes" Attr_ResultsVolumeOnboardingFailures = "results_volume_onboarding_failures" + Attr_Rules = "rules" Attr_SAPS = "saps" Attr_Secondaries = "secondaries" Attr_ServerName = "server_name" @@ -353,6 +371,7 @@ const ( Attr_Size = "size" Attr_SnapshotID = "snapshot_id" Attr_SourceChecksum = "source_checksum" + Attr_SourcePort = "source_port" Attr_SourceVolumeID = "source_volume_id" Attr_SourceVolumeName = "source_volume_name" Attr_Speed = "speed" @@ -381,9 +400,11 @@ const ( Attr_Systems = "systems" Attr_SysType = "sys_type" Attr_Systype = "systype" + Attr_Target = "target" Attr_TargetLocations = "target_locations" Attr_TargetVolumeName = "target_volume_name" Attr_TaskID = "task_id" + Attr_TCPFlags = "tcp_flags" Attr_TenantID = "tenant_id" Attr_TenantName = "tenant_name" Attr_TotalCapacity = "total_capacity" @@ -451,6 +472,8 @@ const ( // Allowed Values Affinity = "affinity" + All = "all" + Allow = "allow" AntiAffinity = "anti-affinity" Attach = "attach" BYOL = "byol" @@ -458,16 +481,28 @@ const ( Critical = "CRITICAL" CUSTOM_VIRTUAL_CORES = "custom-virtualcores" Dedicated = "dedicated" + DefaultNAG = "default-network-address-group" + Deny = "deny" DeploymentTypeEpic = "EPIC" DeploymentTypeVMNoStorage = "VMNoStorage" + DestinationUnreach = "destination-unreach" DHCPVlan = "dhcp-vlan" + Disable = "disable" + Echo = "echo" + EchoReply = "echo-reply" + Enable = "enable" Hana = "Hana" Hard = "hard" Host = "host" HostGroup = "hostGroup" + ICMP = "icmp" + IPV4_Address = "ipv4-address" + NAG = "network-address-group" MaxVolumeSupport = "maxVolumeSupport" Netweaver = "Netweaver" + Network_Interface = "network-interface" None = "none" + NSG = "network-security-group" OK = "OK" PER = "power-edge-router" Prefix = "prefix" @@ -477,7 +512,11 @@ const ( SAP = "SAP" Shared = "shared" Soft = "soft" + SourceQuench = "source-quench" Suffix = "suffix" + TCP = "tcp" + TimeExceeded = "time-exceeded" + UDP = "udp" UserTagType = "user" Vlan = "vlan" vSCSI = "vSCSI" @@ -519,6 +558,7 @@ const ( State_PendingReclamation = "pending_reclamation" State_Provisioning = "provisioning" State_Removed = "removed" + State_Removing = "removing" State_Resize = "resize" State_RESIZE = "RESIZE" State_Retry = "retry" diff --git a/ibm/service/power/resource_ibm_pi_network_security_group.go b/ibm/service/power/resource_ibm_pi_network_security_group.go new file mode 100644 index 0000000000..b92c8a8e45 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_security_group.go @@ -0,0 +1,384 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" +) + +func ResourceIBMPINetworkSecurityGroup() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPINetworkSecurityGroupCreate, + ReadContext: resourceIBMPINetworkSecurityGroupRead, + UpdateContext: resourceIBMPINetworkSecurityGroupUpdate, + DeleteContext: resourceIBMPINetworkSecurityGroupDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + ForceNew: true, + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_Name: { + Description: "The name of the network security group.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_UserTags: { + Description: "The user tags associated with this resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Type: schema.TypeSet, + }, + // Attributes + Attr_CRN: { + Computed: true, + Description: "The network security group's crn.", + Type: schema.TypeString, + }, + Attr_Members: { + Computed: true, + Description: "The list of IPv4 addresses and, or network interfaces in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the member in a network security group.", + Type: schema.TypeString, + }, + Attr_MacAddress: { + Computed: true, + Description: "The mac address of a network interface included if the type is network-interface.", + Type: schema.TypeString, + }, + Attr_Target: { + Computed: true, + Description: "If ipv4-address type, then IPv4 address or if network-interface type, then network interface ID.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of member.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_NetworkSecurityGroupID: { + Computed: true, + Description: "The unique identifier of the network security group.", + Type: schema.TypeString, + }, + Attr_Rules: { + Computed: true, + Description: "The list of rules in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Action: { + Computed: true, + Description: "The action to take if the rule matches network traffic.", + Type: schema.TypeString, + }, + Attr_DestinationPort: { + Computed: true, + Description: "The list of destination port.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_ID: { + Computed: true, + Description: "The ID of the rule in a network security group.", + Type: schema.TypeString, + }, + Attr_Protocol: { + Computed: true, + Description: "The list of protocol.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ICMPType: { + Computed: true, + Description: "If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched.", + Type: schema.TypeString, + }, + Attr_TCPFlags: { + Computed: true, + Description: "If tcp type, the list of TCP flags and if not present then all flags are matched.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Flag: { + Computed: true, + Description: "TCP flag.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Type: { + Computed: true, + Description: "The protocol of the network traffic.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Remote: { + Computed: true, + Description: "List of remote.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the remote Network Address Group or network security group the rules apply to. Not required for default-network-address-group.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of remote group the rules apply to.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_SourcePort: { + Computed: true, + Description: "ist of source port", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + }, + }, + Type: schema.TypeList, + }, + }, + } +} + +func resourceIBMPINetworkSecurityGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + name := d.Get(Arg_Name).(string) + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + + body := &models.NetworkSecurityGroupCreate{ + Name: &name, + } + if v, ok := d.GetOk(Arg_UserTags); ok { + userTags := flex.FlattenSet(v.(*schema.Set)) + body.UserTags = userTags + } + + networkSecurityGroup, err := nsgClient.Create(body) + if err != nil { + return diag.FromErr(err) + } + if _, ok := d.GetOk(Arg_UserTags); ok { + if networkSecurityGroup.Crn != nil { + oldList, newList := d.GetChange(Arg_UserTags) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, string(*networkSecurityGroup.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on update of pi network security group (%s) pi_user_tags during creation: %s", *networkSecurityGroup.ID, err) + } + } + } + nsgID := *networkSecurityGroup.ID + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, nsgID)) + + return resourceIBMPINetworkSecurityGroupRead(ctx, d, meta) +} + +func resourceIBMPINetworkSecurityGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID, nsgID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + networkSecurityGroup, err := nsgClient.Get(nsgID) + if err != nil { + if strings.Contains(strings.ToLower(err.Error()), NotFound) { + d.SetId("") + return nil + } + return diag.FromErr(err) + } + d.Set(Arg_Name, networkSecurityGroup.Name) + crn := networkSecurityGroup.Crn + if crn != nil { + d.Set(Attr_CRN, networkSecurityGroup.Crn) + userTags, err := flex.GetGlobalTagsUsingCRN(meta, string(*networkSecurityGroup.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on get of network security group (%s) pi_user_tags: %s", nsgID, err) + } + d.Set(Arg_UserTags, userTags) + } + + if len(networkSecurityGroup.Members) > 0 { + members := []map[string]interface{}{} + for _, mbr := range networkSecurityGroup.Members { + mbrMap := networkSecurityGroupMemberToMap(mbr) + members = append(members, mbrMap) + } + d.Set(Attr_Members, members) + } else { + d.Set(Attr_Members, []string{}) + } + + d.Set(Attr_NetworkSecurityGroupID, networkSecurityGroup.ID) + + if len(networkSecurityGroup.Rules) > 0 { + rules := []map[string]interface{}{} + for _, rule := range networkSecurityGroup.Rules { + ruleMap := networkSecurityGroupRuleToMap(rule) + rules = append(rules, ruleMap) + } + d.Set(Attr_Rules, rules) + } else { + d.Set(Attr_Rules, []string{}) + } + + return nil +} + +func resourceIBMPINetworkSecurityGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID, nsgID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + if d.HasChange(Arg_UserTags) { + if crn, ok := d.GetOk(Attr_CRN); ok { + oldList, newList := d.GetChange(Arg_UserTags) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, crn.(string), "", UserTagType) + if err != nil { + log.Printf("Error on update of pi network security group (%s) pi_user_tags: %s", nsgID, err) + } + } + } + if d.HasChange(Arg_Name) { + body := &models.NetworkSecurityGroupUpdate{ + Name: d.Get(Arg_Name).(string), + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + _, err = nsgClient.Update(nsgID, body) + if err != nil { + return diag.FromErr(err) + } + } + return resourceIBMPINetworkSecurityGroupRead(ctx, d, meta) +} + +func resourceIBMPINetworkSecurityGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID, nsgID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + err = nsgClient.Delete(nsgID) + if err != nil { + return diag.FromErr(err) + } + _, err = isWaitForIBMPINetworkSecurityGroupDeleted(ctx, nsgClient, nsgID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + d.SetId("") + + return nil +} +func isWaitForIBMPINetworkSecurityGroupDeleted(ctx context.Context, client *instance.IBMPINetworkSecurityGroupClient, nsgID string, timeout time.Duration) (interface{}, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Deleting}, + Target: []string{State_NotFound}, + Refresh: isIBMPINetworkSecurityGroupDeleteRefreshFunc(client, nsgID), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPINetworkSecurityGroupDeleteRefreshFunc(client *instance.IBMPINetworkSecurityGroupClient, nsgID string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + nsg, err := client.Get(nsgID) + if err != nil { + return nsg, State_NotFound, nil + } + return nsg, State_Deleting, nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_network_security_group_action.go b/ibm/service/power/resource_ibm_pi_network_security_group_action.go new file mode 100644 index 0000000000..9fc22b13b1 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_security_group_action.go @@ -0,0 +1,198 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMPINetworkSecurityGroupAction() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPINetworkSecurityGroupActionCreate, + ReadContext: resourceIBMPINetworkSecurityGroupActionRead, + UpdateContext: resourceIBMPINetworkSecurityGroupActionUpdate, + DeleteContext: resourceIBMPINetworkSecurityGroupActionDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Arguments + Arg_Action: { + Description: "Name of the action to take; can be enable to enable NSGs in a workspace or disable to disable NSGs in a workspace.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{Disable, Enable}), + }, + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + ForceNew: true, + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + // Attribute + Attr_State: { + Computed: true, + Description: "The workspace network security group's state.", + Type: schema.TypeString, + }, + }, + } +} + +func resourceIBMPINetworkSecurityGroupActionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + action := d.Get(Arg_Action).(string) + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + wsclient := instance.NewIBMPIWorkspacesClient(ctx, sess, cloudInstanceID) + _, err = isWaitForWorkspaceActive(ctx, wsclient, cloudInstanceID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + body := &models.NetworkSecurityGroupsAction{Action: &action} + err = nsgClient.Action(body) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForNSGStatus(ctx, wsclient, cloudInstanceID, action, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + d.SetId(cloudInstanceID) + return resourceIBMPINetworkSecurityGroupActionRead(ctx, d, meta) +} + +func resourceIBMPINetworkSecurityGroupActionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + wsclient := instance.NewIBMPIWorkspacesClient(ctx, sess, d.Id()) + ws, err := wsclient.Get(d.Id()) + if err != nil { + return diag.FromErr(err) + } + d.Set(Attr_State, ws.Details.NetworkSecurityGroups.State) + + return nil +} +func resourceIBMPINetworkSecurityGroupActionUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + if d.HasChange(Arg_Action) { + action := d.Get(Arg_Action).(string) + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + + body := &models.NetworkSecurityGroupsAction{Action: &action} + err = nsgClient.Action(body) + if err != nil { + return diag.FromErr(err) + } + wsclient := instance.NewIBMPIWorkspacesClient(ctx, sess, cloudInstanceID) + _, err = isWaitForNSGStatus(ctx, wsclient, cloudInstanceID, action, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + + return resourceIBMPINetworkSecurityGroupActionRead(ctx, d, meta) +} +func resourceIBMPINetworkSecurityGroupActionDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId("") + return nil +} +func isWaitForWorkspaceActive(ctx context.Context, client *instance.IBMPIWorkspacesClient, id string, timeout time.Duration) (interface{}, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Provisioning}, + Target: []string{State_Active}, + Refresh: isWorkspaceRefreshFunc(client, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} +func isWorkspaceRefreshFunc(client *instance.IBMPIWorkspacesClient, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + ws, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if *(ws.Status) == State_Active { + return ws, State_Active, nil + } + if *(ws.Details.NetworkSecurityGroups.State) == State_Provisioning { + return ws, State_Provisioning, nil + } + if *(ws.Details.NetworkSecurityGroups.State) == State_Failed { + return ws, *ws.Details.NetworkSecurityGroups.State, fmt.Errorf("[ERROR] workspace network security group configuration state is:%s", *ws.Status) + } + + return ws, State_Configuring, nil + } +} +func isWaitForNSGStatus(ctx context.Context, client *instance.IBMPIWorkspacesClient, id, action string, timeout time.Duration) (interface{}, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Configuring, State_Removing}, + Target: []string{State_Active, State_Inactive}, + Refresh: isPERWorkspaceNSGRefreshFunc(client, id, action), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPERWorkspaceNSGRefreshFunc(client *instance.IBMPIWorkspacesClient, id, action string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + ws, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if *(ws.Details.NetworkSecurityGroups.State) == State_Active && action == Enable { + return ws, State_Active, nil + } + if *(ws.Details.NetworkSecurityGroups.State) == State_Inactive && action == Disable { + return ws, State_Inactive, nil + } + if *(ws.Details.NetworkSecurityGroups.State) == State_Removing { + return ws, State_Removing, nil + } + if *(ws.Details.NetworkSecurityGroups.State) == State_Error { + return ws, *ws.Details.NetworkSecurityGroups.State, fmt.Errorf("[ERROR] workspace network security group configuration failed to %s", action) + } + + return ws, State_Configuring, nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_network_security_group_action_test.go b/ibm/service/power/resource_ibm_pi_network_security_group_action_test.go new file mode 100644 index 0000000000..d7cb8683b2 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_security_group_action_test.go @@ -0,0 +1,44 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" +) + +func TestAccIBMPINetworkSecurityGroupActionBasic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkSecurityGroupActionConfigBasic(power.Enable), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_pi_network_security_group_action.network_security_group_action", "pi_action", power.Enable), + ), + }, + { + Config: testAccCheckIBMPINetworkSecurityGroupActionConfigBasic(power.Disable), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_pi_network_security_group_action.network_security_group_action", "pi_action", power.Disable), + ), + }, + }, + }) +} + +func testAccCheckIBMPINetworkSecurityGroupActionConfigBasic(action string) string { + return fmt.Sprintf(` + resource "ibm_pi_network_security_group_action" "network_security_group_action" { + pi_action = "%[1]s" + pi_cloud_id = "%[2]s" + }`, action, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/resource_ibm_pi_network_security_group_member.go b/ibm/service/power/resource_ibm_pi_network_security_group_member.go new file mode 100644 index 0000000000..50fd0e7614 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_security_group_member.go @@ -0,0 +1,386 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "slices" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" +) + +func ResourceIBMPINetworkSecurityGroupMember() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPINetworkSecurityGroupMemberCreate, + ReadContext: resourceIBMPINetworkSecurityGroupMemberRead, + DeleteContext: resourceIBMPINetworkSecurityGroupMemberDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + ForceNew: true, + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_NetworkSecurityGroupID: { + Description: "network security group ID.", + ForceNew: true, + Required: true, + Type: schema.TypeString, + }, + Arg_NetworkSecurityGroupMemberID: { + ConflictsWith: []string{Arg_Target, Arg_Type}, + Description: "network security group member ID.", + ForceNew: true, + Optional: true, + Type: schema.TypeString, + }, + Arg_Target: { + ConflictsWith: []string{Arg_NetworkSecurityGroupMemberID}, + Description: "The target member to add. An IP4 address if ipv4-address type or a network interface ID if network-interface type.", + ForceNew: true, + Optional: true, + RequiredWith: []string{Arg_Type}, + Type: schema.TypeString, + }, + Arg_Type: { + ConflictsWith: []string{Arg_NetworkSecurityGroupMemberID}, + Description: "The type of member.", + ForceNew: true, + Optional: true, + RequiredWith: []string{Arg_Target}, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{IPV4_Address, Network_Interface}), + }, + // Attributes + Attr_CRN: { + Computed: true, + Description: "The network security group's crn.", + Type: schema.TypeString, + }, + Attr_Members: { + Computed: true, + Description: "The list of IPv4 addresses and, or network interfaces in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the member in a network security group.", + Type: schema.TypeString, + }, + Attr_MacAddress: { + Computed: true, + Description: "The mac address of a network interface included if the type is network-interface.", + Type: schema.TypeString, + }, + Attr_Target: { + Computed: true, + Description: "If ipv4-address type, then IPv4 address or if network-interface type, then network interface ID.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of member.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Name: { + Computed: true, + Description: "The name of the network security group.", + Type: schema.TypeString, + }, + Attr_NetworkSecurityGroupMemberID: { + Computed: true, + Description: "The ID of the network security group.", + Type: schema.TypeString, + }, + Attr_Rules: { + Computed: true, + Description: "The list of rules in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Action: { + Computed: true, + Description: "The action to take if the rule matches network traffic.", + Type: schema.TypeString, + }, + Attr_DestinationPort: { + Computed: true, + Description: "The list of destination port.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_ID: { + Computed: true, + Description: "The ID of the rule in a network security group.", + Type: schema.TypeString, + }, + Attr_Protocol: { + Computed: true, + Description: "The list of protocol.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ICMPType: { + Computed: true, + Description: "IIf icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched.", + Type: schema.TypeString, + }, + Attr_TCPFlags: { + Computed: true, + Description: "If tcp type, the list of TCP flags and if not present then all flags are matched.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Flag: { + Computed: true, + Description: "TCP flag.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Type: { + Computed: true, + Description: "The protocol of the network traffic.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Remote: { + Computed: true, + Description: "List of remote.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the remote Network Address Group or network security group the rules apply to. Not required for default-network-address-group.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of remote group the rules apply to.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_SourcePort: { + Computed: true, + Description: "List of source port", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + }, + }, + Optional: true, + Type: schema.TypeList, + }, + Attr_UserTags: { + Computed: true, + Description: "List of user tags attached to the resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Type: schema.TypeSet, + }, + }, + } +} + +func resourceIBMPINetworkSecurityGroupMemberCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + nsgID := d.Get(Arg_NetworkSecurityGroupID).(string) + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + if mbrID, ok := d.GetOk(Arg_NetworkSecurityGroupMemberID); ok { + err = nsgClient.DeleteMember(nsgID, mbrID.(string)) + if err != nil { + return diag.FromErr(err) + } + _, err = isWaitForIBMPINetworkSecurityGroupMemberDeleted(ctx, nsgClient, nsgID, mbrID.(string), d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, nsgID)) + } else { + target := d.Get(Arg_Target).(string) + mbrType := d.Get(Arg_Type).(string) + body := &models.NetworkSecurityGroupAddMember{ + Target: &target, + Type: &mbrType, + } + member, err := nsgClient.AddMember(nsgID, body) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, nsgID, *member.ID)) + } + + return resourceIBMPINetworkSecurityGroupMemberRead(ctx, d, meta) +} + +func resourceIBMPINetworkSecurityGroupMemberRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, parts[0]) + networkSecurityGroup, err := nsgClient.Get(parts[1]) + if err != nil { + if strings.Contains(strings.ToLower(err.Error()), NotFound) { + d.SetId("") + return nil + } + return diag.FromErr(err) + } + + if networkSecurityGroup.Crn != nil { + d.Set(Attr_CRN, networkSecurityGroup.Crn) + userTags, err := flex.GetTagsUsingCRN(meta, string(*networkSecurityGroup.Crn)) + if err != nil { + log.Printf("Error on get of network security group (%s) user_tags: %s", parts[1], err) + } + d.Set(Arg_UserTags, userTags) + } + if len(networkSecurityGroup.Members) > 0 { + members := []map[string]interface{}{} + for _, mbr := range networkSecurityGroup.Members { + mbrMap := networkSecurityGroupMemberToMap(mbr) + members = append(members, mbrMap) + } + d.Set(Attr_Members, members) + } else { + d.Set(Attr_Members, nil) + } + d.Set(Attr_Name, networkSecurityGroup.Name) + d.Set(Attr_NetworkSecurityGroupMemberID, networkSecurityGroup.ID) + + if len(networkSecurityGroup.Rules) > 0 { + rules := []map[string]interface{}{} + for _, rule := range networkSecurityGroup.Rules { + ruleMap := networkSecurityGroupRuleToMap(rule) + rules = append(rules, ruleMap) + } + d.Set(Attr_Rules, rules) + } else { + d.Set(Attr_Rules, nil) + } + + return nil +} + +func resourceIBMPINetworkSecurityGroupMemberDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + if len(parts) > 2 { + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, parts[0]) + err = nsgClient.DeleteMember(parts[1], parts[2]) + if err != nil { + return diag.FromErr(err) + } + _, err = isWaitForIBMPINetworkSecurityGroupMemberDeleted(ctx, nsgClient, parts[1], parts[2], d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + } + + d.SetId("") + + return nil +} +func isWaitForIBMPINetworkSecurityGroupMemberDeleted(ctx context.Context, client *instance.IBMPINetworkSecurityGroupClient, nsgID, nsgMemberID string, timeout time.Duration) (interface{}, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Deleting}, + Target: []string{State_NotFound}, + Refresh: isIBMPINetworkSecurityGroupMemberDeleteRefreshFunc(client, nsgID, nsgMemberID), + Delay: 10 * time.Second, + MinTimeout: Timeout_Active, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPINetworkSecurityGroupMemberDeleteRefreshFunc(client *instance.IBMPINetworkSecurityGroupClient, nsgID, nsgMemberID string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + nsg, err := client.Get(nsgID) + if err != nil { + return nsg, "", err + } + var mbrIDs []string + for _, mbr := range nsg.Members { + mbrIDs = append(mbrIDs, *mbr.ID) + } + if !slices.Contains(mbrIDs, nsgMemberID) { + return nsg, State_NotFound, nil + } + return nsg, State_Deleting, nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_network_security_group_member_test.go b/ibm/service/power/resource_ibm_pi_network_security_group_member_test.go new file mode 100644 index 0000000000..e716bc6ff2 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_security_group_member_test.go @@ -0,0 +1,93 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" +) + +func TestAccIBMPINetworkSecurityGroupMemberBasic(t *testing.T) { + + typeVar := "network-interface" + name := fmt.Sprintf("tf-nsg-name-%d", acctest.RandIntRange(10, 100)) + network_name := fmt.Sprintf("tf-nsg-network-%d", acctest.RandIntRange(10, 100)) + network_interface_name := fmt.Sprintf("tf-nsg-network-int-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkSecurityGroupMemberConfigBasic(name, typeVar, network_name, network_interface_name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMPINetworkSecurityGroupMemberExists("ibm_pi_network_security_group_member.network_security_group_member"), + resource.TestCheckResourceAttrSet("ibm_pi_network_security_group_member.network_security_group_member", power.Arg_NetworkSecurityGroupID), + resource.TestCheckResourceAttr("ibm_pi_network_security_group_member.network_security_group_member", "pi_type", typeVar), + resource.TestCheckResourceAttrSet("ibm_pi_network_security_group_member.network_security_group_member", power.Attr_Name), + ), + }, + }, + }) +} + +func testAccCheckIBMPINetworkSecurityGroupMemberConfigBasic(name, typeVar, network_name, network_interface_name string) string { + return testAccCheckIBMPINetworkSecurityGroupConfigBasic(name) + fmt.Sprintf(` + resource "ibm_pi_network" "network" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[3]s" + pi_network_type = "vlan" + pi_cidr = "192.168.17.0/24" + } + resource "ibm_pi_network_interface" "network_interface" { + pi_cloud_instance_id = "%[1]s" + pi_name = "%[4]s" + pi_network_id = ibm_pi_network.network.network_id + depends_on = [ibm_pi_network.network] + } + resource "ibm_pi_network_security_group_member" "network_security_group_member" { + pi_cloud_instance_id = "%[1]s" + pi_network_security_group_id = ibm_pi_network_security_group.network_security_group.network_security_group_id + pi_target = ibm_pi_network_interface.network_interface.network_interface_id + pi_type = "%[2]s" + }`, acc.Pi_cloud_instance_id, typeVar, network_name, network_interface_name) +} + +func testAccCheckIBMPINetworkSecurityGroupMemberExists(n string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, nsgID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(context.Background(), sess, cloudInstanceID) + _, err = nsgClient.Get(nsgID) + if err != nil { + return err + } + return nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_network_security_group_rule.go b/ibm/service/power/resource_ibm_pi_network_security_group_rule.go new file mode 100644 index 0000000000..2d8461bbe4 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_security_group_rule.go @@ -0,0 +1,595 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func ResourceIBMPINetworkSecurityGroupRule() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPINetworkSecurityGroupRuleCreate, + ReadContext: resourceIBMPINetworkSecurityGroupRuleRead, + DeleteContext: resourceIBMPINetworkSecurityGroupRuleDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Arguments + Arg_Action: { + ConflictsWith: []string{Arg_NetworkSecurityGroupRuleID}, + Description: "The action to take if the rule matches network traffic.", + ForceNew: true, + Optional: true, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{Allow, Deny}), + }, + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + ForceNew: true, + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_DestinationPorts: { + ConflictsWith: []string{Arg_NetworkSecurityGroupRuleID}, + Description: "Destination port ranges.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Default: 65535, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Optional: true, + Type: schema.TypeInt, + }, + Attr_Minimum: { + Default: 1, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Optional: true, + Type: schema.TypeInt, + }, + }, + }, + ForceNew: true, + MaxItems: 1, + Optional: true, + Type: schema.TypeList, + }, + Arg_NetworkSecurityGroupID: { + Description: "The unique identifier of the network security group.", + ForceNew: true, + Required: true, + Type: schema.TypeString, + }, + Arg_NetworkSecurityGroupRuleID: { + ConflictsWith: []string{Arg_Action, Arg_DestinationPorts, Arg_Protocol, Arg_Remote, Arg_SourcePorts}, + Description: "The network security group rule id to remove.", + ForceNew: true, + Optional: true, + Type: schema.TypeString, + }, + Arg_Protocol: { + ConflictsWith: []string{Arg_NetworkSecurityGroupRuleID}, + Description: "The protocol of the network traffic.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ICMPType: { + Description: "If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched.", + Optional: true, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{All, DestinationUnreach, Echo, EchoReply, SourceQuench, TimeExceeded}), + }, + Attr_TCPFlags: { + Description: "If tcp type, the list of TCP flags and if not present then all flags are matched.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Flag: { + Description: "TCP flag.", + Required: true, + Type: schema.TypeString, + }, + }, + }, + Optional: true, + Type: schema.TypeSet, + }, + Attr_Type: { + Description: "The protocol of the network traffic.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{All, ICMP, TCP, UDP}), + }, + }, + }, + ForceNew: true, + MaxItems: 1, + Optional: true, + Type: schema.TypeList, + }, + Arg_Remote: { + ConflictsWith: []string{Arg_NetworkSecurityGroupRuleID}, + Description: "The protocol of the network traffic.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Description: "The ID of the remote network address group or network security group the rules apply to. Not required for default-network-address-group.", + Optional: true, + Type: schema.TypeString, + }, + Attr_Type: { + Description: "The type of remote group (MAC addresses, IP addresses, CIDRs, external CIDRs) that are the originators of rule's network traffic to match.", + Optional: true, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{DefaultNAG, NAG, NSG}), + }, + }, + }, + ForceNew: true, + MaxItems: 1, + Optional: true, + Type: schema.TypeList, + }, + Arg_SourcePorts: { + ConflictsWith: []string{Arg_NetworkSecurityGroupRuleID}, + Description: "Source port ranges.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Default: 65535, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Optional: true, + Type: schema.TypeInt, + }, + Attr_Minimum: { + Default: 1, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Optional: true, + Type: schema.TypeInt, + }, + }, + }, + ForceNew: true, + MaxItems: 1, + Optional: true, + Type: schema.TypeList, + }, + + // Attributes + Attr_CRN: { + Computed: true, + Description: "The network security group's crn.", + Type: schema.TypeString, + }, + Attr_Members: { + Computed: true, + Description: "The list of IPv4 addresses and, or network interfaces in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the member in a network security group.", + Type: schema.TypeString, + }, + Attr_MacAddress: { + Computed: true, + Description: "The mac address of a network interface included if the type is network-interface.", + Type: schema.TypeString, + }, + Attr_Target: { + Computed: true, + Description: "If ipv4-address type, then IPv4 address or if network-interface type, then network interface ID.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of member.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Name: { + Computed: true, + Description: "The name of the network security group.", + Type: schema.TypeString, + }, + Attr_NetworkSecurityGroupID: { + Computed: true, + Description: "The unique identifier of the network security group.", + Type: schema.TypeString, + }, + Attr_Rules: { + Computed: true, + Description: "The list of rules in the network security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Action: { + Computed: true, + Description: "The action to take if the rule matches network traffic.", + Type: schema.TypeString, + }, + Attr_DestinationPort: { + Computed: true, + Description: "Destination port ranges.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeInt, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeInt, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_ID: { + Computed: true, + Description: "The ID of the rule in a network security group.", + Type: schema.TypeString, + }, + Attr_Protocol: { + Computed: true, + Description: "The list of protocol.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ICMPType: { + Computed: true, + Description: "If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched.", + Type: schema.TypeString, + }, + Attr_TCPFlags: { + Computed: true, + Description: "If tcp type, the list of TCP flags and if not present then all flags are matched.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Flag: { + Computed: true, + Description: "TCP flag.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Type: { + Computed: true, + Description: "The protocol of the network traffic.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_Remote: { + Computed: true, + Description: "List of remote.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Computed: true, + Description: "The ID of the remote network address group or network security group the rules apply to. Not required for default-network-address-group.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "The type of remote group the rules apply to.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_SourcePort: { + Computed: true, + Description: "Source port ranges.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Maximum: { + Computed: true, + Description: "The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number.", + Type: schema.TypeFloat, + }, + Attr_Minimum: { + Computed: true, + Description: "The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number.", + Type: schema.TypeFloat, + }, + }, + }, + Type: schema.TypeList, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_UserTags: { + Computed: true, + Description: "List of user tags attached to the resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Type: schema.TypeSet, + }, + }, + } +} + +func resourceIBMPINetworkSecurityGroupRuleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + nsgID := d.Get(Arg_NetworkSecurityGroupID).(string) + + if v, ok := d.GetOk(Arg_NetworkSecurityGroupRuleID); ok { + ruleID := v.(string) + err := nsgClient.DeleteRule(nsgID, ruleID) + if err != nil { + if strings.Contains(strings.ToLower(err.Error()), NotFound) { + d.SetId("") + return nil + } + return diag.FromErr(err) + } + _, err = isWaitForIBMPINetworkSecurityGroupRuleRemove(ctx, nsgClient, nsgID, ruleID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, nsgID)) + } else { + action := d.Get(Arg_Action).(string) + + networkSecurityGroupAddRule := models.NetworkSecurityGroupAddRule{ + Action: &action, + } + + // Add protocol + protocol := d.Get(Arg_Protocol + ".0").(map[string]interface{}) + networkSecurityGroupAddRule.Protocol = networkSecurityGroupRuleMapToProtocol(protocol) + + // Add remote + remote := d.Get(Arg_Remote + ".0").(map[string]interface{}) + networkSecurityGroupAddRule.Remote = networkSecurityGroupRuleMapToRemote(remote) + + // Optional fields + destinationPort := d.Get(Arg_DestinationPorts + ".0").(map[string]interface{}) + networkSecurityGroupAddRule.DestinationPorts = networkSecurityGroupRuleMapToPort(destinationPort) + + sourcePort := d.Get(Arg_SourcePorts + ".0").(map[string]interface{}) + networkSecurityGroupAddRule.SourcePorts = networkSecurityGroupRuleMapToPort(sourcePort) + + networkSecurityGroup, err := nsgClient.AddRule(nsgID, &networkSecurityGroupAddRule) + ruleID := *networkSecurityGroup.ID + if err != nil { + return diag.FromErr(err) + } + _, err = isWaitForIBMPINetworkSecurityGroupRuleAdd(ctx, nsgClient, nsgID, ruleID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, nsgID, ruleID)) + } + + return resourceIBMPINetworkSecurityGroupRuleRead(ctx, d, meta) +} + +func resourceIBMPINetworkSecurityGroupRuleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID, nsgID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + networkSecurityGroup, err := nsgClient.Get(nsgID) + if err != nil { + return diag.FromErr(err) + } + d.Set(Attr_Name, networkSecurityGroup.Name) + + if networkSecurityGroup.Crn != nil { + d.Set(Attr_CRN, networkSecurityGroup.Crn) + userTags, err := flex.GetTagsUsingCRN(meta, string(*networkSecurityGroup.Crn)) + if err != nil { + log.Printf("Error on get of network security group (%s) user_tags: %s", nsgID, err) + } + d.Set(Arg_UserTags, userTags) + } + + if len(networkSecurityGroup.Members) > 0 { + members := []map[string]interface{}{} + for _, mbr := range networkSecurityGroup.Members { + mbrMap := networkSecurityGroupMemberToMap(mbr) + members = append(members, mbrMap) + } + d.Set(Attr_Members, members) + } else { + d.Set(Attr_Members, []string{}) + } + + d.Set(Attr_NetworkSecurityGroupID, networkSecurityGroup.ID) + if len(networkSecurityGroup.Rules) > 0 { + rules := []map[string]interface{}{} + for _, rule := range networkSecurityGroup.Rules { + ruleMap := networkSecurityGroupRuleToMap(rule) + rules = append(rules, ruleMap) + } + d.Set(Attr_Rules, rules) + } else { + d.Set(Attr_Rules, []string{}) + } + return nil +} + +func resourceIBMPINetworkSecurityGroupRuleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ids, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + if len(ids) == 3 { + cloudInstanceID := ids[0] + nsgID := ids[1] + ruleID := ids[2] + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(ctx, sess, cloudInstanceID) + + err = nsgClient.DeleteRule(nsgID, ruleID) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForIBMPINetworkSecurityGroupRuleRemove(ctx, nsgClient, nsgID, ruleID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + } + d.SetId("") + return nil +} + +func isWaitForIBMPINetworkSecurityGroupRuleAdd(ctx context.Context, client *instance.IBMPINetworkSecurityGroupClient, id, ruleID string, timeout time.Duration) (interface{}, error) { + + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Pending}, + Target: []string{State_Available}, + Refresh: isIBMPINetworkSecurityGroupRuleAddRefreshFunc(client, id, ruleID), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPINetworkSecurityGroupRuleAddRefreshFunc(client *instance.IBMPINetworkSecurityGroupClient, id, ruleID string) retry.StateRefreshFunc { + + return func() (interface{}, string, error) { + networkSecurityGroup, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if networkSecurityGroup.Rules != nil { + for _, rule := range networkSecurityGroup.Rules { + if *rule.ID == ruleID { + return networkSecurityGroup, State_Available, nil + } + + } + } + return networkSecurityGroup, State_Pending, nil + } +} + +func isWaitForIBMPINetworkSecurityGroupRuleRemove(ctx context.Context, client *instance.IBMPINetworkSecurityGroupClient, id, ruleID string, timeout time.Duration) (interface{}, error) { + + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Pending}, + Target: []string{State_Removed}, + Refresh: isIBMPINetworkSecurityGroupRuleRemoveRefreshFunc(client, id, ruleID), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPINetworkSecurityGroupRuleRemoveRefreshFunc(client *instance.IBMPINetworkSecurityGroupClient, id, ruleID string) retry.StateRefreshFunc { + + return func() (interface{}, string, error) { + networkSecurityGroup, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if networkSecurityGroup.Rules != nil { + foundRule := false + for _, rule := range networkSecurityGroup.Rules { + if *rule.ID == ruleID { + foundRule = true + return networkSecurityGroup, State_Pending, nil + } + } + if !foundRule { + return networkSecurityGroup, State_Removed, nil + } + } + return networkSecurityGroup, State_Pending, nil + } +} + +func networkSecurityGroupRuleMapToPort(portMap map[string]interface{}) *models.NetworkSecurityGroupRulePort { + networkSecurityGroupRulePort := models.NetworkSecurityGroupRulePort{} + if portMap[Attr_Maximum] != nil { + networkSecurityGroupRulePort.Maximum = int64(portMap[Attr_Maximum].(int)) + } + if portMap[Attr_Minimum] != nil { + networkSecurityGroupRulePort.Minimum = int64(portMap[Attr_Minimum].(int)) + } + return &networkSecurityGroupRulePort +} + +func networkSecurityGroupRuleMapToRemote(remoteMap map[string]interface{}) *models.NetworkSecurityGroupRuleRemote { + networkSecurityGroupRuleRemote := models.NetworkSecurityGroupRuleRemote{} + if remoteMap[Attr_ID].(string) != "" { + networkSecurityGroupRuleRemote.ID = remoteMap[Attr_ID].(string) + } + networkSecurityGroupRuleRemote.Type = remoteMap[Attr_Type].(string) + return &networkSecurityGroupRuleRemote +} + +func networkSecurityGroupRuleMapToProtocol(protocolMap map[string]interface{}) *models.NetworkSecurityGroupRuleProtocol { + networkSecurityGroupRuleProtocol := models.NetworkSecurityGroupRuleProtocol{} + networkSecurityGroupRuleProtocol.Type = protocolMap[Attr_Type].(string) + + if networkSecurityGroupRuleProtocol.Type == ICMP { + icmpType := protocolMap[Attr_ICMPType].(string) + networkSecurityGroupRuleProtocol.IcmpType = &icmpType + } else if networkSecurityGroupRuleProtocol.Type == TCP { + tcpMaps := protocolMap[Attr_TCPFlags].(*schema.Set) + networkSecurityGroupRuleProtocolTCPFlagArray := []*models.NetworkSecurityGroupRuleProtocolTCPFlag{} + for _, tcpMap := range tcpMaps.List() { + flag := tcpMap.(map[string]interface{}) + networkSecurityGroupRuleProtocolTCPFlag := models.NetworkSecurityGroupRuleProtocolTCPFlag{} + networkSecurityGroupRuleProtocolTCPFlag.Flag = flag[Attr_Flag].(string) + networkSecurityGroupRuleProtocolTCPFlagArray = append(networkSecurityGroupRuleProtocolTCPFlagArray, &networkSecurityGroupRuleProtocolTCPFlag) + } + networkSecurityGroupRuleProtocol.TCPFlags = networkSecurityGroupRuleProtocolTCPFlagArray + } + + return &networkSecurityGroupRuleProtocol +} diff --git a/ibm/service/power/resource_ibm_pi_network_security_group_rule_test.go b/ibm/service/power/resource_ibm_pi_network_security_group_rule_test.go new file mode 100644 index 0000000000..f6234b2abf --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_security_group_rule_test.go @@ -0,0 +1,191 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" +) + +func TestAccIBMPINetworkSecurityGroupRuleBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkSecurityGroupRuleConfigAddRule(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMPINetworkSecurityGroupRuleExists("ibm_pi_network_security_group_rule.network_security_group_rule"), + resource.TestCheckResourceAttrSet("ibm_pi_network_security_group_rule.network_security_group_rule", power.Arg_NetworkSecurityGroupID), + ), + }, + }, + }) +} + +func TestAccIBMPINetworkSecurityGroupRuleTCP(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkSecurityGroupRuleConfigAddRuleTCP(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMPINetworkSecurityGroupRuleExists("ibm_pi_network_security_group_rule.network_security_group_rule"), + resource.TestCheckResourceAttrSet("ibm_pi_network_security_group_rule.network_security_group_rule", power.Arg_NetworkSecurityGroupID), + ), + }, + }, + }) +} + +func TestAccIBMPINetworkSecurityGroupRuleRemove(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkSecurityGroupRuleConfigRemoveRule(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMPINetworkSecurityGroupRuleRemoved("ibm_pi_network_security_group_rule.network_security_group_rule", acc.Pi_network_security_group_rule_id), + resource.TestCheckResourceAttrSet("ibm_pi_network_security_group_rule.network_security_group_rule", power.Arg_NetworkSecurityGroupID), + ), + }, + }, + }) +} + +func testAccCheckIBMPINetworkSecurityGroupRuleConfigAddRule() string { + return fmt.Sprintf(` + resource "ibm_pi_network_security_group_rule" "network_security_group_rule" { + pi_cloud_instance_id = "%[1]s" + pi_network_security_group_id = "%[2]s" + pi_action = "allow" + pi_protocol { + type = "all" + } + pi_remote { + id = "%[3]s" + type = "%[4]s" + } + }`, acc.Pi_cloud_instance_id, acc.Pi_network_security_group_id, acc.Pi_remote_id, acc.Pi_remote_type) +} + +func testAccCheckIBMPINetworkSecurityGroupRuleConfigAddRuleTCP() string { + return fmt.Sprintf(` + resource "ibm_pi_network_security_group_rule" "network_security_group_rule" { + pi_cloud_instance_id = "%[1]s" + pi_network_security_group_id = "%[2]s" + pi_action = "allow" + pi_destination_ports { + minimum = 1200 + maximum = 37466 + } + pi_source_ports { + minimum = 1000 + maximum = 19500 + } + pi_protocol { + tcp_flags { + flag = "ack" + } + tcp_flags { + flag = "syn" + } + tcp_flags { + flag = "psh" + } + type = "tcp" + } + pi_remote { + id = "%[3]s" + type = "%[4]s" + } + }`, acc.Pi_cloud_instance_id, acc.Pi_network_security_group_id, acc.Pi_remote_id, acc.Pi_remote_type) +} + +func testAccCheckIBMPINetworkSecurityGroupRuleConfigRemoveRule() string { + return fmt.Sprintf(` + resource "ibm_pi_network_security_group_rule" "network_security_group_rule" { + pi_cloud_instance_id = "%[1]s" + pi_network_security_group_id = "%[2]s" + pi_network_security_group_rule_id = "%[3]s" + }`, acc.Pi_cloud_instance_id, acc.Pi_network_security_group_id, acc.Pi_network_security_group_rule_id) +} + +func testAccCheckIBMPINetworkSecurityGroupRuleExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, nsgID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(context.Background(), sess, cloudInstanceID) + _, err = nsgClient.Get(nsgID) + if err != nil { + return err + } + return nil + } +} + +func testAccCheckIBMPINetworkSecurityGroupRuleRemoved(n string, ruleID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, nsgID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(context.Background(), sess, cloudInstanceID) + networkSecurityGroup, err := nsgClient.Get(nsgID) + if err != nil { + return err + } + foundRule := false + if networkSecurityGroup.Rules != nil { + for _, rule := range networkSecurityGroup.Rules { + if *rule.ID == ruleID { + foundRule = true + break + } + } + } + if foundRule { + return fmt.Errorf("NSG rule still exists") + } + return nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_network_security_group_test.go b/ibm/service/power/resource_ibm_pi_network_security_group_test.go new file mode 100644 index 0000000000..233c8dcdf4 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_security_group_test.go @@ -0,0 +1,106 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" +) + +func TestAccIBMPINetworkSecurityGroupBasic(t *testing.T) { + name := fmt.Sprintf("tf-nsg-name-%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf-nsg-name-update-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPINetworkSecurityGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkSecurityGroupConfigBasic(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMPINetworkSecurityGroupExists("ibm_pi_network_security_group.network_security_group"), + resource.TestCheckResourceAttr("ibm_pi_network_security_group.network_security_group", power.Arg_Name, name), + ), + }, + { + Config: testAccCheckIBMPINetworkSecurityGroupConfigBasic(nameUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_pi_network_security_group.network_security_group", power.Arg_Name, nameUpdate), + ), + }, + }, + }) +} + +func testAccCheckIBMPINetworkSecurityGroupConfigBasic(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_network_security_group" "network_security_group" { + pi_cloud_instance_id = "%[1]s" + pi_name = "%[2]s" + pi_user_tags = ["tag:test"] + }`, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPINetworkSecurityGroupExists(n string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, nsgID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(context.Background(), sess, cloudInstanceID) + _, err = nsgClient.Get(nsgID) + if err != nil { + return err + } + return nil + } +} + +func testAccCheckIBMPINetworkSecurityGroupDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_network_security_group" { + continue + } + + cloudInstanceID, nsgID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + nsgClient := instance.NewIBMIPINetworkSecurityGroupClient(context.Background(), sess, cloudInstanceID) + _, err = nsgClient.Get(nsgID) + if err == nil { + return fmt.Errorf("network_security_group still exists: %s", rs.Primary.ID) + } + } + + return nil +} diff --git a/website/docs/d/pi_network_security_group.html.markdown b/website/docs/d/pi_network_security_group.html.markdown new file mode 100644 index 0000000000..f3d285275d --- /dev/null +++ b/website/docs/d/pi_network_security_group.html.markdown @@ -0,0 +1,89 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_pi_network_security_group" +description: |- + Get information about pi_network_security_group +subcategory: "Power Systems" +--- + +# ibm_pi_network_security_group + +Retrieves information about a network security group. + +## Example Usage + +```terraform + data "ibm_pi_network_security_group" "network_security_group" { + pi_cloud_instance_id = "" + pi_network_security_group_id = "" + } +``` + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_network_security_group_id` - (Required, String) network security group id or name. + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `crn` - (String) The network security group's crn. + +- `members` - (List) The list of IPv4 addresses and\or network interfaces in the network security group. + + Nested schema for `members`: + - `id` - (String) The id of the member in a network security group. + - `mac_address` - (String) The mac address of a network interface included if the type is `network-interface`. + - `target` - (String) If `ipv4-address` type, then IPv4 address or if `network-interface` type, then network interface id. + - `type` - (String) The type of member. Supported values are: `ipv4-address`, `network-interface`. + +- `name` - (String) The name of the network security group. + +- `rules` - (List) The list of rules in the network security group. + + Nested schema for `rules`: + - `action` - (String) The action to take if the rule matches network traffic. Supported values are: `allow`, `deny`. + - `destination_port` - (List) The list of destination port. + + Nested schema for `destination_port`: + - `maximum` - (Integer) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Integer) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. + - `id` - (String) The id of the rule in a network security group. + - `protocol` - (List) The list of protocol. + + Nested schema for `protocol`: + - `icmp_type` - (String) If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched. + - `tcp_flags` - (List) If tcp type, the list of TCP flags and if not present then all flags are matched. Supported values are: `syn`, `ack`, `fin`, `rst`, `urg`, `psh`, `wnd`, `chk`, `seq`. + Nested schema for `icmp_types`: + - `flags` - (String) TCP flag. + - `type` - (String) The protocol of the network traffic. Supported values are: `icmp`, `tcp`, `udp`, `all`. + - `remote` - (List) List of remote. + + Nested schema for `remote`: + - `id` - (String) The id of the remote network Address group or network security group the rules apply to. Not required for default-network-address-group. + - `type` - (String) The type of remote group the rules apply to. Supported values are: `network-security-group`, `network-address-group`, `default-network-address-group`. + - `source_port` - (List) List of source port. + + Nested schema for `source_port`: + - `maximum` - (Integer) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Integer) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. +- `user_tags` - (List) List of user tags attached to the resource. diff --git a/website/docs/d/pi_network_security_groups.html.markdown b/website/docs/d/pi_network_security_groups.html.markdown new file mode 100644 index 0000000000..27f720fbad --- /dev/null +++ b/website/docs/d/pi_network_security_groups.html.markdown @@ -0,0 +1,87 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_pi_network_security_groups" +description: |- + Get information about pi_network_security_groups +subcategory: "Power Systems" +--- + +# ibm_pi_network_security_groups + +Retrieves information about network security groups. + +## Example Usage + +```terraform + data "ibm_pi_network_security_groups" "network_security_groups" { + pi_cloud_instance_id = "" + } +``` + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `network_security_groups` - (List) list of network security Groups. + + Nested schema for `network_security_groups`: + - `crn` - (String) The network security group's crn. + - `id` - (String) The id of the network security group. + - `members` - (List) The list of IPv4 addresses and\or network Interfaces in the network security group. + + Nested schema for `members`: + - `id` - (String) The id of the member in a network security group. + - `mac_address` - (String) The mac address of a network Interface included if the type is `network-interface`. + - `target` - (String) If `ipv4-address` type, then IPv4 address or if `network-interface` type, then network interface id. + - `type` - (String) The type of member. Supported values are: `ipv4-address`, `network-interface`. + - `name` - (String) The name of the network security group. + - `rules` - (List) The list of rules in the network security group. + + Nested schema for `rules`: + - `action` - (String) The action to take if the rule matches network traffic. Supported values are: `allow`, `deny`. + - `destination_port` - (List) List of destination port. + + Nested schema for `destination_port`: + - `maximum` - (Integer) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Integer) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. + + - `id` - (String) The id of the rule in a network security group. + - `protocol` - (List) List of protocol. + + Nested schema for `protocol`: + - `icmp_type` - (String) If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched. + - `tcp_flags` - (String) If tcp type, the list of TCP flags and if not present then all flags are matched. Supported values are: `syn`, `ack`, `fin`, `rst`, `urg`, `psh`, `wnd`, `chk`, `seq`. + - `type` - (String) The protocol of the network traffic. Supported values are: `icmp`, `tcp`, `udp`, `all`. + - `remote` - (List) List of remote. + + Nested schema for `remote`: + - `id` - (String) The id of the remote network Address group or network security group the rules apply to. Not required for default-network-address-group. + - `type` - (String) The type of remote group the rules apply to. Supported values are: `network-security-group`, `network-address-group`, `default-network-address-group`. + - `source_port` - (List) List of source port. + + Nested schema for `source_port`: + - `maximum` - (Integer) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Integer) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. + - `user_tags` - (List) List of user tags attached to the resource. diff --git a/website/docs/r/pi_network_security_group.html.markdown b/website/docs/r/pi_network_security_group.html.markdown new file mode 100644 index 0000000000..c36afbec78 --- /dev/null +++ b/website/docs/r/pi_network_security_group.html.markdown @@ -0,0 +1,103 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_pi_network_security_group" +description: |- + Manages pi_network_security_group. +subcategory: "Power Systems" +--- + +# ibm_pi_network_security_group + +Create, update, and delete a network security group. + +## Example Usage + +```terraform + resource "ibm_pi_network_security_group" "network_security_group" { + pi_cloud_instance_id = "" + pi_name = "name" + pi_user_tags = ["tag1", "tag2"] + } +``` + +## Timeouts + +The `ibm_pi_network_security_group` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **delete** - (Default 10 minutes) Used for deleting a network security group. + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument Reference + +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_name` - (Required, String) The name of the Network Security Group. +- `pi_user_tags` - (Optional, List) A list of tags. + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `crn` - (String) The network security group's crn. +- `id` - (String) The unique identifier of the network security group resource. Composed of `/` +- `members` - (List) The list of IPv4 addresses and\or network interfaces in the network security group. + + Nested schema for `members`: + - `id` - (String) The id of the member in a network security group. + - `mac_address` - (String) The mac address of a network interface included if the type is `network-interface`. + - `target` - (String) If `ipv4-address` type, then IPv4 address or if `network-interface` type, then network interface id. + - `type` - (String) The type of member. Supported values are: `ipv4-address`, `network-interface`. + +- `network_security_group_id` - (String) The unique identifier of the network security group. +- `rules` - (List) The list of rules in the network security group. + + Nested schema for `rules`: + - `action` - (String) The action to take if the rule matches network traffic. Supported values are: `allow`, `deny`. + - `destination_port` - (List) The list of destination port. + + Nested schema for `destination_port`: + - `maximum` - (Integer) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Integer) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. + - `id` - (String) The id of the rule in a network security group. + - `protocol` - (List) The list of protocol. + + Nested schema for `protocol`: + - `icmp_type` - (String) If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched. + - `tcp_flags` - (String) If tcp type, the list of TCP flags and if not present then all flags are matched. Supported values are: `syn`, `ack`, `fin`, `rst`, `urg`, `psh`, `wnd`, `chk`, `seq`. + - `type` - (String) The protocol of the network traffic. Supported values are: `icmp`, `tcp`, `udp`, `all`. + - `remote` - (List) List of remote. + + Nested schema for `remote`: + - `id` - (String) The id of the remote network Address group or network security group the rules apply to. Not required for default-network-address-group. + - `type` - (String) The type of remote group the rules apply to. Supported values are: `network-security-group`, `network-address-group`, `default-network-address-group`. + - `source_port` - (List) List of source port + + Nested schema for `source_port`: + - `maximum` - (Integer) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Integer) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. + +## Import + +The `ibm_pi_network_security_group` resource can be imported by using `cloud_instance_id` and `network_security_group_id`. + +## Example + +```bash +terraform import ibm_pi_network_security_group.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +``` diff --git a/website/docs/r/pi_network_security_group_action.html.markdown b/website/docs/r/pi_network_security_group_action.html.markdown new file mode 100644 index 0000000000..39f2a36dc3 --- /dev/null +++ b/website/docs/r/pi_network_security_group_action.html.markdown @@ -0,0 +1,56 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_pi_network_security_group_action" +description: |- + Manages pi_network_security_group_action. +subcategory: "Power Systems" +--- + +# ibm_pi_network_security_group_action + +Enable or disable a network security group in your workspace. + +## Example Usage + +```terraform + resource "ibm_pi_network_security_group_action" "network_security_group_action" { + pi_cloud_instance_id = "" + pi_action = "enable" + } +``` + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The `ibm_pi_network_security_group_action` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 5 minutes) Used for enabling a network security group. +- **update** - (Default 5 minutes) Used for disabling a network security group. + +## Argument Reference + +Review the argument references that you can specify for your resource. + +- `pi_action` - (Required, String) Name of the action to take; can be enable to enable NSGs in a workspace or disable to disable NSGs in a workspace. Supported values are: `enable`, `disable`. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `state` - (String) The workspace network security group's state. diff --git a/website/docs/r/pi_network_security_group_member.html.markdown b/website/docs/r/pi_network_security_group_member.html.markdown new file mode 100644 index 0000000000..f0d4d6e540 --- /dev/null +++ b/website/docs/r/pi_network_security_group_member.html.markdown @@ -0,0 +1,108 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_pi_network_security_group_member" +description: |- + Manages pi_network_security_group_member. +subcategory: "Power Systems" +--- + +# ibm_pi_network_security_group_member + +Add or remove a network security group member. + +## Example Usage + +```terraform + resource "ibm_pi_network_security_group_member" "network_security_group_member" { + pi_cloud_instance_id = "" + pi_network_security_group_id = "network_security_group_id" + pi_target = "target" + pi_type = "ipv4-address" + } +``` + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The `ibm_pi_network_security_group_member` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **delete** - (Default 5 minutes) Used for deleting a network security group member. + +## Argument Reference + +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_network_security_group_id` - (Required, String) Network security group ID. +- `pi_network_security_group_member_id` - (Optional, String) Network security group member ID. This conflicts with `pi_target` and `pi_type`. +- `pi_target` - (Optional, String) The target member to add. Required with `pi_type`. This conflicts with `pi_network_security_group_member_id`. +- `pi_type` - (Optional, String) The type of member. Supported values are: `ipv4-address`, `network-interface`. Required with `pi_target`. This conflicts with `pi_network_security_group_member_id`. + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `crn` - (String) The network security group's crn. +- `id` - (String) The unique identifier of the network security group resource. Composed of `//` +- `members` - (List) The list of IPv4 addresses and\or network interfaces in the network security group. + + Nested schema for `members`: + - `id` - (String) The id of the member in a network security group. + - `mac_address` - (String) The mac address of a network interface included if the type is `network-interface`. + - `target` - (String) If `ipv4-address` type, then IPv4 address or if `network-interface` type, then network interface id. + - `type` - (String) The type of member. Supported values are: `ipv4-address`, `network-interface`. + +- `name` - (String) The name of the network security group. +- `network_security_group_member_id` - (String) The unique identifier of the network security group resource. +- `rules` - (List) The list of rules in the network security group. + + Nested schema for `rules`: + - `action` - (String) The action to take if the rule matches network traffic. Supported values are: `allow`, `deny`. + - `destination_port` - (List) The list of destination port. + + Nested schema for `destination_port`: + - `maximum` - (Integer) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Integer) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. + - `id` - (String) The id of the rule in a network security group. + - `protocol` - (List) The list of protocol. + + Nested schema for `protocol`: + - `icmp_type` - (String) If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched. + - `tcp_flags` - (String) If tcp type, the list of TCP flags and if not present then all flags are matched. Supported values are: `syn`, `ack`, `fin`, `rst`, `urg`, `psh`, `wnd`, `chk`, `seq`. + - `type` - (String) The protocol of the network traffic. Supported values are: `icmp`, `tcp`, `udp`, `all`. + - `remote` - (List) List of remote. + + Nested schema for `remote`: + - `id` - (String) The id of the remote network Address group or network security group the rules apply to. Not required for default-network-address-group. + - `type` - (String) The type of remote group the rules apply to. Supported values are: `network-security-group`, `network-address-group`, `default-network-address-group`. + - `source_port` - (List) List of source port + + Nested schema for `source_port`: + - `maximum` - (Integer) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Integer) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum +- `user_tags` - (List) List of user tags attached to the resource. + +## Import + +The `ibm_pi_network_security_group_member` resource can be imported by using `cloud_instance_id`, `network_security_group_id` and `network_security_group_member_id`. + +## Example + +```bash +terraform import ibm_pi_network_security_group_member.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +``` diff --git a/website/docs/r/pi_network_security_group_rule.html.markdown b/website/docs/r/pi_network_security_group_rule.html.markdown new file mode 100644 index 0000000000..4dc7aba8ed --- /dev/null +++ b/website/docs/r/pi_network_security_group_rule.html.markdown @@ -0,0 +1,154 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_pi_network_security_group_rule" +description: |- + Manages pi_network_security_group_rule. +subcategory: "Power Systems" +--- + +# ibm_pi_network_security_group_rule + +Add or remove a network security group rule. + +## Example Usage + +```terraform + resource "ibm_pi_network_security_group_rule" "network_security_group_rule" { + pi_cloud_instance_id = "" + pi_network_security_group_id = "" + pi_action = "allow" + pi_destination_ports { + minimum = 1200 + maximum = 37466 + } + pi_source_ports { + minimum = 1000 + maximum = 19500 + } + pi_protocol { + tcp_flags { + flag = "ack" + } + tcp_flags { + flag = "syn" + } + tcp_flags { + flag = "psh" + } + type = "tcp" + } + pi_remote { + id = "" + type = "network-security-group" + } + } +``` + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The `ibm_pi_network_security_group` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 10 minutes) Used for creating a network security group rule. +- **delete** - (Default 10 minutes) Used for deleting a network security group rule. + +## Argument Reference + +Review the argument references that you can specify for your resource. + +- `pi_action` - (Optional, String) The action to take if the rule matches network traffic. Supported values are: `allow`, `deny`. Required if `pi_network_security_group_rule_id` is not provided. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_destination_port` - (Optional, List) The list of destination port. + + Nested schema for `pi_destination_port`: + - `maximum` - (Optional, Int) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Optional, Int) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. +- `pi_network_security_group_id` - (Required, String) The unique identifier of the network security group. +- `pi_network_security_group_rule_id` - (Optional, String) The network security group rule id to remove. Required if none of the other optional fields are provided. +- `pi_protocol` - (Optional, List) The list of protocol. Required if `pi_network_security_group_rule_id` is not provided. + + Nested schema for `pi_protocol`: + - `icmp_type` - (Optional, String) If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched. Supported values are: `all`, `destination-unreach`, `echo`, `echo-reply`, `source-quench`, `time-exceeded`. + - `tcp_flags` - (Optional, String) If tcp type, the list of TCP flags and if not present then all flags are matched. Supported values are: `syn`, `ack`, `fin`, `rst`, `urg`, `psh`, `wnd`, `chk`, `seq`. + - `type` - (Required, String) The protocol of the network traffic. Supported values are: `icmp`, `tcp`, `udp`, `all`. +- `pi_remote` - (Optional, List) List of remote. Required if `pi_network_security_group_rule_id` is not provided. + + Nested schema for `pi_remote`: + - `id` - (Optional, String) The id of the remote network address group or network security group the rules apply to. Not required for default-network-address-group. + - `type` - (Optional, String) The type of remote group the rules apply to. Supported values are: `network-security-group`, `network-address-group`, `default-network-address-group`. +- `pi_source_port` - (Optional, List) List of source port + + Nested schema for `pi_source_port`: + - `maximum` - (Optional, Int) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Optional, Int) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. + +- `pi_name` - (Optional, String) The name of the network security group rule. Required if `pi_network_security_group_rule_id` is not provided. + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `crn` - (String) The network security group's crn. +- `id` - (String) The unique identifier of the network security group resource. Composed of `/` +- `members` - (List) The list of IPv4 addresses and\or network interfaces in the network security group. + + Nested schema for `members`: + - `id` - (String) The id of the member in a network security group. + - `mac_address` - (String) The mac address of a network interface included if the type is `network-interface`. + - `target` - (String) If `ipv4-address` type, then IPv4 address or if `network-interface` type, then network interface id. + - `type` - (String) The type of member. Supported values are: `ipv4-address`, `network-interface`. + +- `network_security_group_id` -(String) The unique identifier of the network security group. +- `rules` - (List) The list of rules in the network security group. + + Nested schema for `rules`: + - `action` - (String) The action to take if the rule matches network traffic. Supported values are: `allow`, `deny`. + - `destination_port` - (List) The list of destination port. + + Nested schema for `destination_port`: + - `maximum` - (Int) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Int) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. + - `id` - (String) The id of the rule in a network security group. + - `name` - (String) The unique name of the network security group rule. + - `protocol` - (List) The list of protocol. + + Nested schema for `protocol`: + - `icmp_type` - (String) If icmp type, a ICMP packet type affected by ICMP rules and if not present then all types are matched. Supported values are: `all`, `destination-unreach`, `echo`, `echo-reply`, `source-quench`, `time-exceeded`. + - `tcp_flags` - (String) If tcp type, the list of TCP flags and if not present then all flags are matched. Supported values are: `syn`, `ack`, `fin`, `rst`, `urg`, `psh`, `wnd`, `chk`, `seq`. + - `type` - (String) The protocol of the network traffic. Supported values are: `icmp`, `tcp`, `udp`, `all`. + - `remote` - (List) List of remote. + + Nested schema for `remote`: + - `id` - (String) The id of the remote network address group or network security group the rules apply to. Not required for default-network-address-group. + - `type` - (String) The type of remote group the rules apply to. Supported values are: `network-security-group`, `network-address-group`, `default-network-address-group`. + - `source_port` - (List) List of source port + + Nested schema for `source_port`: + - `maximum` - (Int) The end of the port range, if applicable. If the value is not present then the default value of 65535 will be the maximum port number. + - `minimum` - (Int) The start of the port range, if applicable. If the value is not present then the default value of 1 will be the minimum port number. +- `user_tags` - (List) List of user tags attached to the resource. + +## Import + +The `ibm_pi_network_security_group_rule` resource can be imported by using `cloud_instance_id`, `network_security_group_id` and `network_security_group_rule_id`. + +## Example + +```bash +terraform import ibm_pi_network_security_group_rule.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +```