Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added docs & enhanced network-port-attach resource #3756

Merged
merged 3 commits into from
May 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ibm/service/power/resource_ibm_pi_network_port.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func ResourceIBMPINetworkPort() *schema.Resource {
Computed: true,
},
},
DeprecationMessage: "Resource ibm_pi_network_port is deprecated. Use ibm_pi_network_port_attach to create & attach a network port to a pvm instance",
}
}

Expand Down
154 changes: 105 additions & 49 deletions ibm/service/power/resource_ibm_pi_network_port_attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,63 @@ func ResourceIBMPINetworkPortAttach() *schema.Resource {

CreateContext: resourceIBMPINetworkPortAttachCreate,
ReadContext: resourceIBMPINetworkPortAttachRead,
UpdateContext: resourceIBMPINetworkPortAttachUpdate,
DeleteContext: resourceIBMPINetworkPortAttachDelete,
Importer: &schema.ResourceImporter{},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(60 * time.Minute),
Delete: schema.DefaultTimeout(60 * time.Minute),
Update: schema.DefaultTimeout(60 * time.Minute),
},
Schema: map[string]*schema.Schema{
"port_id": {
Type: schema.TypeString,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The required argument can't be removed directly needs to follow Terraform guidelines
https://www.terraform.io/plugin/sdkv2/best-practices/deprecations

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this resources we are exposin to the users for the first time ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this resource was present in an earlier version but without documentation, the network-port resource will be deprecated and the features of network-port will combine in the network-port-attach resource

Required: true,
},
helpers.PICloudInstanceId: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
helpers.PIInstanceName: {
helpers.PIInstanceId: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above can't change a argument ..

Type: schema.TypeString,
Required: true,
Description: "Instance name to attach the network port to",
ForceNew: true,
Description: "Instance id to attach the network port to",
},
helpers.PINetworkName: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Network Name - This is the subnet name in the Cloud instance",
},
helpers.PINetworkPortDescription: {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: "A human readable description for this network Port",
Default: "Port Created via Terraform",
},
helpers.PINetworkPortIPAddress: {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},

//Computed Attributes
"macaddress": {
Type: schema.TypeString,
Computed: true,
},
"port_id": {
Type: schema.TypeString,
Computed: true,
Deprecated: "port_id attribute is deprecated, use network_port_id instead.",
},
"network_port_id": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"public_ip": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -73,118 +96,152 @@ func resourceIBMPINetworkPortAttachCreate(ctx context.Context, d *schema.Resourc
if err != nil {
return diag.FromErr(err)
}

cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string)
networkname := d.Get(helpers.PINetworkName).(string)
portid := d.Get("port_id").(string)
instancename := d.Get(helpers.PIInstanceName).(string)
instanceID := d.Get(helpers.PIInstanceId).(string)
description := d.Get(helpers.PINetworkPortDescription).(string)
client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID)
nwportBody := &models.NetworkPortCreate{Description: description}

log.Printf("Printing the input to the resource: cloud instance [%s] and network name [%s] and the portid [%s]", cloudInstanceID, networkname, portid)
body := &models.NetworkPortUpdate{
if v, ok := d.GetOk(helpers.PINetworkPortIPAddress); ok {
ipaddress := v.(string)
nwportBody.IPAddress = ipaddress
}

nwportattachBody := &models.NetworkPortUpdate{
Description: &description,
PvmInstanceID: &instancename,
PvmInstanceID: &instanceID,
}
networkPortResponse, err := client.UpdatePort(networkname, portid, body)

client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID)

networkPortResponse, err := client.CreatePort(networkname, nwportBody)
if err != nil {
return diag.FromErr(err)
}

log.Printf("Printing the networkresponse %+v", &networkPortResponse)

IBMPINetworkPortID := *networkPortResponse.PortID
networkPortID := *networkPortResponse.PortID

d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, networkname, IBMPINetworkPortID))
_, err = isWaitForIBMPINetworkportAvailable(ctx, client, networkPortID, networkname, d.Timeout(schema.TimeoutCreate))
if err != nil {
return diag.FromErr(err)
}

networkPortResponse, err = client.UpdatePort(networkname, networkPortID, nwportattachBody)
if err != nil {
return diag.FromErr(err)
}

_, err = isWaitForIBMPINetworkPortAttachAvailable(ctx, client, IBMPINetworkPortID, networkname, d.Timeout(schema.TimeoutCreate))
_, err = isWaitForIBMPINetworkPortAttachAvailable(ctx, client, networkPortID, networkname, instanceID, d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.FromErr(err)
}

d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, networkname, networkPortID))

return resourceIBMPINetworkPortAttachRead(ctx, d, meta)
}

func resourceIBMPINetworkPortAttachRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("Calling ther Network Port Attach Read code")
sess, err := meta.(conns.ClientSession).IBMPISession()

if err != nil {
fmt.Printf("failed to get a session from the IBM Cloud Service %v", err)
return diag.FromErr(err)
}

