From a7844bde3598d43c50ba836b6480978cc9cdb9bc Mon Sep 17 00:00:00 2001 From: jcanizalez Date: Tue, 9 Mar 2021 18:53:17 -0600 Subject: [PATCH 1/7] Include Live Outputs resource definition --- .../internal/services/media/client/client.go | 5 + .../media/media_live_output_resource.go | 243 ++++++++++++++++++ .../services/media/parse/live_output.go | 81 ++++++ .../services/media/parse/live_output_test.go | 144 +++++++++++ .../internal/services/media/registration.go | 1 + .../internal/services/media/resourceids.go | 1 + .../services/media/validate/live_output_id.go | 23 ++ .../media/validate/live_output_id_test.go | 100 +++++++ azurerm/internal/services/media/validation.go | 26 ++ 9 files changed, 624 insertions(+) create mode 100644 azurerm/internal/services/media/media_live_output_resource.go create mode 100644 azurerm/internal/services/media/parse/live_output.go create mode 100644 azurerm/internal/services/media/parse/live_output_test.go create mode 100644 azurerm/internal/services/media/validate/live_output_id.go create mode 100644 azurerm/internal/services/media/validate/live_output_id_test.go diff --git a/azurerm/internal/services/media/client/client.go b/azurerm/internal/services/media/client/client.go index 85bbd0549852..37690e8e7afc 100644 --- a/azurerm/internal/services/media/client/client.go +++ b/azurerm/internal/services/media/client/client.go @@ -14,6 +14,7 @@ type Client struct { StreamingLocatorsClient *media.StreamingLocatorsClient ContentKeyPoliciesClient *media.ContentKeyPoliciesClient StreamingPoliciesClient *media.StreamingPoliciesClient + LiveOutputsClient *media.LiveOutputsClient } func NewClient(o *common.ClientOptions) *Client { @@ -41,6 +42,9 @@ func NewClient(o *common.ClientOptions) *Client { StreamingPoliciesClient := media.NewStreamingPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&StreamingPoliciesClient.Client, o.ResourceManagerAuthorizer) + LiveOutputsClient := media.NewLiveOutputsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&LiveOutputsClient.Client, o.ResourceManagerAuthorizer) + return &Client{ ServicesClient: &ServicesClient, AssetsClient: &AssetsClient, @@ -50,5 +54,6 @@ func NewClient(o *common.ClientOptions) *Client { StreamingLocatorsClient: &StreamingLocatorsClient, ContentKeyPoliciesClient: &ContentKeyPoliciesClient, StreamingPoliciesClient: &StreamingPoliciesClient, + LiveOutputsClient: &LiveOutputsClient, } } diff --git a/azurerm/internal/services/media/media_live_output_resource.go b/azurerm/internal/services/media/media_live_output_resource.go new file mode 100644 index 000000000000..a7944143c169 --- /dev/null +++ b/azurerm/internal/services/media/media_live_output_resource.go @@ -0,0 +1,243 @@ +package media + +import ( + "fmt" + "log" + "regexp" + "time" + + "github.com/Azure/azure-sdk-for-go/services/mediaservices/mgmt/2020-05-01/media" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "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/services/media/parse" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceMediaLiveOutput() *schema.Resource { + return &schema.Resource{ + Create: resourceMediaLiveOutputCreate, + Read: resourceMediaLiveOutputRead, + Delete: resourceMediaLiveOutputDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.LiveOutputID(id) + return err + }), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "media_services_account_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: ValidateMediaServicesAccountName, + }, + + "live_event_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: ValidateLiveEventName, + }, + + "archive_window_length": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "asset_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^[-a-zA-Z0-9]{1,128}$"), + "Asset name must be 1 - 128 characters long, contain only letters, hyphen and numbers.", + ), + }, + + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "hls_fragments_per_ts_segment": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IntAtLeast(0), + }, + + "manifest_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "output_snap_time": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IntAtLeast(0), + }, + }, + } +} + +func resourceMediaLiveOutputCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Media.LiveOutputsClient + subscriptionID := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + resourceID := parse.NewLiveOutputID(subscriptionID, d.Get("resource_group_name").(string), d.Get("media_services_account_name").(string), d.Get("live_event_name").(string), d.Get("name").(string)) + if d.IsNewResource() { + existing, err := client.Get(ctx, resourceID.ResourceGroup, resourceID.MediaserviceName, resourceID.LiveeventName, resourceID.Name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing %s: %+v", resourceID, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_media_live_output", resourceID.ID()) + } + } + + parameters := media.LiveOutput{ + LiveOutputProperties: &media.LiveOutputProperties{}, + } + + if archiveWindowLength, ok := d.GetOk("archive_window_length"); ok { + parameters.LiveOutputProperties.ArchiveWindowLength = utils.String(archiveWindowLength.(string)) + } + + if assetName, ok := d.GetOk("asset_name"); ok { + parameters.LiveOutputProperties.AssetName = utils.String(assetName.(string)) + } + + if description, ok := d.GetOk("description"); ok { + parameters.LiveOutputProperties.Description = utils.String(description.(string)) + } + + if hlsFragmentsPerTsSegment, ok := d.GetOk("hls_fragments_per_ts_segment"); ok { + parameters.LiveOutputProperties.Hls = &media.Hls{ + FragmentsPerTsSegment: utils.Int32(int32(hlsFragmentsPerTsSegment.(int))), + } + } + + if manifestName, ok := d.GetOk("manifest_name"); ok { + parameters.LiveOutputProperties.ManifestName = utils.String(manifestName.(string)) + } + + if outputSnapTime, ok := d.GetOk("output_snap_time"); ok { + parameters.LiveOutputProperties.OutputSnapTime = utils.Int64(int64(outputSnapTime.(int))) + } + + future, err := client.Create(ctx, resourceID.ResourceGroup, resourceID.MediaserviceName, resourceID.LiveeventName, resourceID.Name, parameters) + if err != nil { + return fmt.Errorf("creating %s: %+v", resourceID, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation %s: %+v", resourceID, err) + } + + d.SetId(resourceID.ID()) + + return resourceMediaLiveOutputRead(d, meta) +} + +func resourceMediaLiveOutputRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Media.LiveOutputsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.LiveOutputID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.MediaserviceName, id.LiveeventName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] %s was not found - removing from state", id) + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + d.Set("name", id.Name) + d.Set("resource_group_name", id.ResourceGroup) + d.Set("media_services_account_name", id.MediaserviceName) + d.Set("live_event_name", id.LiveeventName) + + if props := resp.LiveOutputProperties; props != nil { + d.Set("archive_window_length", props.ArchiveWindowLength) + d.Set("asset_name", props.AssetName) + d.Set("description", props.Description) + + var hlsFragmentsPerTsSegment int32 + if props.Hls != nil && props.Hls.FragmentsPerTsSegment != nil { + hlsFragmentsPerTsSegment = *props.Hls.FragmentsPerTsSegment + } + d.Set("hls_fragments_per_ts_segment", hlsFragmentsPerTsSegment) + d.Set("manifest_name", props.ManifestName) + + var outputSnapTime int64 + if props.OutputSnapTime != nil { + outputSnapTime = *props.OutputSnapTime + } + d.Set("output_snap_time", outputSnapTime) + } + + return nil +} + +func resourceMediaLiveOutputDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Media.LiveOutputsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.LiveOutputID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.MediaserviceName, id.LiveeventName, id.Name) + if err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for %s to delete: %+v", id, err) + } + + return nil +} diff --git a/azurerm/internal/services/media/parse/live_output.go b/azurerm/internal/services/media/parse/live_output.go new file mode 100644 index 000000000000..bf105a2f4fd3 --- /dev/null +++ b/azurerm/internal/services/media/parse/live_output.go @@ -0,0 +1,81 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type LiveOutputId struct { + SubscriptionId string + ResourceGroup string + MediaserviceName string + LiveeventName string + Name string +} + +func NewLiveOutputID(subscriptionId, resourceGroup, mediaserviceName, liveeventName, name string) LiveOutputId { + return LiveOutputId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + MediaserviceName: mediaserviceName, + LiveeventName: liveeventName, + Name: name, + } +} + +func (id LiveOutputId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Liveevent Name %q", id.LiveeventName), + fmt.Sprintf("Mediaservice Name %q", id.MediaserviceName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Live Output", segmentsStr) +} + +func (id LiveOutputId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Media/mediaservices/%s/liveevents/%s/liveoutputs/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.MediaserviceName, id.LiveeventName, id.Name) +} + +// LiveOutputID parses a LiveOutput ID into an LiveOutputId struct +func LiveOutputID(input string) (*LiveOutputId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := LiveOutputId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.MediaserviceName, err = id.PopSegment("mediaservices"); err != nil { + return nil, err + } + if resourceId.LiveeventName, err = id.PopSegment("liveevents"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("liveoutputs"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/media/parse/live_output_test.go b/azurerm/internal/services/media/parse/live_output_test.go new file mode 100644 index 000000000000..a65f9b05857c --- /dev/null +++ b/azurerm/internal/services/media/parse/live_output_test.go @@ -0,0 +1,144 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = LiveOutputId{} + +func TestLiveOutputIDFormatter(t *testing.T) { + actual := NewLiveOutputID("12345678-1234-9876-4563-123456789012", "resGroup1", "account1", "event1", "output1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/liveoutputs/output1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestLiveOutputID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *LiveOutputId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing MediaserviceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/", + Error: true, + }, + + { + // missing value for MediaserviceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/", + Error: true, + }, + + { + // missing LiveeventName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/", + Error: true, + }, + + { + // missing value for LiveeventName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/liveoutputs/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/liveoutputs/output1", + Expected: &LiveOutputId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + MediaserviceName: "account1", + LiveeventName: "event1", + Name: "output1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.MEDIA/MEDIASERVICES/ACCOUNT1/LIVEEVENTS/EVENT1/LIVEOUTPUTS/OUTPUT1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := LiveOutputID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.MediaserviceName != v.Expected.MediaserviceName { + t.Fatalf("Expected %q but got %q for MediaserviceName", v.Expected.MediaserviceName, actual.MediaserviceName) + } + if actual.LiveeventName != v.Expected.LiveeventName { + t.Fatalf("Expected %q but got %q for LiveeventName", v.Expected.LiveeventName, actual.LiveeventName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/media/registration.go b/azurerm/internal/services/media/registration.go index b2686a601d76..713cf76d7980 100644 --- a/azurerm/internal/services/media/registration.go +++ b/azurerm/internal/services/media/registration.go @@ -34,5 +34,6 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_media_streaming_locator": resourceMediaStreamingLocator(), "azurerm_media_content_key_policy": resourceMediaContentKeyPolicy(), "azurerm_media_streaming_policy": resourceMediaStreamingPolicy(), + "azurerm_media_live_output": resourceMediaLiveOutput(), } } diff --git a/azurerm/internal/services/media/resourceids.go b/azurerm/internal/services/media/resourceids.go index d0369dd61d62..107512976ea2 100644 --- a/azurerm/internal/services/media/resourceids.go +++ b/azurerm/internal/services/media/resourceids.go @@ -8,3 +8,4 @@ package media //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=StreamingLocator -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/streaminglocators/locator1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ContentKeyPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/contentkeypolicies/policy1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=StreamingPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/streamingpolicies/policy1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=LiveOutput -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/liveoutputs/output1 diff --git a/azurerm/internal/services/media/validate/live_output_id.go b/azurerm/internal/services/media/validate/live_output_id.go new file mode 100644 index 000000000000..4ccea1c48845 --- /dev/null +++ b/azurerm/internal/services/media/validate/live_output_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/media/parse" +) + +func LiveOutputID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.LiveOutputID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/media/validate/live_output_id_test.go b/azurerm/internal/services/media/validate/live_output_id_test.go new file mode 100644 index 000000000000..2b1c1ad0e155 --- /dev/null +++ b/azurerm/internal/services/media/validate/live_output_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestLiveOutputID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing MediaserviceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/", + Valid: false, + }, + + { + // missing value for MediaserviceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/", + Valid: false, + }, + + { + // missing LiveeventName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/", + Valid: false, + }, + + { + // missing value for LiveeventName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/liveoutputs/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/liveoutputs/output1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.MEDIA/MEDIASERVICES/ACCOUNT1/LIVEEVENTS/EVENT1/LIVEOUTPUTS/OUTPUT1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := LiveOutputID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/azurerm/internal/services/media/validation.go b/azurerm/internal/services/media/validation.go index 2b2ef2379e71..11d9fc2b2ebe 100644 --- a/azurerm/internal/services/media/validation.go +++ b/azurerm/internal/services/media/validation.go @@ -51,3 +51,29 @@ func ValidateStreamingEnpointName(i interface{}, k string) (warnings []string, e return warnings, errors } + +func ValidateLiveEventName(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("Expected %q to be a string but it wasn't!", k)) + return + } + + // The value must not be empty. + if strings.TrimSpace(v) == "" { + errors = append(errors, fmt.Errorf("%q must not be empty", k)) + return + } + + // Live Event name can be 1-32 characters in length + const maxLength = 32 + if len(v) > maxLength { + errors = append(errors, fmt.Errorf("%q cannot exceed 32 characters.", k)) + } + + if matched := regexp.MustCompile(`^[a-zA-Z0-9]+(-*[a-zA-Z0-9])*$`).Match([]byte(v)); !matched { + errors = append(errors, fmt.Errorf("%q can contain letters, numbers, and hyphens (but the first and last character must be a letter or number).", k)) + } + + return warnings, errors +} From e1714d742e9c9afd8626c1f31f3595ca5db14fae Mon Sep 17 00:00:00 2001 From: jcanizalez Date: Tue, 9 Mar 2021 18:53:35 -0600 Subject: [PATCH 2/7] Add acceptance tests for Live Outputs --- .../media/media_live_output_resource_test.go | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 azurerm/internal/services/media/media_live_output_resource_test.go diff --git a/azurerm/internal/services/media/media_live_output_resource_test.go b/azurerm/internal/services/media/media_live_output_resource_test.go new file mode 100644 index 000000000000..0a05d17e9fee --- /dev/null +++ b/azurerm/internal/services/media/media_live_output_resource_test.go @@ -0,0 +1,185 @@ +package media_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/media/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type LiveOutputResource struct{} + +func TestAccLiveOutput_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_media_live_output", "test") + r := LiveOutputResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("name").HasValue("Output-1"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccLiveOutput_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_media_live_output", "test") + r := LiveOutputResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("name").HasValue("Output-1"), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccLiveOutput_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_media_live_output", "test") + r := LiveOutputResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("manifest_name").HasValue("testmanifest"), + check.That(data.ResourceName).Key("hls_fragments_per_ts_segment").HasValue("5"), + ), + }, + data.ImportStep(), + }) +} + +func (LiveOutputResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.LiveOutputID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Media.LiveOutputsClient.Get(ctx, id.ResourceGroup, id.MediaserviceName, id.LiveeventName, id.Name) + if err != nil { + return nil, fmt.Errorf("retrieving Live Event %s (Media Services Account %s) (resource group: %s): %v", id.Name, id.MediaserviceName, id.ResourceGroup, err) + } + + return utils.Bool(resp.LiveOutputProperties != nil), nil +} + +func (r LiveOutputResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_media_live_output" "test" { + name = "Output-1" + resource_group_name = azurerm_resource_group.test.name + media_services_account_name = azurerm_media_services_account.test.name + live_event_name = azurerm_media_live_event.test.name + archive_window_length = "PT5M" + asset_name = azurerm_media_asset.test.name +} + +`, r.template(data)) +} + +func (r LiveOutputResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_media_live_output" "import" { + name = azurerm_media_live_output.test.name + resource_group_name = azurerm_media_live_output.test.resource_group_name + media_services_account_name = azurerm_media_live_output.test.media_services_account_name + live_event_name = azurerm_media_live_event.test.name + archive_window_length = "PT5M" + asset_name = azurerm_media_asset.test.name +} + +`, r.basic(data)) +} + +func (r LiveOutputResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_media_live_output" "test" { + name = "Output-2" + resource_group_name = azurerm_resource_group.test.name + media_services_account_name = azurerm_media_services_account.test.name + live_event_name = azurerm_media_live_event.test.name + archive_window_length = "PT5M" + asset_name = azurerm_media_asset.test.name + description = "Test live output 1" + manifest_name = "testmanifest" + output_snap_time = 0 + hls_fragments_per_ts_segment = 5 +} + +`, r.template(data)) +} + +func (LiveOutputResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-media-%d" + location = "%s" +} + +resource "azurerm_storage_account" "test" { + name = "acctestsa1%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "GRS" +} + +resource "azurerm_media_services_account" "test" { + name = "acctestmsa%s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + storage_account { + id = azurerm_storage_account.test.id + is_primary = true + } +} + +resource "azurerm_media_asset" "test" { + name = "inputAsset" + resource_group_name = azurerm_resource_group.test.name + media_services_account_name = azurerm_media_services_account.test.name +} + +resource "azurerm_media_live_event" "test" { + name = "event" + resource_group_name = azurerm_resource_group.test.name + media_services_account_name = azurerm_media_services_account.test.name + location = azurerm_resource_group.test.location + + input { + streaming_protocol = "RTMP" + key_frame_interval_duration = "PT6S" + ip_access_control_allow { + name = "AllowAll" + address = "0.0.0.0" + subnet_prefix_length = 0 + } + } +} + +`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) +} From 3568ac07c24f72d85e8e7d5bce6812b7e3264e85 Mon Sep 17 00:00:00 2001 From: jcanizalez Date: Tue, 9 Mar 2021 18:53:47 -0600 Subject: [PATCH 3/7] Include documentation for Live Outputs --- .../docs/r/media_live_output.html.markdown | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 website/docs/r/media_live_output.html.markdown diff --git a/website/docs/r/media_live_output.html.markdown b/website/docs/r/media_live_output.html.markdown new file mode 100644 index 000000000000..f0cac25685a7 --- /dev/null +++ b/website/docs/r/media_live_output.html.markdown @@ -0,0 +1,125 @@ +--- +subcategory: "Media" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_media_live_output" +description: |- + Manages a Live Output. +--- + +# azurerm_media_live_output + +Manages a Live Output. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "media-resources" + location = "West Europe" +} + +resource "azurerm_storage_account" "example" { + name = "examplestoracc" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + account_tier = "Standard" + account_replication_type = "GRS" +} + +resource "azurerm_media_services_account" "example" { + name = "examplemediaacc" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + + storage_account { + id = azurerm_storage_account.example.id + is_primary = true + } +} + +resource "azurerm_media_asset" "example" { + name = "inputAsset" + resource_group_name = azurerm_resource_group.example.name + media_services_account_name = azurerm_media_services_account.example.name +} + +resource "azurerm_media_live_event" "example" { + name = "exampleevent" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + media_services_account_name = azurerm_media_services_account.example.name + description = "My Event Description" + + input { + streaming_protocol = "RTMP" + key_frame_interval_duration = "PT6S" + ip_access_control_allow { + name = "AllowAll" + address = "0.0.0.0" + subnet_prefix_length = 0 + } + } +} + +resource "azurerm_media_live_output" "example" { + name = "exampleoutput" + resource_group_name = azurerm_resource_group.example.name + media_services_account_name = azurerm_media_services_account.example.name + live_event_name = azurerm_media_live_event.example.name + archive_window_length = "PT5M" + asset_name = azurerm_media_asset.example.name + description = "Test live output 1" + manifest_name = "testmanifest" + output_snap_time = 0 + hls_fragments_per_ts_segment = 5 +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `archive_window_length` - (Required) `ISO 8601` time between 1 minute to 25 hours to indicate the maximum content length that can be archived in the asset for this live output. This also sets the maximum content length for the rewind window. For example, use `PT1H30M` to indicate 1 hour and 30 minutes of archive window. Changing this forces a new Live Output to be created. + +* `asset_name` - (Required) The asset that the live output will write to. Changing this forces a new Live Output to be created. + +* `live_event_name` - (Required) The name of the live event, maximum length is 32. Changing this forces a new Live Output to be created. + +* `media_services_account_name` - (Required) The Media Services account name. Changing this forces a new Live Output to be created. + +* `name` - (Required) The name which should be used for this Live Output. Changing this forces a new Live Output to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the Live Output should exist. Changing this forces a new Live Output to be created. + +--- + +* `description` - (Optional) The description of the live output. Changing this forces a new Live Output to be created. + +* `hls_fragments_per_ts_segment` - (Optional) The number of fragments in an HTTP Live Streaming (HLS) TS segment in the output of the live event. This value does not affect the packing ratio for HLS CMAF output. Changing this forces a new Live Output to be created. + +* `manifest_name` - (Optional) The manifest file name. If not provided, the service will generate one automatically. Changing this forces a new Live Output to be created. + +* `output_snap_time` - (Optional) The initial timestamp that the live output will start at, any content before this value will not be archived. Changing this forces a new Live Output to be created. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Live Output. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Live Output. +* `read` - (Defaults to 5 minutes) Used when retrieving the Live Output. +* `update` - (Defaults to 30 minutes) Used when updating the Live Output. +* `delete` - (Defaults to 30 minutes) Used when deleting the Live Output. + +## Import + +Live Outputs can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_media_live_output.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Media/mediaservices/account1/liveevents/event1/liveoutputs/output1 +``` From 45f353c4dcc1f470097dcfa880f94e2f4c53dca3 Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Wed, 7 Apr 2021 17:41:20 -0600 Subject: [PATCH 4/7] Apply code review suggestions --- .../media/media_live_output_resource.go | 50 +++++++------- .../media/media_live_output_resource_test.go | 66 +++++++++++++------ .../internal/services/media/registration.go | 2 +- .../docs/r/media_live_output.html.markdown | 24 +++---- 4 files changed, 78 insertions(+), 64 deletions(-) diff --git a/azurerm/internal/services/media/media_live_output_resource.go b/azurerm/internal/services/media/media_live_output_resource.go index a7944143c169..e2883abcf1ea 100644 --- a/azurerm/internal/services/media/media_live_output_resource.go +++ b/azurerm/internal/services/media/media_live_output_resource.go @@ -43,23 +43,14 @@ func resourceMediaLiveOutput() *schema.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), - - "media_services_account_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: ValidateMediaServicesAccountName, - }, - - "live_event_name": { + "live_event_id": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: ValidateLiveEventName, + ValidateFunc: azure.ValidateResourceID, }, - "archive_window_length": { + "archive_window_duration": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -98,7 +89,7 @@ func resourceMediaLiveOutput() *schema.Resource { ValidateFunc: validation.StringIsNotEmpty, }, - "output_snap_time": { + "output_snap_timestamp": { Type: schema.TypeInt, Optional: true, ForceNew: true, @@ -114,17 +105,21 @@ func resourceMediaLiveOutputCreate(d *schema.ResourceData, meta interface{}) err ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - resourceID := parse.NewLiveOutputID(subscriptionID, d.Get("resource_group_name").(string), d.Get("media_services_account_name").(string), d.Get("live_event_name").(string), d.Get("name").(string)) + eventID, err := parse.LiveEventID(d.Get("live_event_id").(string)) + if err != nil { + return err + } + id := parse.NewLiveOutputID(subscriptionID, eventID.ResourceGroup, eventID.MediaserviceName, eventID.Name, d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, resourceID.ResourceGroup, resourceID.MediaserviceName, resourceID.LiveeventName, resourceID.Name) + existing, err := client.Get(ctx, id.ResourceGroup, id.MediaserviceName, id.LiveeventName, id.Name) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing %s: %+v", resourceID, err) + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_media_live_output", resourceID.ID()) + return tf.ImportAsExistsError("azurerm_media_live_event_output", id.ID()) } } @@ -132,7 +127,7 @@ func resourceMediaLiveOutputCreate(d *schema.ResourceData, meta interface{}) err LiveOutputProperties: &media.LiveOutputProperties{}, } - if archiveWindowLength, ok := d.GetOk("archive_window_length"); ok { + if archiveWindowLength, ok := d.GetOk("archive_window_duration"); ok { parameters.LiveOutputProperties.ArchiveWindowLength = utils.String(archiveWindowLength.(string)) } @@ -158,22 +153,23 @@ func resourceMediaLiveOutputCreate(d *schema.ResourceData, meta interface{}) err parameters.LiveOutputProperties.OutputSnapTime = utils.Int64(int64(outputSnapTime.(int))) } - future, err := client.Create(ctx, resourceID.ResourceGroup, resourceID.MediaserviceName, resourceID.LiveeventName, resourceID.Name, parameters) + future, err := client.Create(ctx, id.ResourceGroup, id.MediaserviceName, id.LiveeventName, id.Name, parameters) if err != nil { - return fmt.Errorf("creating %s: %+v", resourceID, err) + return fmt.Errorf("creating %s: %+v", id, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation %s: %+v", resourceID, err) + return fmt.Errorf("waiting for creation %s: %+v", id, err) } - d.SetId(resourceID.ID()) + d.SetId(id.ID()) return resourceMediaLiveOutputRead(d, meta) } func resourceMediaLiveOutputRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Media.LiveOutputsClient + subscriptionID := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -194,12 +190,12 @@ func resourceMediaLiveOutputRead(d *schema.ResourceData, meta interface{}) error } d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("media_services_account_name", id.MediaserviceName) - d.Set("live_event_name", id.LiveeventName) + + eventID := parse.NewLiveEventID(subscriptionID, id.ResourceGroup, id.MediaserviceName, id.LiveeventName) + d.Set("live_event_id", eventID.ID()) if props := resp.LiveOutputProperties; props != nil { - d.Set("archive_window_length", props.ArchiveWindowLength) + d.Set("archive_window_duration", props.ArchiveWindowLength) d.Set("asset_name", props.AssetName) d.Set("description", props.Description) @@ -214,7 +210,7 @@ func resourceMediaLiveOutputRead(d *schema.ResourceData, meta interface{}) error if props.OutputSnapTime != nil { outputSnapTime = *props.OutputSnapTime } - d.Set("output_snap_time", outputSnapTime) + d.Set("output_snap_timestamp", outputSnapTime) } return nil diff --git a/azurerm/internal/services/media/media_live_output_resource_test.go b/azurerm/internal/services/media/media_live_output_resource_test.go index 0a05d17e9fee..0643997d2113 100644 --- a/azurerm/internal/services/media/media_live_output_resource_test.go +++ b/azurerm/internal/services/media/media_live_output_resource_test.go @@ -17,7 +17,7 @@ import ( type LiveOutputResource struct{} func TestAccLiveOutput_basic(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_media_live_output", "test") + data := acceptance.BuildTestData(t, "azurerm_media_live_event_output", "test") r := LiveOutputResource{} data.ResourceTest(t, r, []resource.TestStep{ @@ -32,7 +32,7 @@ func TestAccLiveOutput_basic(t *testing.T) { } func TestAccLiveOutput_requiresImport(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_media_live_output", "test") + data := acceptance.BuildTestData(t, "azurerm_media_live_event_output", "test") r := LiveOutputResource{} data.ResourceTest(t, r, []resource.TestStep{ @@ -47,7 +47,7 @@ func TestAccLiveOutput_requiresImport(t *testing.T) { } func TestAccLiveOutput_complete(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_media_live_output", "test") + data := acceptance.BuildTestData(t, "azurerm_media_live_event_output", "test") r := LiveOutputResource{} data.ResourceTest(t, r, []resource.TestStep{ @@ -62,6 +62,36 @@ func TestAccLiveOutput_complete(t *testing.T) { }) } +func TestAccLiveOutput_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_media_live_event_output", "test") + r := LiveOutputResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("name").HasValue("Output-1"), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("manifest_name").HasValue("testmanifest"), + check.That(data.ResourceName).Key("hls_fragments_per_ts_segment").HasValue("5"), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("name").HasValue("Output-1"), + ), + }, + data.ImportStep(), + }) +} + func (LiveOutputResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { id, err := parse.LiveOutputID(state.ID) if err != nil { @@ -70,7 +100,7 @@ func (LiveOutputResource) Exists(ctx context.Context, clients *clients.Client, s resp, err := clients.Media.LiveOutputsClient.Get(ctx, id.ResourceGroup, id.MediaserviceName, id.LiveeventName, id.Name) if err != nil { - return nil, fmt.Errorf("retrieving Live Event %s (Media Services Account %s) (resource group: %s): %v", id.Name, id.MediaserviceName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving Live Event Output %s (Media Services Account %s) (resource group: %s): %v", id.Name, id.MediaserviceName, id.ResourceGroup, err) } return utils.Bool(resp.LiveOutputProperties != nil), nil @@ -80,12 +110,10 @@ func (r LiveOutputResource) basic(data acceptance.TestData) string { return fmt.Sprintf(` %s -resource "azurerm_media_live_output" "test" { +resource "azurerm_media_live_event_output" "test" { name = "Output-1" - resource_group_name = azurerm_resource_group.test.name - media_services_account_name = azurerm_media_services_account.test.name - live_event_name = azurerm_media_live_event.test.name - archive_window_length = "PT5M" + live_event_id = azurerm_media_live_event.test.id + archive_window_duration = "PT5M" asset_name = azurerm_media_asset.test.name } @@ -96,12 +124,10 @@ func (r LiveOutputResource) requiresImport(data acceptance.TestData) string { return fmt.Sprintf(` %s -resource "azurerm_media_live_output" "import" { - name = azurerm_media_live_output.test.name - resource_group_name = azurerm_media_live_output.test.resource_group_name - media_services_account_name = azurerm_media_live_output.test.media_services_account_name - live_event_name = azurerm_media_live_event.test.name - archive_window_length = "PT5M" +resource "azurerm_media_live_event_output" "import" { + name = azurerm_media_live_event_output.test.name + live_event_id = azurerm_media_live_event.test.id + archive_window_duration = "PT5M" asset_name = azurerm_media_asset.test.name } @@ -112,16 +138,14 @@ func (r LiveOutputResource) complete(data acceptance.TestData) string { return fmt.Sprintf(` %s -resource "azurerm_media_live_output" "test" { +resource "azurerm_media_live_event_output" "test" { name = "Output-2" - resource_group_name = azurerm_resource_group.test.name - media_services_account_name = azurerm_media_services_account.test.name - live_event_name = azurerm_media_live_event.test.name - archive_window_length = "PT5M" + live_event_id = azurerm_media_live_event.test.id + archive_window_duration = "PT5M" asset_name = azurerm_media_asset.test.name description = "Test live output 1" manifest_name = "testmanifest" - output_snap_time = 0 + output_snap_timestamp = 0 hls_fragments_per_ts_segment = 5 } diff --git a/azurerm/internal/services/media/registration.go b/azurerm/internal/services/media/registration.go index 657735b73d53..f70757f7426d 100644 --- a/azurerm/internal/services/media/registration.go +++ b/azurerm/internal/services/media/registration.go @@ -35,6 +35,6 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_media_content_key_policy": resourceMediaContentKeyPolicy(), "azurerm_media_streaming_policy": resourceMediaStreamingPolicy(), "azurerm_media_live_event": resourceMediaLiveEvent(), - "azurerm_media_live_output": resourceMediaLiveOutput(), + "azurerm_media_live_event_output": resourceMediaLiveOutput(), } } diff --git a/website/docs/r/media_live_output.html.markdown b/website/docs/r/media_live_output.html.markdown index f0cac25685a7..a1314fc180fe 100644 --- a/website/docs/r/media_live_output.html.markdown +++ b/website/docs/r/media_live_output.html.markdown @@ -1,14 +1,14 @@ --- subcategory: "Media" layout: "azurerm" -page_title: "Azure Resource Manager: azurerm_media_live_output" +page_title: "Azure Resource Manager: azurerm_media_live_event_output" description: |- - Manages a Live Output. + Manages an Azure Media Live Event Output. --- # azurerm_media_live_output -Manages a Live Output. +Manages a Azure Media Live Event Output. ## Example Usage @@ -61,16 +61,14 @@ resource "azurerm_media_live_event" "example" { } } -resource "azurerm_media_live_output" "example" { +resource "azurerm_media_live_event_output" "example" { name = "exampleoutput" - resource_group_name = azurerm_resource_group.example.name - media_services_account_name = azurerm_media_services_account.example.name - live_event_name = azurerm_media_live_event.example.name + live_event_id = azurerm_media_live_event.example.id archive_window_length = "PT5M" asset_name = azurerm_media_asset.example.name description = "Test live output 1" manifest_name = "testmanifest" - output_snap_time = 0 + output_snap_timestamp = 0 hls_fragments_per_ts_segment = 5 } ``` @@ -79,18 +77,14 @@ resource "azurerm_media_live_output" "example" { The following arguments are supported: -* `archive_window_length` - (Required) `ISO 8601` time between 1 minute to 25 hours to indicate the maximum content length that can be archived in the asset for this live output. This also sets the maximum content length for the rewind window. For example, use `PT1H30M` to indicate 1 hour and 30 minutes of archive window. Changing this forces a new Live Output to be created. +* `archive_window_duration` - (Required) `ISO 8601` time between 1 minute to 25 hours to indicate the maximum content length that can be archived in the asset for this live output. This also sets the maximum content length for the rewind window. For example, use `PT1H30M` to indicate 1 hour and 30 minutes of archive window. Changing this forces a new Live Output to be created. * `asset_name` - (Required) The asset that the live output will write to. Changing this forces a new Live Output to be created. -* `live_event_name` - (Required) The name of the live event, maximum length is 32. Changing this forces a new Live Output to be created. - -* `media_services_account_name` - (Required) The Media Services account name. Changing this forces a new Live Output to be created. +* `live_event_id` - (Required) The id of the live event. Changing this forces a new Live Output to be created. * `name` - (Required) The name which should be used for this Live Output. Changing this forces a new Live Output to be created. -* `resource_group_name` - (Required) The name of the Resource Group where the Live Output should exist. Changing this forces a new Live Output to be created. - --- * `description` - (Optional) The description of the live output. Changing this forces a new Live Output to be created. @@ -99,7 +93,7 @@ The following arguments are supported: * `manifest_name` - (Optional) The manifest file name. If not provided, the service will generate one automatically. Changing this forces a new Live Output to be created. -* `output_snap_time` - (Optional) The initial timestamp that the live output will start at, any content before this value will not be archived. Changing this forces a new Live Output to be created. +* `output_snap_timestamp` - (Optional) The initial timestamp that the live output will start at, any content before this value will not be archived. Changing this forces a new Live Output to be created. ## Attributes Reference From 3c407e6a3d9d6a7b6f637cfbdab5cfb4a3108c6d Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Wed, 7 Apr 2021 17:53:14 -0600 Subject: [PATCH 5/7] Fix lint --- .../media/media_live_output_resource_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/azurerm/internal/services/media/media_live_output_resource_test.go b/azurerm/internal/services/media/media_live_output_resource_test.go index 0643997d2113..9311ffa2d0d7 100644 --- a/azurerm/internal/services/media/media_live_output_resource_test.go +++ b/azurerm/internal/services/media/media_live_output_resource_test.go @@ -111,10 +111,10 @@ func (r LiveOutputResource) basic(data acceptance.TestData) string { %s resource "azurerm_media_live_event_output" "test" { - name = "Output-1" - live_event_id = azurerm_media_live_event.test.id - archive_window_duration = "PT5M" - asset_name = azurerm_media_asset.test.name + name = "Output-1" + live_event_id = azurerm_media_live_event.test.id + archive_window_duration = "PT5M" + asset_name = azurerm_media_asset.test.name } `, r.template(data)) @@ -125,10 +125,10 @@ func (r LiveOutputResource) requiresImport(data acceptance.TestData) string { %s resource "azurerm_media_live_event_output" "import" { - name = azurerm_media_live_event_output.test.name - live_event_id = azurerm_media_live_event.test.id - archive_window_duration = "PT5M" - asset_name = azurerm_media_asset.test.name + name = azurerm_media_live_event_output.test.name + live_event_id = azurerm_media_live_event.test.id + archive_window_duration = "PT5M" + asset_name = azurerm_media_asset.test.name } `, r.basic(data)) From 85bc50942a6d4e0d80bceb4056af062473bded32 Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Wed, 7 Apr 2021 18:07:00 -0600 Subject: [PATCH 6/7] apply code review suggestions --- website/docs/r/media_live_output.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/media_live_output.html.markdown b/website/docs/r/media_live_output.html.markdown index a1314fc180fe..2eb828884670 100644 --- a/website/docs/r/media_live_output.html.markdown +++ b/website/docs/r/media_live_output.html.markdown @@ -6,7 +6,7 @@ description: |- Manages an Azure Media Live Event Output. --- -# azurerm_media_live_output +# azurerm_media_live_event_output Manages a Azure Media Live Event Output. @@ -83,7 +83,7 @@ The following arguments are supported: * `live_event_id` - (Required) The id of the live event. Changing this forces a new Live Output to be created. -* `name` - (Required) The name which should be used for this Live Output. Changing this forces a new Live Output to be created. +* `name` - (Required) The name which should be used for this Live Event Output. Changing this forces a new Live Output to be created. --- From 3b8a742696cace734c62b69ce95c339e33cf9c64 Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Thu, 8 Apr 2021 16:43:16 -0600 Subject: [PATCH 7/7] Rename output_snap_time attribute --- .../internal/services/media/media_live_output_resource.go | 6 +++--- .../services/media/media_live_output_resource_test.go | 2 +- website/docs/r/media_live_output.html.markdown | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/azurerm/internal/services/media/media_live_output_resource.go b/azurerm/internal/services/media/media_live_output_resource.go index e2883abcf1ea..7dfb898d2e52 100644 --- a/azurerm/internal/services/media/media_live_output_resource.go +++ b/azurerm/internal/services/media/media_live_output_resource.go @@ -89,7 +89,7 @@ func resourceMediaLiveOutput() *schema.Resource { ValidateFunc: validation.StringIsNotEmpty, }, - "output_snap_timestamp": { + "output_snap_time_in_seconds": { Type: schema.TypeInt, Optional: true, ForceNew: true, @@ -149,7 +149,7 @@ func resourceMediaLiveOutputCreate(d *schema.ResourceData, meta interface{}) err parameters.LiveOutputProperties.ManifestName = utils.String(manifestName.(string)) } - if outputSnapTime, ok := d.GetOk("output_snap_time"); ok { + if outputSnapTime, ok := d.GetOk("output_snap_time_in_seconds"); ok { parameters.LiveOutputProperties.OutputSnapTime = utils.Int64(int64(outputSnapTime.(int))) } @@ -210,7 +210,7 @@ func resourceMediaLiveOutputRead(d *schema.ResourceData, meta interface{}) error if props.OutputSnapTime != nil { outputSnapTime = *props.OutputSnapTime } - d.Set("output_snap_timestamp", outputSnapTime) + d.Set("output_snap_time_in_seconds", outputSnapTime) } return nil diff --git a/azurerm/internal/services/media/media_live_output_resource_test.go b/azurerm/internal/services/media/media_live_output_resource_test.go index 9311ffa2d0d7..8561627f1438 100644 --- a/azurerm/internal/services/media/media_live_output_resource_test.go +++ b/azurerm/internal/services/media/media_live_output_resource_test.go @@ -145,7 +145,7 @@ resource "azurerm_media_live_event_output" "test" { asset_name = azurerm_media_asset.test.name description = "Test live output 1" manifest_name = "testmanifest" - output_snap_timestamp = 0 + output_snap_time_in_seconds = 0 hls_fragments_per_ts_segment = 5 } diff --git a/website/docs/r/media_live_output.html.markdown b/website/docs/r/media_live_output.html.markdown index 2eb828884670..b064b72bb523 100644 --- a/website/docs/r/media_live_output.html.markdown +++ b/website/docs/r/media_live_output.html.markdown @@ -68,7 +68,7 @@ resource "azurerm_media_live_event_output" "example" { asset_name = azurerm_media_asset.example.name description = "Test live output 1" manifest_name = "testmanifest" - output_snap_timestamp = 0 + output_snap_time_in_seconds = 0 hls_fragments_per_ts_segment = 5 } ``` @@ -93,7 +93,7 @@ The following arguments are supported: * `manifest_name` - (Optional) The manifest file name. If not provided, the service will generate one automatically. Changing this forces a new Live Output to be created. -* `output_snap_timestamp` - (Optional) The initial timestamp that the live output will start at, any content before this value will not be archived. Changing this forces a new Live Output to be created. +* `output_snap_timestamp_in_seconds` - (Optional) The initial timestamp that the live output will start at, any content before this value will not be archived. Changing this forces a new Live Output to be created. ## Attributes Reference