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

Update segment of resource id for network packet capture #8167

Merged
merged 7 commits into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package network

import (
"fmt"
"log"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func ResourceNetworkPacketCaptureMigrateState(v int, is *terraform.InstanceState, _ interface{}) (*terraform.InstanceState, error) {
switch v {
case 0:
log.Println("[INFO] Found AzureRM Network Packet Capture State v0; migrating to v1")
return resourceNetworkPacketCaptureStateV0toV1(is)
default:
return is, fmt.Errorf("Unexpected schema version: %d", v)
}
}

func resourceNetworkPacketCaptureStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
if is.Empty() {
log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
return is, nil
}

log.Printf("[DEBUG] ARM Network Packet Capture before Migration: %#v", is.Attributes)

newID := strings.Replace(is.Attributes["id"], "/NetworkPacketCaptures/", "/packetCaptures/", 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

can you confirm this migration works correctly when provisioning a resource using 2.0.0 -> that then shows no diff using tis branch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tombuildsstuff , yes. I tested the scenario you mentioned and it works fine.
The scenario:

  1. Create Network Packet Captures with 2.0.0 (Also tried 1.27.0)
  2. Run tf plan with this branch
  3. There is no diff.

Copy link
Member

Choose a reason for hiding this comment

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

Hi @neil-yechenwei - Can you post the manual test results / output here? (Ideally with an apply rather than a plan as this will actually update the state and exercise the code.).

Thanks

Copy link
Contributor Author

@neil-yechenwei neil-yechenwei Sep 11, 2020

Choose a reason for hiding this comment

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

@jackofallops , sure.

  1. Run tf apply to create Network Packet Capture with provider.azurerm v2.0.0 (I have to manually update the name segment to "NetworkPacketCaptures" since the name segment in all api versions has been updated to "packetCaptures" such as api version 2018-08-01. So we cannot get old value anymore.)
azurerm_network_packet_capture.test: Creation complete after 16s [id=/subscriptions/xx-xx-xx-xx/resourceGroups/acctestRG-watcher-test01/providers/Microsoft.Network/networkWatchers/acctestnw-test01/NetworkPacketCaptures/acctestpc-test02]

image
2. Switch provider.azurerm from v2.0.0 to this branch
3. Run tf plan

azurerm_network_packet_capture.test: Refreshing state... [id=/subscriptions/xx-xx-xx-xx/resourceGroups/acctestRG-watcher-test01/providers/Microsoft.Network/networkWatchers/acctestnw-test01/packetCaptures/acctestpc-test02]

image
4. Run tf apply

azurerm_network_packet_capture.test: Refreshing state... [id=/subscriptions/xx-x-xx-xx/resourceGroups/acctestRG-watcher-test01/providers/Microsoft.Network/networkWatchers/acctestnw-test01/packetCaptures/acctestpc-test02]

image
5. Update the name of network packet capture in tfconfig. (I cannot test update scenario since this resource doesn't support update operation.)
6. Run tf apply

azurerm_network_packet_capture.test: Creation complete after 5s [id=/subscriptions/xx-xx-xx-xxx/resourceGroups/acctestRG-watcher-test01/providers/Microsoft.Network/networkWatchers/acctestnw-test01/packetCaptures/acctestpc-test03]

image
7. Run tf plan

azurerm_network_packet_capture.test: Refreshing state... [id=/subscriptions/xx-xx-xx-xx/resourceGroups/acctestRG-watcher-test01/providers/Microsoft.Network/networkWatchers/acctestnw-test01/packetCaptures/acctestpc-test03]

image
8. Run tf destroy

azurerm_network_packet_capture.test: Destroying... [id=/subscriptions/xx-x-x-xx/resourceGroups/acctestRG-watcher-test01/providers/Microsoft.Network/networkWatchers/acctestnw-test01/packetCaptures/acctestpc-test03]
azurerm_network_packet_capture.test: Destruction complete after 2s

image

is.Attributes["id"] = newID
is.ID = newID

log.Printf("[DEBUG] ARM Network Packet Capture Attributes after State Migration: %#v", is.Attributes)

return is, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)
Expand All @@ -23,6 +24,9 @@ func resourceArmNetworkPacketCapture() *schema.Resource {
Read: resourceArmNetworkPacketCaptureRead,
Delete: resourceArmNetworkPacketCaptureDelete,

MigrateState: ResourceNetworkPacketCaptureMigrateState,
SchemaVersion: 1,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Expand Down Expand Up @@ -210,29 +214,25 @@ func resourceArmNetworkPacketCaptureRead(d *schema.ResourceData, meta interface{
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := azure.ParseAzureResourceID(d.Id())
id, err := parse.NetworkPacketCaptureID(d.Id())
if err != nil {
return err
}

resourceGroup := id.ResourceGroup
watcherName := id.Path["networkWatchers"]
name := id.Path["NetworkPacketCaptures"]

resp, err := client.Get(ctx, resourceGroup, watcherName, name)
resp, err := client.Get(ctx, id.ResourceGroup, id.WatcherName, id.Name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[WARN] Packet Capture %q (Watcher %q / Resource Group %q) %qw not found - removing from state", name, watcherName, resourceGroup, id)
log.Printf("[WARN] Packet Capture %q (Watcher %q / Resource Group %q) %qw not found - removing from state", id.Name, id.WatcherName, id.ResourceGroup, id)
d.SetId("")
return nil
}

return fmt.Errorf("Error reading Packet Capture %q (Watcher %q / Resource Group %q) %+v", name, watcherName, resourceGroup, err)
return fmt.Errorf("Error reading Packet Capture %q (Watcher %q / Resource Group %q) %+v", id.Name, id.WatcherName, id.ResourceGroup, err)
}

d.Set("name", name)
d.Set("network_watcher_name", watcherName)
d.Set("resource_group_name", resourceGroup)
d.Set("name", id.Name)
d.Set("network_watcher_name", id.WatcherName)
d.Set("resource_group_name", id.ResourceGroup)

if props := resp.PacketCaptureResultProperties; props != nil {
d.Set("target_resource_id", props.Target)
Expand All @@ -259,30 +259,26 @@ func resourceArmNetworkPacketCaptureDelete(d *schema.ResourceData, meta interfac
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := azure.ParseAzureResourceID(d.Id())
id, err := parse.NetworkPacketCaptureID(d.Id())
if err != nil {
return err
}

resourceGroup := id.ResourceGroup
watcherName := id.Path["networkWatchers"]
name := id.Path["NetworkPacketCaptures"]

future, err := client.Delete(ctx, resourceGroup, watcherName, name)
future, err := client.Delete(ctx, id.ResourceGroup, id.WatcherName, id.Name)
if err != nil {
if response.WasNotFound(future.Response()) {
return nil
}

return fmt.Errorf("Error deleting Packet Capture %q (Watcher %q / Resource Group %q): %+v", name, watcherName, resourceGroup, err)
return fmt.Errorf("Error deleting Packet Capture %q (Watcher %q / Resource Group %q): %+v", id.Name, id.WatcherName, id.ResourceGroup, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
if response.WasNotFound(future.Response()) {
return nil
}

return fmt.Errorf("Error waiting for the deletion of Packet Capture %q (Watcher %q / Resource Group %q): %+v", name, watcherName, resourceGroup, err)
return fmt.Errorf("Error waiting for the deletion of Packet Capture %q (Watcher %q / Resource Group %q): %+v", id.Name, id.WatcherName, id.ResourceGroup, err)
}

return nil
Expand Down
34 changes: 34 additions & 0 deletions azurerm/internal/services/network/parse/network_packet_capture.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package parse

import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"

type NetworkPacketCaptureId struct {
ResourceGroup string
WatcherName string
Name string
}

func NetworkPacketCaptureID(input string) (*NetworkPacketCaptureId, error) {
id, err := azure.ParseAzureResourceID(input)
if err != nil {
return nil, err
}

packetCapture := NetworkPacketCaptureId{
ResourceGroup: id.ResourceGroup,
}

if packetCapture.WatcherName, err = id.PopSegment("networkWatchers"); err != nil {
return nil, err
}

if packetCapture.Name, err = id.PopSegment("packetCaptures"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(input); err != nil {
return nil, err
}

return &packetCapture, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package parse

import (
"testing"
)

func TestNetworkPacketCaptureID(t *testing.T) {
testData := []struct {
Name string
Input string
Error bool
Expect *NetworkPacketCaptureId
}{
{
Name: "Empty",
Input: "",
Error: true,
},
{
Name: "No Resource Groups Segment",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000",
Error: true,
},
{
Name: "No Resource Groups Value",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/",
Error: true,
},
{
Name: "Resource Group ID",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/",
Error: true,
},
{
Name: "Missing Network Watcher Key",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/networkWatchers/",
Error: true,
},
{
Name: "Missing Network Watcher Value",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/networkWatchers/watcher1",
Error: true,
},
{
Name: "Missing Network Packet Capture Key",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/networkWatchers/watcher1/packetCaptures",
Error: true,
},
{
Name: "Namespace Network Packet Capture Value",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/networkWatchers/watcher1/packetCaptures/packetCapture1",
Error: false,
Expect: &NetworkPacketCaptureId{
ResourceGroup: "group1",
WatcherName: "watcher1",
Name: "packetCapture1",
},
},
{
Name: "Wrong Segment",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/networkWatchers/watcher1/NetworkPacketCaptures/packetCapture1",
Error: true,
},
}

for _, v := range testData {
t.Logf("[DEBUG] Testing %q", v.Name)

actual, err := NetworkPacketCaptureID(v.Input)
if err != nil {
if v.Error {
continue
}

t.Fatalf("Expected a value but got an error: %s", err)
}

if actual.Name != v.Expect.Name {
t.Fatalf("Expected %q but got %q for Name", v.Expect.Name, actual.Name)
}

if actual.WatcherName != v.Expect.WatcherName {
t.Fatalf("Expected %q but got %q for Name", v.Expect.WatcherName, actual.WatcherName)
}

if actual.ResourceGroup != v.Expect.ResourceGroup {
t.Fatalf("Expected %q but got %q for Resource Group", v.Expect.ResourceGroup, actual.ResourceGroup)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ resource "azurerm_virtual_machine" "test" {

resource "azurerm_virtual_machine_extension" "test" {
name = "network-watcher"
virtual_machine_id = azurerm_virtual_machine.src.id
virtual_machine_id = azurerm_virtual_machine.test.id
publisher = "Microsoft.Azure.NetworkWatcher"
type = "NetworkWatcherAgentLinux"
type_handler_version = "1.4"
Expand Down