parts, err := flex.IdParts(d.Id())
if err != nil {
return diag.FromErr(err)
}
cloudInstanceID := parts[0]
networkID := parts[1]
networkname := parts[1]
portID := parts[2]

networkC := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID)
networkdata, err := networkC.GetPort(networkID, portID)
networkdata, err := networkC.GetPort(networkname, portID)
if err != nil {
return diag.FromErr(err)
}

d.Set("ipaddress", networkdata.IPAddress)
d.Set(helpers.PINetworkPortIPAddress, networkdata.IPAddress)
d.Set(helpers.PINetworkPortDescription, networkdata.Description)
d.Set(helpers.PIInstanceId, networkdata.PvmInstance.PvmInstanceID)
d.Set("macaddress", networkdata.MacAddress)
d.Set("status", networkdata.Status)
d.Set("portid", networkdata.PortID)
d.Set("pvminstance", networkdata.PvmInstance.Href)
d.Set("network_port_id", networkdata.PortID)
d.Set("port_id", networkdata.PortID)
d.Set("public_ip", networkdata.ExternalIP)

return nil
}

func resourceIBMPINetworkPortAttachUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("Calling the attach update ")
return nil
}

func resourceIBMPINetworkPortAttachDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("Detaching the network port from the Instance ")

log.Printf("Calling the network delete functions. ")
sess, err := meta.(conns.ClientSession).IBMPISession()
if err != nil {
fmt.Printf("failed to get a session from the IBM Cloud Service %v", err)

return diag.FromErr(err)
}

parts, err := flex.IdParts(d.Id())
if err != nil {
return diag.FromErr(err)
}
cloudInstanceID := parts[0]
networkID := parts[1]
networkname := parts[1]
portID := parts[2]

client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID)
log.Printf("Executing network port detach")
emptyPVM := ""
body := &models.NetworkPortUpdate{
PvmInstanceID: &emptyPVM,
}
networkPort, err := client.UpdatePort(networkID, portID, body)

log.Printf("Calling the delete with the following params delete with cloud instance (%s) and networkid (%s) and portid (%s) ", cloudInstanceID, networkname, portID)
err = client.DeletePort(networkname, portID)
if err != nil {
return diag.FromErr(err)
}

log.Printf("Printing the networkresponse %+v", &networkPort)

d.SetId("")
return nil
}

func isWaitForIBMPINetworkportAvailable(ctx context.Context, client *st.IBMPINetworkClient, id string, networkname string, timeout time.Duration) (interface{}, error) {
log.Printf("Waiting for Power Network (%s) that was created for Network Zone (%s) to be available.", id, networkname)

stateConf := &resource.StateChangeConf{
Pending: []string{"retry", helpers.PINetworkProvisioning},
Target: []string{"DOWN"},
Refresh: isIBMPINetworkportRefreshFunc(client, id, networkname),
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 10 * time.Minute,
}

return stateConf.WaitForStateContext(ctx)
}

