From 427e58a2d8b8aa542847947ff8ca917e087f57f1 Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Mon, 22 Mar 2021 15:38:28 -0600 Subject: [PATCH 1/8] Include definition for Asset Filter resource --- .../internal/services/media/client/client.go | 5 + .../media/media_asset_filter_resource.go | 173 ++++++++++++++++++ .../services/media/parse/asset_filter.go | 81 ++++++++ .../services/media/parse/asset_filter_test.go | 144 +++++++++++++++ .../internal/services/media/registration.go | 1 + .../internal/services/media/resourceids.go | 1 + .../media/validate/asset_filter_id.go | 23 +++ .../media/validate/asset_filter_id_test.go | 100 ++++++++++ 8 files changed, 528 insertions(+) create mode 100644 azurerm/internal/services/media/media_asset_filter_resource.go create mode 100644 azurerm/internal/services/media/parse/asset_filter.go create mode 100644 azurerm/internal/services/media/parse/asset_filter_test.go create mode 100644 azurerm/internal/services/media/validate/asset_filter_id.go create mode 100644 azurerm/internal/services/media/validate/asset_filter_id_test.go diff --git a/azurerm/internal/services/media/client/client.go b/azurerm/internal/services/media/client/client.go index 85bbd0549852..57be41ab0ed2 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 + AssetFiltersClient *media.AssetFiltersClient } 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) + AssetFiltersClient := media.NewAssetFiltersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&AssetFiltersClient.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, + AssetFiltersClient: &AssetFiltersClient, } } diff --git a/azurerm/internal/services/media/media_asset_filter_resource.go b/azurerm/internal/services/media/media_asset_filter_resource.go new file mode 100644 index 000000000000..7520ebe800b1 --- /dev/null +++ b/azurerm/internal/services/media/media_asset_filter_resource.go @@ -0,0 +1,173 @@ +package media + +import ( + "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/internal/services/media/parse" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" +) + +func resourceMediaAssetFilter() *schema.Resource { + return &schema.Resource{ + Create: resourceMediaAssetFilterCreateUpdate, + Read: resourceMediaAssetFilterRead, + Update: resourceMediaAssetFilterCreateUpdate, + Delete: resourceMediaAssetFilterDelete, + + 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.AssetFilterID(id) + return err + }), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^[-a-zA-Z0-9(_)]{1,128}$"), + "Asset Filter name must be 1 - 128 characters long, can contain letters, numbers, underscores, and hyphens (but the first and last character must be a letter or number).", + ), + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "media_services_account_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: ValidateMediaServicesAccountName, + }, + + "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.", + ), + }, + + "first_quality_bitrate": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + + "presentation_time_range": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end_timestamp": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(0), + }, + + "force_end_timestamp": { + Type: schema.TypeBool, + Optional: true, + }, + + "live_backoff_duration": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(0), + }, + + "presentation_window_duration": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(0), + }, + + "start_timestamp": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(0), + }, + + "time_scale": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(0), + }, + }, + }, + }, + + "track": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "selection": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "operation": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(media.Equal), + string(media.NotEqual), + }, false), + }, + + "property": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(media.FilterTrackPropertyTypeBitrate), + string(media.FilterTrackPropertyTypeFourCC), + string(media.FilterTrackPropertyTypeLanguage), + string(media.FilterTrackPropertyTypeName), + string(media.FilterTrackPropertyTypeType), + }, false), + }, + + "value": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourceMediaAssetFilterCreateUpdate(d *schema.ResourceData, meta interface{}) error { + + return resourceMediaAssetFilterRead(d, meta) +} + +func resourceMediaAssetFilterRead(d *schema.ResourceData, meta interface{}) error { + + return nil +} + +func resourceMediaAssetFilterDelete(d *schema.ResourceData, meta interface{}) error { + + return nil +} diff --git a/azurerm/internal/services/media/parse/asset_filter.go b/azurerm/internal/services/media/parse/asset_filter.go new file mode 100644 index 000000000000..a22fd34e3378 --- /dev/null +++ b/azurerm/internal/services/media/parse/asset_filter.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 AssetFilterId struct { + SubscriptionId string + ResourceGroup string + MediaserviceName string + AssetName string + Name string +} + +func NewAssetFilterID(subscriptionId, resourceGroup, mediaserviceName, assetName, name string) AssetFilterId { + return AssetFilterId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + MediaserviceName: mediaserviceName, + AssetName: assetName, + Name: name, + } +} + +func (id AssetFilterId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Asset Name %q", id.AssetName), + fmt.Sprintf("Mediaservice Name %q", id.MediaserviceName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Asset Filter", segmentsStr) +} + +func (id AssetFilterId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Media/mediaservices/%s/assets/%s/assetFilters/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.MediaserviceName, id.AssetName, id.Name) +} + +// AssetFilterID parses a AssetFilter ID into an AssetFilterId struct +func AssetFilterID(input string) (*AssetFilterId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := AssetFilterId{ + 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.AssetName, err = id.PopSegment("assets"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("assetFilters"); 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/asset_filter_test.go b/azurerm/internal/services/media/parse/asset_filter_test.go new file mode 100644 index 000000000000..faddbc5641ef --- /dev/null +++ b/azurerm/internal/services/media/parse/asset_filter_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 = AssetFilterId{} + +func TestAssetFilterIDFormatter(t *testing.T) { + actual := NewAssetFilterID("12345678-1234-9876-4563-123456789012", "resGroup1", "account1", "asset1", "filter1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/assetFilters/filter1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestAssetFilterID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *AssetFilterId + }{ + + { + // 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 AssetName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/", + Error: true, + }, + + { + // missing value for AssetName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/assetFilters/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/assetFilters/filter1", + Expected: &AssetFilterId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + MediaserviceName: "account1", + AssetName: "asset1", + Name: "filter1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.MEDIA/MEDIASERVICES/ACCOUNT1/ASSETS/ASSET1/ASSETFILTERS/FILTER1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := AssetFilterID(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.AssetName != v.Expected.AssetName { + t.Fatalf("Expected %q but got %q for AssetName", v.Expected.AssetName, actual.AssetName) + } + 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..882d6c7af90d 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_asset_filter": resourceMediaAssetFilter(), } } diff --git a/azurerm/internal/services/media/resourceids.go b/azurerm/internal/services/media/resourceids.go index d0369dd61d62..45062091dcce 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=AssetFilter -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/assetFilters/filter1 diff --git a/azurerm/internal/services/media/validate/asset_filter_id.go b/azurerm/internal/services/media/validate/asset_filter_id.go new file mode 100644 index 000000000000..21643673e40f --- /dev/null +++ b/azurerm/internal/services/media/validate/asset_filter_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 AssetFilterID(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.AssetFilterID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/media/validate/asset_filter_id_test.go b/azurerm/internal/services/media/validate/asset_filter_id_test.go new file mode 100644 index 000000000000..553146ea8d65 --- /dev/null +++ b/azurerm/internal/services/media/validate/asset_filter_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 TestAssetFilterID(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 AssetName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/", + Valid: false, + }, + + { + // missing value for AssetName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/assetFilters/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/assetFilters/filter1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.MEDIA/MEDIASERVICES/ACCOUNT1/ASSETS/ASSET1/ASSETFILTERS/FILTER1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := AssetFilterID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} From db27a174b250d1602a7e5aea381e0af36ba9f6ad Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Tue, 23 Mar 2021 18:08:50 -0600 Subject: [PATCH 2/8] Include Update/Read/Delete/Create operations --- .../media/media_asset_filter_resource.go | 245 ++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/azurerm/internal/services/media/media_asset_filter_resource.go b/azurerm/internal/services/media/media_asset_filter_resource.go index 7520ebe800b1..2f5ac51a5fc1 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource.go +++ b/azurerm/internal/services/media/media_asset_filter_resource.go @@ -1,6 +1,8 @@ package media import ( + "fmt" + "log" "regexp" "time" @@ -8,8 +10,12 @@ import ( "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 resourceMediaAssetFilter() *schema.Resource { @@ -158,16 +164,255 @@ func resourceMediaAssetFilter() *schema.Resource { } func resourceMediaAssetFilterCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Media.AssetFiltersClient + subscriptionID := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + resourceID := parse.NewAssetFilterID(subscriptionID, d.Get("resource_group_name").(string), d.Get("media_services_account_name").(string), d.Get("asset_name").(string), d.Get("name").(string)) + if d.IsNewResource() { + existing, err := client.Get(ctx, resourceID.ResourceGroup, resourceID.MediaserviceName, resourceID.AssetName, resourceID.Name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of %s: %+v", resourceID, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_media_content_key_policy", resourceID.ID()) + } + } + + parameters := media.AssetFilter{ + FilterProperties: &media.FilterProperties{ + FirstQuality: &media.FirstQuality{}, + }, + } + + if firstQualityBitrate, ok := d.GetOk("first_quality_bitrate"); ok { + parameters.FilterProperties.FirstQuality.Bitrate = utils.Int32(int32(firstQualityBitrate.(int))) + } + + if v, ok := d.GetOk("presentation_time_range"); ok { + parameters.FilterProperties.PresentationTimeRange = expandPresentationTimeRange(v.([]interface{})) + } + + if v, ok := d.GetOk("track"); ok { + parameters.FilterProperties.Tracks = expandTracks(v.([]interface{})) + } + + _, err := client.CreateOrUpdate(ctx, resourceID.ResourceGroup, resourceID.MediaserviceName, resourceID.AssetName, resourceID.Name, parameters) + if err != nil { + return fmt.Errorf("creating/updating %s: %+v", resourceID, err) + } + + d.SetId(resourceID.ID()) return resourceMediaAssetFilterRead(d, meta) } func resourceMediaAssetFilterRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Media.AssetFiltersClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.AssetFilterID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.MediaserviceName, id.AssetName, 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("asset_name", id.AssetName) + + if props := resp.FilterProperties; props != nil { + + var firstQualityBitrate int32 + if props.FirstQuality != nil && props.FirstQuality.Bitrate != nil { + firstQualityBitrate = *props.FirstQuality.Bitrate + } + d.Set("first_quality_bitrate", firstQualityBitrate) + + if err := d.Set("presentation_time_range", flattenPresentationTimeRange(resp.PresentationTimeRange)); err != nil { + return fmt.Errorf("Error flattening `presentation_time_range`: %s", err) + } + + if err := d.Set("track", flattenTracks(resp.Tracks)); err != nil { + return fmt.Errorf("Error flattening `track`: %s", err) + } + } return nil } func resourceMediaAssetFilterDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Media.AssetFiltersClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.AssetFilterID(d.Id()) + if err != nil { + return err + } + + if _, err = client.Delete(ctx, id.ResourceGroup, id.MediaserviceName, id.AssetName, id.Name); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } return nil } + +func expandPresentationTimeRange(input []interface{}) *media.PresentationTimeRange { + if len(input) == 0 { + return nil + } + + timeRange := input[0].(map[string]interface{}) + presentationTimeRange := &media.PresentationTimeRange{} + + if v := timeRange["end_timestamp"]; v != nil { + presentationTimeRange.EndTimestamp = utils.Int64(int64(v.(int))) + } + + if v := timeRange["force_end_timestamp"]; v != nil { + presentationTimeRange.ForceEndTimestamp = utils.Bool(v.(bool)) + } + + if v := timeRange["live_backoff_duration"]; v != nil { + presentationTimeRange.LiveBackoffDuration = utils.Int64(int64(v.(int))) + } + + if v := timeRange["presentation_window_duration"]; v != nil { + presentationTimeRange.LiveBackoffDuration = utils.Int64(int64(v.(int))) + } + + if v := timeRange["start_timestamp"]; v != nil { + presentationTimeRange.StartTimestamp = utils.Int64(int64(v.(int))) + } + + if v := timeRange["time_scale"]; v != nil { + presentationTimeRange.Timescale = utils.Int64(int64(v.(int))) + } + + return presentationTimeRange +} + +func flattenPresentationTimeRange(input *media.PresentationTimeRange) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + var endTimestamp int64 + if input.EndTimestamp != nil { + endTimestamp = *input.EndTimestamp + } + + var forceEndTimestamp bool + if input.ForceEndTimestamp != nil { + forceEndTimestamp = *input.ForceEndTimestamp + } + + var liveBackoffDuration int64 + if input.LiveBackoffDuration != nil { + liveBackoffDuration = *input.LiveBackoffDuration + } + + var presentationWindowDuration int64 + if input.PresentationWindowDuration != nil { + presentationWindowDuration = *input.PresentationWindowDuration + } + + var startTimestamp int64 + if input.StartTimestamp != nil { + endTimestamp = *input.StartTimestamp + } + + var timeScale int64 + if input.Timescale != nil { + timeScale = *input.Timescale + } + + return []interface{}{ + map[string]interface{}{ + "end_timestamp": endTimestamp, + "force_end_timestamp": forceEndTimestamp, + "live_backoff_duration": liveBackoffDuration, + "presentation_window_duration": presentationWindowDuration, + "start_timestamp": startTimestamp, + "time_scale": timeScale, + }, + } +} + +func expandTracks(input []interface{}) *[]media.FilterTrackSelection { + results := make([]media.FilterTrackSelection, 0) + + for _, trackRaw := range input { + track := trackRaw.(map[string]interface{}) + + if rawSelection, ok := track["selection"]; ok { + trackSelectionList := rawSelection.([]interface{}) + filterTrackSelections := make([]media.FilterTrackPropertyCondition, 0) + for _, trackSelection := range trackSelectionList { + filterTrackSelection := media.FilterTrackPropertyCondition{} + track := trackSelection.(map[string]interface{}) + + if v := track["operation"]; v != nil { + filterTrackSelection.Operation = media.FilterTrackPropertyCompareOperation(v.(string)) + } + + if v := track["property"]; v != nil { + filterTrackSelection.Property = media.FilterTrackPropertyType(v.(string)) + } + + if v := track["value"]; v != nil { + filterTrackSelection.Value = utils.String(v.(string)) + } + + filterTrackSelections = append(filterTrackSelections, filterTrackSelection) + } + + results = append(results, media.FilterTrackSelection{ + TrackSelections: &filterTrackSelections, + }) + } + + } + + return &results +} + +func flattenTracks(input *[]media.FilterTrackSelection) []interface{} { + tracks := make([]interface{}, 0) + + for _, v := range *input { + selections := make([]interface{}, 0) + if v.TrackSelections != nil { + for _, selection := range *v.TrackSelections { + value := "" + if selection.Value != nil { + value = *selection.Value + } + + selections = append(selections, map[string]interface{}{ + "operation": string(selection.Operation), + "property": string(selection.Property), + "value": value, + }) + + } + } + } + + return tracks +} From 7ec5b4d7ace77d1679e2e3cb69b8f9d0f43cad37 Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Wed, 24 Mar 2021 17:44:22 -0600 Subject: [PATCH 3/8] Include acc test for Asset Filters --- .../media/media_asset_filter_resource.go | 15 +- .../media/media_asset_filter_resource_test.go | 201 ++++++++++++++++++ 2 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 azurerm/internal/services/media/media_asset_filter_resource_test.go diff --git a/azurerm/internal/services/media/media_asset_filter_resource.go b/azurerm/internal/services/media/media_asset_filter_resource.go index 2f5ac51a5fc1..27355f9ef116 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource.go +++ b/azurerm/internal/services/media/media_asset_filter_resource.go @@ -108,7 +108,7 @@ func resourceMediaAssetFilter() *schema.Resource { ValidateFunc: validation.IntAtLeast(0), }, - "time_scale": { + "timescale": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), @@ -293,14 +293,14 @@ func expandPresentationTimeRange(input []interface{}) *media.PresentationTimeRan } if v := timeRange["presentation_window_duration"]; v != nil { - presentationTimeRange.LiveBackoffDuration = utils.Int64(int64(v.(int))) + presentationTimeRange.PresentationWindowDuration = utils.Int64(int64(v.(int))) } if v := timeRange["start_timestamp"]; v != nil { presentationTimeRange.StartTimestamp = utils.Int64(int64(v.(int))) } - if v := timeRange["time_scale"]; v != nil { + if v := timeRange["timescale"]; v != nil { presentationTimeRange.Timescale = utils.Int64(int64(v.(int))) } @@ -334,7 +334,7 @@ func flattenPresentationTimeRange(input *media.PresentationTimeRange) []interfac var startTimestamp int64 if input.StartTimestamp != nil { - endTimestamp = *input.StartTimestamp + startTimestamp = *input.StartTimestamp } var timeScale int64 @@ -349,7 +349,7 @@ func flattenPresentationTimeRange(input *media.PresentationTimeRange) []interfac "live_backoff_duration": liveBackoffDuration, "presentation_window_duration": presentationWindowDuration, "start_timestamp": startTimestamp, - "time_scale": timeScale, + "timescale": timeScale, }, } } @@ -360,7 +360,7 @@ func expandTracks(input []interface{}) *[]media.FilterTrackSelection { for _, trackRaw := range input { track := trackRaw.(map[string]interface{}) - if rawSelection, ok := track["selection"]; ok { + if rawSelection := track["selection"]; rawSelection != nil { trackSelectionList := rawSelection.([]interface{}) filterTrackSelections := make([]media.FilterTrackPropertyCondition, 0) for _, trackSelection := range trackSelectionList { @@ -412,6 +412,9 @@ func flattenTracks(input *[]media.FilterTrackSelection) []interface{} { } } + tracks = append(tracks, map[string]interface{}{ + "selection": selections, + }) } return tracks diff --git a/azurerm/internal/services/media/media_asset_filter_resource_test.go b/azurerm/internal/services/media/media_asset_filter_resource_test.go new file mode 100644 index 000000000000..276224a9f092 --- /dev/null +++ b/azurerm/internal/services/media/media_asset_filter_resource_test.go @@ -0,0 +1,201 @@ +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 AssetFilterResource struct{} + +func TestAccAssetFilter_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_media_asset_filter", "test") + r := AssetFilterResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("name").HasValue("Filter-1"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccAssetFilter_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_media_asset_filter", "test") + r := AssetFilterResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("name").HasValue("Filter-1"), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccAssetFilter_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_media_asset_filter", "test") + r := AssetFilterResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("first_quality_bitrate").HasValue("128000"), + ), + }, + data.ImportStep(), + }) +} + +func (AssetFilterResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.AssetFilterID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Media.AssetFiltersClient.Get(ctx, id.ResourceGroup, id.MediaserviceName, id.AssetName, id.Name) + if err != nil { + return nil, fmt.Errorf("retrieving Asset Filter %s (Media Services Account %s) (resource group: %s): %v", id.Name, id.MediaserviceName, id.ResourceGroup, err) + } + + return utils.Bool(resp.FilterProperties != nil), nil +} + +func (r AssetFilterResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_media_asset_filter" "test" { + name = "Filter-1" + resource_group_name = azurerm_resource_group.test.name + media_services_account_name = azurerm_media_services_account.test.name + asset_name = azurerm_media_asset.test.name +} + +`, r.template(data)) +} + +func (r AssetFilterResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_media_asset_filter" "import" { + name = azurerm_media_asset_filter.test.name + resource_group_name = azurerm_media_asset_filter.test.resource_group_name + media_services_account_name = azurerm_media_asset_filter.test.media_services_account_name + asset_name = azurerm_media_asset.test.name +} + +`, r.basic(data)) +} + +func (r AssetFilterResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_media_asset_filter" "test" { + name = "Filter-1" + resource_group_name = azurerm_resource_group.test.name + media_services_account_name = azurerm_media_services_account.test.name + asset_name = azurerm_media_asset.test.name + first_quality_bitrate = 128000 + + presentation_time_range { + start_timestamp = 0 + end_timestamp = 170000000 + presentation_window_duration = 9223372036854775000 + live_backoff_duration = 0 + timescale = 10000000 + force_end_timestamp = false + } + + track { + selection { + property = "Type" + operation = "Equal" + value = "Audio" + } + + selection { + property = "Language" + operation = "NotEqual" + value = "en" + } + + selection { + property = "FourCC" + operation = "NotEqual" + value = "EC-3" + } + } + + + track { + selection { + property = "Type" + operation = "Equal" + value = "Video" + } + + selection { + property = "Bitrate" + operation = "Equal" + value = "3000000-5000000" + } + } +} + +`, r.template(data)) +} + +func (AssetFilterResource) 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 = "test" + resource_group_name = azurerm_resource_group.test.name + media_services_account_name = azurerm_media_services_account.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) +} From 17d4535ed429a83cd4ab141a87284c86db74305c Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Thu, 25 Mar 2021 10:03:25 -0600 Subject: [PATCH 4/8] Include documentation for Asset filter --- .../media/media_asset_filter_resource.go | 3 - .../media/media_asset_filter_resource_test.go | 70 +++---- .../docs/r/media_asset_filter.html.markdown | 173 ++++++++++++++++++ 3 files changed, 208 insertions(+), 38 deletions(-) create mode 100644 website/docs/r/media_asset_filter.html.markdown diff --git a/azurerm/internal/services/media/media_asset_filter_resource.go b/azurerm/internal/services/media/media_asset_filter_resource.go index 27355f9ef116..c3acf5327d51 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource.go +++ b/azurerm/internal/services/media/media_asset_filter_resource.go @@ -236,7 +236,6 @@ func resourceMediaAssetFilterRead(d *schema.ResourceData, meta interface{}) erro d.Set("asset_name", id.AssetName) if props := resp.FilterProperties; props != nil { - var firstQualityBitrate int32 if props.FirstQuality != nil && props.FirstQuality.Bitrate != nil { firstQualityBitrate = *props.FirstQuality.Bitrate @@ -386,7 +385,6 @@ func expandTracks(input []interface{}) *[]media.FilterTrackSelection { TrackSelections: &filterTrackSelections, }) } - } return &results @@ -409,7 +407,6 @@ func flattenTracks(input *[]media.FilterTrackSelection) []interface{} { "property": string(selection.Property), "value": value, }) - } } tracks = append(tracks, map[string]interface{}{ diff --git a/azurerm/internal/services/media/media_asset_filter_resource_test.go b/azurerm/internal/services/media/media_asset_filter_resource_test.go index 276224a9f092..378abea7921b 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource_test.go +++ b/azurerm/internal/services/media/media_asset_filter_resource_test.go @@ -83,7 +83,7 @@ resource "azurerm_media_asset_filter" "test" { name = "Filter-1" resource_group_name = azurerm_resource_group.test.name media_services_account_name = azurerm_media_services_account.test.name - asset_name = azurerm_media_asset.test.name + asset_name = azurerm_media_asset.test.name } `, r.template(data)) @@ -97,7 +97,7 @@ resource "azurerm_media_asset_filter" "import" { name = azurerm_media_asset_filter.test.name resource_group_name = azurerm_media_asset_filter.test.resource_group_name media_services_account_name = azurerm_media_asset_filter.test.media_services_account_name - asset_name = azurerm_media_asset.test.name + asset_name = azurerm_media_asset.test.name } `, r.basic(data)) @@ -111,12 +111,12 @@ resource "azurerm_media_asset_filter" "test" { name = "Filter-1" resource_group_name = azurerm_resource_group.test.name media_services_account_name = azurerm_media_services_account.test.name - asset_name = azurerm_media_asset.test.name + asset_name = azurerm_media_asset.test.name first_quality_bitrate = 128000 presentation_time_range { - start_timestamp = 0 - end_timestamp = 170000000 + start_timestamp = 0 + end_timestamp = 170000000 presentation_window_duration = 9223372036854775000 live_backoff_duration = 0 timescale = 10000000 @@ -124,39 +124,39 @@ resource "azurerm_media_asset_filter" "test" { } track { - selection { - property = "Type" - operation = "Equal" - value = "Audio" - } - - selection { - property = "Language" - operation = "NotEqual" - value = "en" - } - - selection { - property = "FourCC" - operation = "NotEqual" - value = "EC-3" - } + selection { + property = "Type" + operation = "Equal" + value = "Audio" } + selection { + property = "Language" + operation = "NotEqual" + value = "en" + } - track { - selection { - property = "Type" - operation = "Equal" - value = "Video" - } - - selection { - property = "Bitrate" - operation = "Equal" - value = "3000000-5000000" - } - } + selection { + property = "FourCC" + operation = "NotEqual" + value = "EC-3" + } + } + + + track { + selection { + property = "Type" + operation = "Equal" + value = "Video" + } + + selection { + property = "Bitrate" + operation = "Equal" + value = "3000000-5000000" + } + } } `, r.template(data)) diff --git a/website/docs/r/media_asset_filter.html.markdown b/website/docs/r/media_asset_filter.html.markdown new file mode 100644 index 000000000000..7e8243361973 --- /dev/null +++ b/website/docs/r/media_asset_filter.html.markdown @@ -0,0 +1,173 @@ +--- +subcategory: "Media" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_media_asset_filter" +description: |- + Manages an Asset Filter. +--- + +# azurerm_media_asset_filter + +Manages an Asset Filter. + +## 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 = "Asset1" + resource_group_name = azurerm_resource_group.example.name + media_services_account_name = azurerm_media_services_account.example.name + description = "Asset description" +} + +resource "azurerm_media_asset_filter" "example" { + name = "Filter1" + resource_group_name = azurerm_resource_group.example.name + media_services_account_name = azurerm_media_services_account.example.name + asset_name = azurerm_media_asset.example.name + first_quality_bitrate = 128000 + + presentation_time_range { + start_timestamp = 0 + end_timestamp = 170000000 + presentation_window_duration = 9223372036854775000 + live_backoff_duration = 0 + timescale = 10000000 + force_end_timestamp = false + } + + track { + selection { + property = "Type" + operation = "Equal" + value = "Audio" + } + + selection { + property = "Language" + operation = "NotEqual" + value = "en" + } + + selection { + property = "FourCC" + operation = "NotEqual" + value = "EC-3" + } + } + + + track { + selection { + property = "Type" + operation = "Equal" + value = "Video" + } + + selection { + property = "Bitrate" + operation = "Equal" + value = "3000000-5000000" + } + } +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `asset_name` - (Required) The Asset name. Changing this forces a new Asset Filter to be created. + +* `media_services_account_name` - (Required) Specifies the name of the Media Services Account. Changing this forces a new Asset Filter to be created. + +* `name` - (Required) The name which should be used for this Asset Filter. Changing this forces a new Asset Filter to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the Asset Filter should exist. Changing this forces a new Asset Filter to be created. + +--- + +* `first_quality_bitrate` - (Optional) The first quality bitrate. + +* `presentation_time_range` - (Optional) A `presentation_time_range` block as defined below. + +* `track` - (Optional) One or more `track` blocks as defined below. + +--- + +A `presentation_time_range` block supports the following: + +* `end_timestamp` - (Optional) The absolute end time boundary. + +* `force_end_timestamp` - (Optional) The indicator of forcing existing of end time stamp. + +* `live_backoff_duration` - (Optional) The relative to end right edge. + +* `presentation_window_duration` - (Optional) The relative to end sliding window. + +* `start_timestamp` - (Optional) The absolute start time boundary. + +* `timescale` - (Optional) The time scale of time stamps. + +--- + +A `selection` block supports the following: + +* `operation` - (Optional) The track property condition operation. Supported values are `Equal` and `NotEqual`. + +* `property` - (Optional) The track property type. Supported values are `Bitrate`, `FourCC`, `Language`, `Name` and `Type`. + +* `value` - (Optional) The track property value. + +--- + +A `track` block supports the following: + +* `selection` - (Optional) One or more `selection` blocks as defined above. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Asset Filter. + +## 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 Asset Filter. +* `read` - (Defaults to 5 minutes) Used when retrieving the Asset Filter. +* `update` - (Defaults to 30 minutes) Used when updating the Asset Filter. +* `delete` - (Defaults to 30 minutes) Used when deleting the Asset Filter. + +## Import + +Asset Filters can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_media_asset_filter.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Media/mediaservices/account1/assets/asset1/assetFilters/filter1 +``` From 6ec6d764037b4a15707d47aa37a953eec7f5e65a Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Thu, 25 Mar 2021 10:40:12 -0600 Subject: [PATCH 5/8] depscheck difference --- .../mgmt/2019-06-01-preview/templatespecs/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2019-06-01-preview/templatespecs/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2019-06-01-preview/templatespecs/CHANGELOG.md index f08cecd3bc6f..2cf4f187cbae 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2019-06-01-preview/templatespecs/CHANGELOG.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2019-06-01-preview/templatespecs/CHANGELOG.md @@ -1,5 +1,5 @@ Generated from https://github.com/Azure/azure-rest-api-specs/tree/b08824e05817297a4b2874d8db5e6fc8c29349c9//specification/resources/resource-manager/readme.md tag: `package-templatespecs-2019-06-preview` -Code generator @microsoft.azure/autorest.go@2.1.171 +Code generator @microsoft.azure/autorest.go@2.1.175 From 7977890a0609a5febe2f18845594c5438b0620e6 Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Thu, 8 Apr 2021 11:32:50 -0600 Subject: [PATCH 6/8] Apply Code review suggestions --- .../media/media_asset_filter_resource.go | 90 +++++++++---------- .../media/media_asset_filter_resource_test.go | 67 +++++++++----- .../docs/r/media_asset_filter.html.markdown | 70 +++++++-------- 3 files changed, 120 insertions(+), 107 deletions(-) diff --git a/azurerm/internal/services/media/media_asset_filter_resource.go b/azurerm/internal/services/media/media_asset_filter_resource.go index c3acf5327d51..e844abba53d6 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource.go +++ b/azurerm/internal/services/media/media_asset_filter_resource.go @@ -48,23 +48,11 @@ func resourceMediaAssetFilter() *schema.Resource { ), }, - "resource_group_name": azure.SchemaResourceGroupName(), - - "media_services_account_name": { + "asset_id": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: ValidateMediaServicesAccountName, - }, - - "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.", - ), + ValidateFunc: azure.ValidateResourceID, }, "first_quality_bitrate": { @@ -79,36 +67,36 @@ func resourceMediaAssetFilter() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "end_timestamp": { + "end_timescale": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), }, - "force_end_timestamp": { + "force_end_timescale": { Type: schema.TypeBool, Optional: true, }, - "live_backoff_duration": { + "live_backoff_in_timescale": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), }, - "presentation_window_duration": { + "presentation_window_in_timescale": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), }, - "start_timestamp": { + "start_timescale": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), }, - "timescale": { + "timescale_increment_in_seconds": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), @@ -117,12 +105,12 @@ func resourceMediaAssetFilter() *schema.Resource { }, }, - "track": { + "track_selection": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "selection": { + "condition": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ @@ -169,16 +157,21 @@ func resourceMediaAssetFilterCreateUpdate(d *schema.ResourceData, meta interface ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - resourceID := parse.NewAssetFilterID(subscriptionID, d.Get("resource_group_name").(string), d.Get("media_services_account_name").(string), d.Get("asset_name").(string), d.Get("name").(string)) + assetID, err := parse.AssetID(d.Get("asset_id").(string)) + if err != nil { + return err + } + + id := parse.NewAssetFilterID(subscriptionID, assetID.ResourceGroup, assetID.MediaserviceName, assetID.Name, d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, resourceID.ResourceGroup, resourceID.MediaserviceName, resourceID.AssetName, resourceID.Name) + existing, err := client.Get(ctx, id.ResourceGroup, id.MediaserviceName, id.AssetName, id.Name) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of %s: %+v", resourceID, err) + return fmt.Errorf("checking for presence of %s: %+v", id, err) } } if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_media_content_key_policy", resourceID.ID()) + return tf.ImportAsExistsError("azurerm_media_asset_filter", id.ID()) } } @@ -196,22 +189,22 @@ func resourceMediaAssetFilterCreateUpdate(d *schema.ResourceData, meta interface parameters.FilterProperties.PresentationTimeRange = expandPresentationTimeRange(v.([]interface{})) } - if v, ok := d.GetOk("track"); ok { + if v, ok := d.GetOk("track_selection"); ok { parameters.FilterProperties.Tracks = expandTracks(v.([]interface{})) } - _, err := client.CreateOrUpdate(ctx, resourceID.ResourceGroup, resourceID.MediaserviceName, resourceID.AssetName, resourceID.Name, parameters) - if err != nil { - return fmt.Errorf("creating/updating %s: %+v", resourceID, err) + if _, err = client.CreateOrUpdate(ctx, id.ResourceGroup, id.MediaserviceName, id.AssetName, id.Name, parameters); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } - d.SetId(resourceID.ID()) + d.SetId(id.ID()) return resourceMediaAssetFilterRead(d, meta) } func resourceMediaAssetFilterRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Media.AssetFiltersClient + subscriptionID := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -231,9 +224,8 @@ func resourceMediaAssetFilterRead(d *schema.ResourceData, meta interface{}) erro } d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("media_services_account_name", id.MediaserviceName) - d.Set("asset_name", id.AssetName) + assetID := parse.NewAssetID(subscriptionID, id.ResourceGroup, id.MediaserviceName, id.AssetName) + d.Set("asset_id", assetID.ID()) if props := resp.FilterProperties; props != nil { var firstQualityBitrate int32 @@ -246,7 +238,7 @@ func resourceMediaAssetFilterRead(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("Error flattening `presentation_time_range`: %s", err) } - if err := d.Set("track", flattenTracks(resp.Tracks)); err != nil { + if err := d.Set("track_selection", flattenTracks(resp.Tracks)); err != nil { return fmt.Errorf("Error flattening `track`: %s", err) } } @@ -279,27 +271,27 @@ func expandPresentationTimeRange(input []interface{}) *media.PresentationTimeRan timeRange := input[0].(map[string]interface{}) presentationTimeRange := &media.PresentationTimeRange{} - if v := timeRange["end_timestamp"]; v != nil { + if v := timeRange["end_timescale"]; v != nil { presentationTimeRange.EndTimestamp = utils.Int64(int64(v.(int))) } - if v := timeRange["force_end_timestamp"]; v != nil { + if v := timeRange["force_end_timescale"]; v != nil { presentationTimeRange.ForceEndTimestamp = utils.Bool(v.(bool)) } - if v := timeRange["live_backoff_duration"]; v != nil { + if v := timeRange["live_backoff_in_timescale"]; v != nil { presentationTimeRange.LiveBackoffDuration = utils.Int64(int64(v.(int))) } - if v := timeRange["presentation_window_duration"]; v != nil { + if v := timeRange["presentation_window_in_timescale"]; v != nil { presentationTimeRange.PresentationWindowDuration = utils.Int64(int64(v.(int))) } - if v := timeRange["start_timestamp"]; v != nil { + if v := timeRange["start_timescale"]; v != nil { presentationTimeRange.StartTimestamp = utils.Int64(int64(v.(int))) } - if v := timeRange["timescale"]; v != nil { + if v := timeRange["timescale_increment_in_seconds"]; v != nil { presentationTimeRange.Timescale = utils.Int64(int64(v.(int))) } @@ -343,12 +335,12 @@ func flattenPresentationTimeRange(input *media.PresentationTimeRange) []interfac return []interface{}{ map[string]interface{}{ - "end_timestamp": endTimestamp, - "force_end_timestamp": forceEndTimestamp, - "live_backoff_duration": liveBackoffDuration, - "presentation_window_duration": presentationWindowDuration, - "start_timestamp": startTimestamp, - "timescale": timeScale, + "end_timescale": endTimestamp, + "force_end_timescale": forceEndTimestamp, + "live_backoff_in_timescale": liveBackoffDuration, + "presentation_window_in_timescale": presentationWindowDuration, + "start_timescale": startTimestamp, + "timescale_increment_in_seconds": timeScale, }, } } @@ -359,7 +351,7 @@ func expandTracks(input []interface{}) *[]media.FilterTrackSelection { for _, trackRaw := range input { track := trackRaw.(map[string]interface{}) - if rawSelection := track["selection"]; rawSelection != nil { + if rawSelection := track["condition"]; rawSelection != nil { trackSelectionList := rawSelection.([]interface{}) filterTrackSelections := make([]media.FilterTrackPropertyCondition, 0) for _, trackSelection := range trackSelectionList { @@ -410,7 +402,7 @@ func flattenTracks(input *[]media.FilterTrackSelection) []interface{} { } } tracks = append(tracks, map[string]interface{}{ - "selection": selections, + "condition": selections, }) } diff --git a/azurerm/internal/services/media/media_asset_filter_resource_test.go b/azurerm/internal/services/media/media_asset_filter_resource_test.go index 378abea7921b..954c817214d4 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource_test.go +++ b/azurerm/internal/services/media/media_asset_filter_resource_test.go @@ -61,6 +61,35 @@ func TestAccAssetFilter_complete(t *testing.T) { }) } +func TestAccAssetFilter_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_media_asset_filter", "test") + r := AssetFilterResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("name").HasValue("Filter-1"), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("first_quality_bitrate").HasValue("128000"), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: resource.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).Key("name").HasValue("Filter-1"), + ), + }, + data.ImportStep(), + }) +} + func (AssetFilterResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { id, err := parse.AssetFilterID(state.ID) if err != nil { @@ -81,9 +110,7 @@ func (r AssetFilterResource) basic(data acceptance.TestData) string { resource "azurerm_media_asset_filter" "test" { name = "Filter-1" - resource_group_name = azurerm_resource_group.test.name - media_services_account_name = azurerm_media_services_account.test.name - asset_name = azurerm_media_asset.test.name + asset_id = azurerm_media_asset.test.id } `, r.template(data)) @@ -95,9 +122,7 @@ func (r AssetFilterResource) requiresImport(data acceptance.TestData) string { resource "azurerm_media_asset_filter" "import" { name = azurerm_media_asset_filter.test.name - resource_group_name = azurerm_media_asset_filter.test.resource_group_name - media_services_account_name = azurerm_media_asset_filter.test.media_services_account_name - asset_name = azurerm_media_asset.test.name + asset_id = azurerm_media_asset.test.id } `, r.basic(data)) @@ -109,34 +134,32 @@ func (r AssetFilterResource) complete(data acceptance.TestData) string { resource "azurerm_media_asset_filter" "test" { name = "Filter-1" - resource_group_name = azurerm_resource_group.test.name - media_services_account_name = azurerm_media_services_account.test.name - asset_name = azurerm_media_asset.test.name + asset_id = azurerm_media_asset.test.id first_quality_bitrate = 128000 presentation_time_range { - start_timestamp = 0 - end_timestamp = 170000000 - presentation_window_duration = 9223372036854775000 - live_backoff_duration = 0 - timescale = 10000000 - force_end_timestamp = false + start_timescale = 0 + end_timescale = 170000000 + presentation_window_in_timescale = 9223372036854775000 + live_backoff_in_timescale = 0 + timescale_increment_in_seconds = 10000000 + force_end_timescale = false } - track { - selection { + track_selection { + condition { property = "Type" operation = "Equal" value = "Audio" } - selection { + condition { property = "Language" operation = "NotEqual" value = "en" } - selection { + condition { property = "FourCC" operation = "NotEqual" value = "EC-3" @@ -144,14 +167,14 @@ resource "azurerm_media_asset_filter" "test" { } - track { - selection { + track_selection { + condition { property = "Type" operation = "Equal" value = "Video" } - selection { + condition { property = "Bitrate" operation = "Equal" value = "3000000-5000000" diff --git a/website/docs/r/media_asset_filter.html.markdown b/website/docs/r/media_asset_filter.html.markdown index 7e8243361973..b60366785841 100644 --- a/website/docs/r/media_asset_filter.html.markdown +++ b/website/docs/r/media_asset_filter.html.markdown @@ -3,12 +3,12 @@ subcategory: "Media" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_media_asset_filter" description: |- - Manages an Asset Filter. + Manages an Azure Media Asset Filter. --- # azurerm_media_asset_filter -Manages an Asset Filter. +Manages an Azure Media Asset Filter. ## Example Usage @@ -46,34 +46,32 @@ resource "azurerm_media_asset" "example" { resource "azurerm_media_asset_filter" "example" { name = "Filter1" - resource_group_name = azurerm_resource_group.example.name - media_services_account_name = azurerm_media_services_account.example.name - asset_name = azurerm_media_asset.example.name + asset_id = azurerm_media_asset.example.id first_quality_bitrate = 128000 presentation_time_range { - start_timestamp = 0 - end_timestamp = 170000000 - presentation_window_duration = 9223372036854775000 - live_backoff_duration = 0 - timescale = 10000000 - force_end_timestamp = false + start_timescale = 0 + end_timescale = 170000000 + presentation_window_in_timescale = 9223372036854775000 + live_backoff_in_timescale = 0 + timescale_increment_in_seconds = 10000000 + force_end_timescale = false } - track { - selection { + track_selection { + condition { property = "Type" operation = "Equal" value = "Audio" } - selection { + condition { property = "Language" operation = "NotEqual" value = "en" } - selection { + condition { property = "FourCC" operation = "NotEqual" value = "EC-3" @@ -81,14 +79,14 @@ resource "azurerm_media_asset_filter" "example" { } - track { - selection { + track_selection { + condition { property = "Type" operation = "Equal" value = "Video" } - selection { + condition { property = "Bitrate" operation = "Equal" value = "3000000-5000000" @@ -101,53 +99,53 @@ resource "azurerm_media_asset_filter" "example" { The following arguments are supported: -* `asset_name` - (Required) The Asset name. Changing this forces a new Asset Filter to be created. - -* `media_services_account_name` - (Required) Specifies the name of the Media Services Account. Changing this forces a new Asset Filter to be created. +* `asset_id` - (Required) The Asset ID for which the Asset Filter should be created. Changing this forces a new Asset Filter to be created. * `name` - (Required) The name which should be used for this Asset Filter. Changing this forces a new Asset Filter to be created. -* `resource_group_name` - (Required) The name of the Resource Group where the Asset Filter should exist. Changing this forces a new Asset Filter to be created. - --- -* `first_quality_bitrate` - (Optional) The first quality bitrate. +* `first_quality_bitrate` - (Optional) The first quality bitrate. Sets the first video track to appear in the Live Streaming playlist to allow HLS native players to start downloading from this quality level at the beginning. * `presentation_time_range` - (Optional) A `presentation_time_range` block as defined below. -* `track` - (Optional) One or more `track` blocks as defined below. +* `track_selection` - (Optional) One or more `track_selection` blocks as defined below. --- A `presentation_time_range` block supports the following: -* `end_timestamp` - (Optional) The absolute end time boundary. +* `end_timescale` - (Optional) The absolute end time boundary. Applies to Video on Demand (VoD). +For the Live Streaming presentation, it is silently ignored and applied when the presentation ends and the stream becomes VoD. This is a long value that represents an absolute end point of the presentation, rounded to the closest next GOP start. The unit is the timescale, so an `end_timescale` of 1800000000 would be for 3 minutes. Use `start_timescale` and `end_timescale` to trim the fragments that will be in the playlist (manifest). For example, `start_timescale` set to 40000000 and `end_timescale` set to 100000000 using the default `timescale_increment_in_seconds` will generate a playlist that contains fragments from between 4 seconds and 10 seconds of the VoD presentation. If a fragment straddles the boundary, the entire fragment will be included in the manifest. -* `force_end_timestamp` - (Optional) The indicator of forcing existing of end time stamp. +* `force_end_timescale` - (Optional) Indicates whether the `end_timescale` property must be present. If true, `end_timescale` must be specified or a bad request code is returned. Applies to Live Streaming only.Allowed values: false, true. -* `live_backoff_duration` - (Optional) The relative to end right edge. +* `live_backoff_in_timescale` - (Optional) The relative to end right edge. Applies to Live Streaming only. +This value defines the latest live position that a client can seek to. Using this property, you can delay live playback position and create a server-side buffer for players. The unit for this property is timescale. The maximum live back off duration is 300 seconds (3000000000). For example, a value of 2000000000 means that the latest available content is 20 seconds delayed from the real live edge. -* `presentation_window_duration` - (Optional) The relative to end sliding window. +* `presentation_window_in_timescale` - (Optional) The relative to end sliding window. Applies to Live Streaming only. Use `presentation_window_in_timescale` to apply a sliding window of fragments to include in a playlist. The unit for this property is timescale. For example, set `presentation_window_in_timescale` to 1200000000 to apply a two-minute sliding window. Media within 2 minutes of the live edge will be included in the playlist. If a fragment straddles the boundary, the entire fragment will be included in the playlist. The minimum presentation window duration is 60 seconds. -* `start_timestamp` - (Optional) The absolute start time boundary. +* `start_timescale` - (Optional) The absolute start time boundary. Applies to Video on Demand (VoD) or Live Streaming. This is a long value that represents an absolute start point of the stream. The value gets rounded to the closest next GOP start. The unit is the timescale, so a `start_timescale` of 150000000 would be for 15 seconds. Use `start_timescale` and `end_timescale` to trim the fragments that will be in the playlist (manifest). For example, `start_timescale` set to 40000000 and `end_timescale` set to 100000000 using the default `timescale_increment_in_seconds` will generate a playlist that contains fragments from between 4 seconds and 10 seconds of the VoD presentation. If a fragment straddles the boundary, the entire fragment will be included in the manifest. -* `timescale` - (Optional) The time scale of time stamps. +* `timescale_increment_in_seconds` - (Optional) Specified as the number of increments in one second. +Default is 10000000 - ten million increments in one second, where each increment would be 100 nanoseconds long. For example, if you want to set a `start_timescale` at 30 seconds, you would use a value of 300000000 when using the default timescale. Applies timescale to `end_timescale`, `start_timescale` +and `presentation_window_in_timescale` and `live_backoff_in_timescale`. --- A `selection` block supports the following: -* `operation` - (Optional) The track property condition operation. Supported values are `Equal` and `NotEqual`. +* `operation` - (Optional) The condition operation to test a track property against. Supported values are `Equal` and `NotEqual`. -* `property` - (Optional) The track property type. Supported values are `Bitrate`, `FourCC`, `Language`, `Name` and `Type`. +* `property` - (Optional) The track property to compare. Supported values are `Bitrate`, `FourCC`, `Language`, `Name` and `Type`. Check [documentation](https://docs.microsoft.com/en-us/azure/media-services/latest/filters-concept) for more details. -* `value` - (Optional) The track property value. +* `value` - (Optional) The track property value to match or not match. --- -A `track` block supports the following: +A `track_selection` block supports the following: -* `selection` - (Optional) One or more `selection` blocks as defined above. +* `condition` - (Optional) One or more `condition` blocks as defined above. ## Attributes Reference From bcbbd78a805e767c8e0f9ce965dc1df8962a45b0 Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Thu, 8 Apr 2021 12:13:38 -0600 Subject: [PATCH 7/8] Fix linting issues --- .../media/media_asset_filter_resource_test.go | 14 +++++++------- website/docs/r/media_asset_filter.html.markdown | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/azurerm/internal/services/media/media_asset_filter_resource_test.go b/azurerm/internal/services/media/media_asset_filter_resource_test.go index 954c817214d4..57551f30a97e 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource_test.go +++ b/azurerm/internal/services/media/media_asset_filter_resource_test.go @@ -109,8 +109,8 @@ func (r AssetFilterResource) basic(data acceptance.TestData) string { %s resource "azurerm_media_asset_filter" "test" { - name = "Filter-1" - asset_id = azurerm_media_asset.test.id + name = "Filter-1" + asset_id = azurerm_media_asset.test.id } `, r.template(data)) @@ -121,8 +121,8 @@ func (r AssetFilterResource) requiresImport(data acceptance.TestData) string { %s resource "azurerm_media_asset_filter" "import" { - name = azurerm_media_asset_filter.test.name - asset_id = azurerm_media_asset.test.id + name = azurerm_media_asset_filter.test.name + asset_id = azurerm_media_asset.test.id } `, r.basic(data)) @@ -133,9 +133,9 @@ func (r AssetFilterResource) complete(data acceptance.TestData) string { %s resource "azurerm_media_asset_filter" "test" { - name = "Filter-1" - asset_id = azurerm_media_asset.test.id - first_quality_bitrate = 128000 + name = "Filter-1" + asset_id = azurerm_media_asset.test.id + first_quality_bitrate = 128000 presentation_time_range { start_timescale = 0 diff --git a/website/docs/r/media_asset_filter.html.markdown b/website/docs/r/media_asset_filter.html.markdown index b60366785841..ad7ecee984a6 100644 --- a/website/docs/r/media_asset_filter.html.markdown +++ b/website/docs/r/media_asset_filter.html.markdown @@ -45,17 +45,17 @@ resource "azurerm_media_asset" "example" { } resource "azurerm_media_asset_filter" "example" { - name = "Filter1" - asset_id = azurerm_media_asset.example.id - first_quality_bitrate = 128000 + name = "Filter1" + asset_id = azurerm_media_asset.example.id + first_quality_bitrate = 128000 presentation_time_range { - start_timescale = 0 - end_timescale = 170000000 + start_timescale = 0 + end_timescale = 170000000 presentation_window_in_timescale = 9223372036854775000 live_backoff_in_timescale = 0 - timescale_increment_in_seconds = 10000000 - force_end_timescale = false + timescale_increment_in_seconds = 10000000 + force_end_timescale = false } track_selection { From 0f9173a12ab98eb2121191e8a727a28960333489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CJavier?= Date: Wed, 28 Apr 2021 21:08:33 -0600 Subject: [PATCH 8/8] Improve presentation_time_range attribute --- .../media/media_asset_filter_resource.go | 78 +++++++++++-------- .../media/media_asset_filter_resource_test.go | 12 +-- .../docs/r/media_asset_filter.html.markdown | 30 ++++--- 3 files changed, 64 insertions(+), 56 deletions(-) diff --git a/azurerm/internal/services/media/media_asset_filter_resource.go b/azurerm/internal/services/media/media_asset_filter_resource.go index e844abba53d6..82a3c1d05b5f 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource.go +++ b/azurerm/internal/services/media/media_asset_filter_resource.go @@ -18,6 +18,11 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) +// define constants based on docs https://docs.microsoft.com/en-us/azure/media-services/latest/filters-concept +const incrementsInASecond = 10000000 +const nanoSecondsInAIncrement = 100 +const milliSecondsInASecond = 1000 + func resourceMediaAssetFilter() *schema.Resource { return &schema.Resource{ Create: resourceMediaAssetFilterCreateUpdate, @@ -67,39 +72,39 @@ func resourceMediaAssetFilter() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "end_timescale": { + "end_in_units": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), }, - "force_end_timescale": { + "force_end": { Type: schema.TypeBool, Optional: true, }, - "live_backoff_in_timescale": { + "live_backoff_in_units": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), }, - "presentation_window_in_timescale": { + "presentation_window_in_units": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), }, - "start_timescale": { + "start_in_units": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntAtLeast(0), }, - "timescale_increment_in_seconds": { + "unit_timescale_in_miliseconds": { Type: schema.TypeInt, Optional: true, - ValidateFunc: validation.IntAtLeast(0), + ValidateFunc: validation.IntAtLeast(1), }, }, }, @@ -271,28 +276,31 @@ func expandPresentationTimeRange(input []interface{}) *media.PresentationTimeRan timeRange := input[0].(map[string]interface{}) presentationTimeRange := &media.PresentationTimeRange{} - if v := timeRange["end_timescale"]; v != nil { - presentationTimeRange.EndTimestamp = utils.Int64(int64(v.(int))) + var baseUnit int64 + if v := timeRange["unit_timescale_in_miliseconds"]; v != nil { + timeScaleInMiliSeconds := int64(v.(int)) + presentationTimeRange.Timescale = utils.Int64((incrementsInASecond * nanoSecondsInAIncrement) / milliSecondsInASecond / timeScaleInMiliSeconds) + baseUnit = milliSecondsInASecond } - if v := timeRange["force_end_timescale"]; v != nil { - presentationTimeRange.ForceEndTimestamp = utils.Bool(v.(bool)) + if v := timeRange["end_in_units"]; v != nil { + presentationTimeRange.EndTimestamp = utils.Int64(int64(v.(int)) * baseUnit) } - if v := timeRange["live_backoff_in_timescale"]; v != nil { - presentationTimeRange.LiveBackoffDuration = utils.Int64(int64(v.(int))) + if v := timeRange["force_end"]; v != nil { + presentationTimeRange.ForceEndTimestamp = utils.Bool(v.(bool)) } - if v := timeRange["presentation_window_in_timescale"]; v != nil { - presentationTimeRange.PresentationWindowDuration = utils.Int64(int64(v.(int))) + if v := timeRange["live_backoff_in_units"]; v != nil { + presentationTimeRange.LiveBackoffDuration = utils.Int64(int64(v.(int)) * baseUnit) } - if v := timeRange["start_timescale"]; v != nil { - presentationTimeRange.StartTimestamp = utils.Int64(int64(v.(int))) + if v := timeRange["presentation_window_in_units"]; v != nil { + presentationTimeRange.PresentationWindowDuration = utils.Int64(int64(v.(int)) * baseUnit) } - if v := timeRange["timescale_increment_in_seconds"]; v != nil { - presentationTimeRange.Timescale = utils.Int64(int64(v.(int))) + if v := timeRange["start_in_units"]; v != nil { + presentationTimeRange.StartTimestamp = utils.Int64(int64(v.(int)) * baseUnit) } return presentationTimeRange @@ -303,9 +311,16 @@ func flattenPresentationTimeRange(input *media.PresentationTimeRange) []interfac return make([]interface{}, 0) } + var timeScale int64 + var baseUnit int64 + if input.Timescale != nil { + timeScale = (incrementsInASecond * nanoSecondsInAIncrement) / milliSecondsInASecond / *input.Timescale + baseUnit = milliSecondsInASecond + } + var endTimestamp int64 if input.EndTimestamp != nil { - endTimestamp = *input.EndTimestamp + endTimestamp = *input.EndTimestamp / baseUnit } var forceEndTimestamp bool @@ -315,32 +330,27 @@ func flattenPresentationTimeRange(input *media.PresentationTimeRange) []interfac var liveBackoffDuration int64 if input.LiveBackoffDuration != nil { - liveBackoffDuration = *input.LiveBackoffDuration + liveBackoffDuration = *input.LiveBackoffDuration / baseUnit } var presentationWindowDuration int64 if input.PresentationWindowDuration != nil { - presentationWindowDuration = *input.PresentationWindowDuration + presentationWindowDuration = *input.PresentationWindowDuration / baseUnit } var startTimestamp int64 if input.StartTimestamp != nil { - startTimestamp = *input.StartTimestamp - } - - var timeScale int64 - if input.Timescale != nil { - timeScale = *input.Timescale + startTimestamp = *input.StartTimestamp / baseUnit } return []interface{}{ map[string]interface{}{ - "end_timescale": endTimestamp, - "force_end_timescale": forceEndTimestamp, - "live_backoff_in_timescale": liveBackoffDuration, - "presentation_window_in_timescale": presentationWindowDuration, - "start_timescale": startTimestamp, - "timescale_increment_in_seconds": timeScale, + "end_in_units": endTimestamp, + "force_end": forceEndTimestamp, + "live_backoff_in_units": liveBackoffDuration, + "presentation_window_in_units": presentationWindowDuration, + "start_in_units": startTimestamp, + "unit_timescale_in_miliseconds": timeScale, }, } } diff --git a/azurerm/internal/services/media/media_asset_filter_resource_test.go b/azurerm/internal/services/media/media_asset_filter_resource_test.go index 57551f30a97e..92e8e1a9e7e7 100644 --- a/azurerm/internal/services/media/media_asset_filter_resource_test.go +++ b/azurerm/internal/services/media/media_asset_filter_resource_test.go @@ -138,12 +138,12 @@ resource "azurerm_media_asset_filter" "test" { first_quality_bitrate = 128000 presentation_time_range { - start_timescale = 0 - end_timescale = 170000000 - presentation_window_in_timescale = 9223372036854775000 - live_backoff_in_timescale = 0 - timescale_increment_in_seconds = 10000000 - force_end_timescale = false + start_in_units = 0 + end_in_units = 15 + presentation_window_in_units = 90 + live_backoff_in_units = 0 + unit_timescale_in_miliseconds = 1000 + force_end = false } track_selection { diff --git a/website/docs/r/media_asset_filter.html.markdown b/website/docs/r/media_asset_filter.html.markdown index ad7ecee984a6..a85fadc4ef97 100644 --- a/website/docs/r/media_asset_filter.html.markdown +++ b/website/docs/r/media_asset_filter.html.markdown @@ -50,12 +50,12 @@ resource "azurerm_media_asset_filter" "example" { first_quality_bitrate = 128000 presentation_time_range { - start_timescale = 0 - end_timescale = 170000000 - presentation_window_in_timescale = 9223372036854775000 - live_backoff_in_timescale = 0 - timescale_increment_in_seconds = 10000000 - force_end_timescale = false + start_in_units = 0 + end_in_units = 15 + presentation_window_in_units = 90 + live_backoff_in_units = 0 + unit_timescale_in_miliseconds = 1000 + force_end = false } track_selection { @@ -115,21 +115,19 @@ The following arguments are supported: A `presentation_time_range` block supports the following: -* `end_timescale` - (Optional) The absolute end time boundary. Applies to Video on Demand (VoD). -For the Live Streaming presentation, it is silently ignored and applied when the presentation ends and the stream becomes VoD. This is a long value that represents an absolute end point of the presentation, rounded to the closest next GOP start. The unit is the timescale, so an `end_timescale` of 1800000000 would be for 3 minutes. Use `start_timescale` and `end_timescale` to trim the fragments that will be in the playlist (manifest). For example, `start_timescale` set to 40000000 and `end_timescale` set to 100000000 using the default `timescale_increment_in_seconds` will generate a playlist that contains fragments from between 4 seconds and 10 seconds of the VoD presentation. If a fragment straddles the boundary, the entire fragment will be included in the manifest. +* `end_in_units` - (Optional) The absolute end time boundary. Applies to Video on Demand (VoD). +For the Live Streaming presentation, it is silently ignored and applied when the presentation ends and the stream becomes VoD. This is a long value that represents an absolute end point of the presentation, rounded to the closest next GOP start. The unit is defined by `unit_timescale_in_miliseconds`, so an `end_in_units` of 180 would be for 3 minutes. Use `start_in_units` and `end_in_units` to trim the fragments that will be in the playlist (manifest). For example, `start_in_units` set to 20 and `end_in_units` set to 60 using `unit_timescale_in_miliseconds` in 1000 will generate a playlist that contains fragments from between 20 seconds and 60 seconds of the VoD presentation. If a fragment straddles the boundary, the entire fragment will be included in the manifest. -* `force_end_timescale` - (Optional) Indicates whether the `end_timescale` property must be present. If true, `end_timescale` must be specified or a bad request code is returned. Applies to Live Streaming only.Allowed values: false, true. +* `force_end` - (Optional) Indicates whether the `end_in_units` property must be present. If true, `end_in_units` must be specified or a bad request code is returned. Applies to Live Streaming only. Allowed values: false, true. -* `live_backoff_in_timescale` - (Optional) The relative to end right edge. Applies to Live Streaming only. -This value defines the latest live position that a client can seek to. Using this property, you can delay live playback position and create a server-side buffer for players. The unit for this property is timescale. The maximum live back off duration is 300 seconds (3000000000). For example, a value of 2000000000 means that the latest available content is 20 seconds delayed from the real live edge. +* `live_backoff_in_units` - (Optional) The relative to end right edge. Applies to Live Streaming only. +This value defines the latest live position that a client can seek to. Using this property, you can delay live playback position and create a server-side buffer for players. The unit is defined by `unit_timescale_in_miliseconds`. The maximum live back off duration is 300 seconds. For example, a value of 20 means that the latest available content is 20 seconds delayed from the real live edge. -* `presentation_window_in_timescale` - (Optional) The relative to end sliding window. Applies to Live Streaming only. Use `presentation_window_in_timescale` to apply a sliding window of fragments to include in a playlist. The unit for this property is timescale. For example, set `presentation_window_in_timescale` to 1200000000 to apply a two-minute sliding window. Media within 2 minutes of the live edge will be included in the playlist. If a fragment straddles the boundary, the entire fragment will be included in the playlist. The minimum presentation window duration is 60 seconds. +* `presentation_window_in_units` - (Optional) The relative to end sliding window. Applies to Live Streaming only. Use `presentation_window_in_units` to apply a sliding window of fragments to include in a playlist. The unit is defined by `unit_timescale_in_miliseconds`. For example, set `presentation_window_in_units` to 120 to apply a two-minute sliding window. Media within 2 minutes of the live edge will be included in the playlist. If a fragment straddles the boundary, the entire fragment will be included in the playlist. The minimum presentation window duration is 60 seconds. -* `start_timescale` - (Optional) The absolute start time boundary. Applies to Video on Demand (VoD) or Live Streaming. This is a long value that represents an absolute start point of the stream. The value gets rounded to the closest next GOP start. The unit is the timescale, so a `start_timescale` of 150000000 would be for 15 seconds. Use `start_timescale` and `end_timescale` to trim the fragments that will be in the playlist (manifest). For example, `start_timescale` set to 40000000 and `end_timescale` set to 100000000 using the default `timescale_increment_in_seconds` will generate a playlist that contains fragments from between 4 seconds and 10 seconds of the VoD presentation. If a fragment straddles the boundary, the entire fragment will be included in the manifest. +* `start_in_units` - (Optional) The absolute start time boundary. Applies to Video on Demand (VoD) or Live Streaming. This is a long value that represents an absolute start point of the stream. The value gets rounded to the closest next GOP start. The unit is defined by `unit_timescale_in_miliseconds`, so a `start_in_units` of 15 would be for 15 seconds. Use `start_in_units` and `end_in_units` to trim the fragments that will be in the playlist (manifest). For example, `start_in_units` set to 20 and `end_in_units` set to 60 using `unit_timescale_in_miliseconds` in 1000 will generate a playlist that contains fragments from between 20 seconds and 60 seconds of the VoD presentation. If a fragment straddles the boundary, the entire fragment will be included in the manifest. -* `timescale_increment_in_seconds` - (Optional) Specified as the number of increments in one second. -Default is 10000000 - ten million increments in one second, where each increment would be 100 nanoseconds long. For example, if you want to set a `start_timescale` at 30 seconds, you would use a value of 300000000 when using the default timescale. Applies timescale to `end_timescale`, `start_timescale` -and `presentation_window_in_timescale` and `live_backoff_in_timescale`. +* `unit_timescale_in_miliseconds` - (Optional) Specified as the number of miliseconds in one unit timescale. For example, if you want to set a `start_in_units` at 30 seconds, you would use a value of 30 when using the `unit_timescale_in_miliseconds` in 1000. Or if you want to set `start_in_units` in 30 miliseconds, you would use a value of 30 when using the `unit_timescale_in_miliseconds` in 1. Applies timescale to `start_in_units`, `start_timescale` and `presentation_window_in_timescale` and `live_backoff_in_timescale`. ---