func isWaitForIBMPINetworkPortAttachAvailable(ctx context.Context, client *st.IBMPINetworkClient, id string, networkname string, timeout time.Duration) (interface{}, error) {
func isIBMPINetworkportRefreshFunc(client *st.IBMPINetworkClient, id, networkname string) resource.StateRefreshFunc {

log.Printf("Calling the IsIBMPINetwork Refresh Function....with the following id (%s) for network port and following id (%s) for network name and waiting for network to be READY", id, networkname)
return func() (interface{}, string, error) {
network, err := client.GetPort(networkname, id)
if err != nil {
return nil, "", err
}

if *network.Status == "DOWN" {
log.Printf(" The port has been created with the following ip address and attached to an instance ")
return network, "DOWN", nil
}

return network, helpers.PINetworkProvisioning, nil
}
}
func isWaitForIBMPINetworkPortAttachAvailable(ctx context.Context, client *st.IBMPINetworkClient, id, networkname, instanceid string, timeout time.Duration) (interface{}, error) {
log.Printf("Waiting for Power Network (%s) that was created for Network Zone (%s) to be available.", id, networkname)

stateConf := &resource.StateChangeConf{
Pending: []string{"retry", helpers.PINetworkProvisioning},
Target: []string{"ACTIVE"},
Refresh: isIBMPINetworkPortAttachRefreshFunc(client, id, networkname),
Refresh: isIBMPINetworkPortAttachRefreshFunc(client, id, networkname, instanceid),
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 10 * time.Minute,
Expand All @@ -193,7 +250,7 @@ func isWaitForIBMPINetworkPortAttachAvailable(ctx context.Context, client *st.IB
return stateConf.WaitForStateContext(ctx)
}

func isIBMPINetworkPortAttachRefreshFunc(client *st.IBMPINetworkClient, id, networkname string) resource.StateRefreshFunc {
func isIBMPINetworkPortAttachRefreshFunc(client *st.IBMPINetworkClient, id, networkname, instanceid string) resource.StateRefreshFunc {

log.Printf("Calling the IsIBMPINetwork Refresh Function....with the following id (%s) for network port and following id (%s) for network name and waiting for network to be READY", id, networkname)
return func() (interface{}, string, error) {
Expand All @@ -202,8 +259,7 @@ func isIBMPINetworkPortAttachRefreshFunc(client *st.IBMPINetworkClient, id, netw
return nil, "", err
}

if &network.PortID != nil && &network.PvmInstance.PvmInstanceID != nil {
//if network.State == "available" {
if *network.Status == "ACTIVE" && network.PvmInstance.PvmInstanceID == instanceid {
log.Printf(" The port has been created with the following ip address and attached to an instance ")
return network, "ACTIVE", nil
}
Expand Down
52 changes: 42 additions & 10 deletions ibm/service/power/resource_ibm_pi_network_port_attach_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
)

func TestAccIBMPINetworkPortAttachbasic(t *testing.T) {
t.Skip()
name := fmt.Sprintf("tf-pi-network-port-attach-%d", acctest.RandIntRange(10, 100))
resource.Test(t, resource.TestCase{
PreCheck: func() { acc.TestAccPreCheck(t) },
Expand All @@ -34,13 +33,36 @@ func TestAccIBMPINetworkPortAttachbasic(t *testing.T) {
testAccCheckIBMPINetworkPortAttachExists("ibm_pi_network_port_attach.power_network_port_attach"),
resource.TestCheckResourceAttr(
"ibm_pi_network_port_attach.power_network_port_attach", "pi_network_name", name),
resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "id"),
resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "network_port_id"),
resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "public_ip"),
),
},
},
})
}
func testAccCheckIBMPINetworkPortAttachDestroy(s *terraform.State) error {

func TestAccIBMPINetworkPortAttachVlanbasic(t *testing.T) {
name := fmt.Sprintf("tf-pi-network-port-attach-%d", acctest.RandIntRange(10, 100))
resource.Test(t, resource.TestCase{
PreCheck: func() { acc.TestAccPreCheck(t) },
Providers: acc.TestAccProviders,
CheckDestroy: testAccCheckIBMPINetworkPortAttachDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckIBMPINetworkPortAttachVlanConfig(name),
Check: resource.ComposeTestCheckFunc(
testAccCheckIBMPINetworkPortAttachExists("ibm_pi_network_port_attach.power_network_port_attach"),
resource.TestCheckResourceAttr(
"ibm_pi_network_port_attach.power_network_port_attach", "pi_network_name", name),
resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "id"),
resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "network_port_id"),
),
},
},
})
}
func testAccCheckIBMPINetworkPortAttachDestroy(s *terraform.State) error {
sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession()
if err != nil {
return err
Expand All @@ -54,10 +76,10 @@ func testAccCheckIBMPINetworkPortAttachDestroy(s *terraform.State) error {
return err
}
cloudInstanceID := parts[0]
networkID := parts[1]
networkname := parts[1]
portID := parts[2]
networkC := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID)
_, err = networkC.GetPort(networkID, portID)
_, err = networkC.GetPort(networkname, portID)
if err == nil {
return fmt.Errorf("PI Network Port still exists: %s", rs.Primary.ID)
}
Expand Down Expand Up @@ -87,27 +109,37 @@ func testAccCheckIBMPINetworkPortAttachExists(n string) resource.TestCheckFunc {
return err
}
cloudInstanceID := parts[0]
networkID := parts[1]
networkname := parts[1]
portID := parts[2]
client := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID)

network, err := client.GetPort(networkID, portID)
_, err = client.GetPort(networkname, portID)
if err != nil {
return err
}
parts[1] = *network.PortID
return nil

}
}

func testAccCheckIBMPINetworkPortAttachConfig(name string) string {
return testAccCheckIBMPINetworkPortConfig(name) + fmt.Sprintf(`
return testAccCheckIBMPINetworkConfig(name) + fmt.Sprintf(`
resource "ibm_pi_network_port_attach" "power_network_port_attach" {
pi_cloud_instance_id = "%s"
pi_network_name = ibm_pi_network.power_networks.pi_network_name
pi_network_port_description = "IP Reserved for Test UAT"
pi_instance_id = "%s"
}
`, acc.Pi_cloud_instance_id, acc.Pi_instance_name)
}

func testAccCheckIBMPINetworkPortAttachVlanConfig(name string) string {
return testAccCheckIBMPINetworkGatewayConfig(name) + fmt.Sprintf(`
resource "ibm_pi_network_port_attach" "power_network_port_attach" {
pi_cloud_instance_id = "%s"
pi_network_name = ibm_pi_network.power_networks.pi_network_name
pi_network_port_description = "IP Reserved for Test UAT"
port_id=ibm_pi_network_port.power_network_port.id
pi_instance_id = "%s"
}
`, acc.Pi_cloud_instance_id)
`, acc.Pi_cloud_instance_id, acc.Pi_instance_name)
}
Loading