From a154b0ca531b08d73dc976ba8cfea4641c068001 Mon Sep 17 00:00:00 2001 From: Domenico Di Ruocco Date: Fri, 21 Jun 2024 11:09:15 +0200 Subject: [PATCH] fix: flickering values in channel resource OTT-6126 --- awsmt/data_source_channel.go | 2 +- awsmt/helpers_channels.go | 234 +++++++++++++++++---------------- awsmt/resource_channel.go | 12 +- awsmt/resource_channel_test.go | 2 +- 4 files changed, 131 insertions(+), 119 deletions(-) diff --git a/awsmt/data_source_channel.go b/awsmt/data_source_channel.go index 1bfae9d..f703f8c 100644 --- a/awsmt/data_source_channel.go +++ b/awsmt/data_source_channel.go @@ -122,7 +122,7 @@ func (d *dataSourceChannel) Read(ctx context.Context, req datasource.ReadRequest data.ChannelState = channel.ChannelState } - data = readChannelToState(data, *channel) + data = writeChannelToState(data, *channel) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } diff --git a/awsmt/helpers_channels.go b/awsmt/helpers_channels.go index 571dee3..a6c2786 100644 --- a/awsmt/helpers_channels.go +++ b/awsmt/helpers_channels.go @@ -9,16 +9,62 @@ import ( "time" ) -// CHANNEL +// Functions used to edit the channel once created + +func createChannelPolicy(channelName *string, policy *string, client *mediatailor.MediaTailor) error { + putChannelPolicyParams := mediatailor.PutChannelPolicyInput{ + ChannelName: channelName, + Policy: policy, + } + _, err := client.PutChannelPolicy(&putChannelPolicyParams) + if err != nil { + return err + } + return err +} + +func stopChannel(state *string, channelName *string, client *mediatailor.MediaTailor) error { + if *state == "RUNNING" { + _, err := client.StopChannel(&mediatailor.StopChannelInput{ChannelName: channelName}) + if err != nil { + return err + } + } + return nil +} + +func updatePolicy(plan *channelModel, channelName *string, oldPolicy jsontypes.Normalized, newPolicy jsontypes.Normalized, client *mediatailor.MediaTailor) (channelModel, error) { + if !reflect.DeepEqual(oldPolicy, newPolicy) { + if !newPolicy.IsNull() { + plan.Policy = newPolicy + policy := newPolicy.ValueString() + _, err := client.PutChannelPolicy(&mediatailor.PutChannelPolicyInput{ChannelName: channelName, Policy: &policy}) + if err != nil { + return *plan, err + } + } else if newPolicy.IsNull() { + plan.Policy = jsontypes.NewNormalizedNull() + _, err := client.DeleteChannelPolicy(&mediatailor.DeleteChannelPolicyInput{ChannelName: channelName}) + if err != nil { + return *plan, err + } + } + } else { + plan.Policy = oldPolicy + } + return *plan, nil +} + +// Functions used to create the resource in MediaTailor func newChannelInputBuilder(channelName *string, outputs []outputsModel, fillerSlate *fillerSlateModel) (*string, []*mediatailor.RequestOutputItem, *mediatailor.SlateSource) { theChannelName := channelName - output := getOutputsFromPlan(outputs) - fillerSlates := getFillerSlateFromPlan(fillerSlate) + output := buildRequestOutput(outputs) + fillerSlates := buildSlateSource(fillerSlate) return theChannelName, output, fillerSlates } -func channelInput(plan channelModel) mediatailor.CreateChannelInput { +func buildChannelInput(plan channelModel) mediatailor.CreateChannelInput { var input mediatailor.CreateChannelInput input.ChannelName, input.Outputs, input.FillerSlate = newChannelInputBuilder(plan.Name, plan.Outputs, plan.FillerSlate) @@ -37,81 +83,41 @@ func channelInput(plan channelModel) mediatailor.CreateChannelInput { return input } -func readChannelToPlan(plan channelModel, channel mediatailor.CreateChannelOutput) channelModel { - - plan = readChannelComputedValuesToPlan(plan, channel.Arn, channel.ChannelName, channel.CreationTime, channel.LastModifiedTime) - - plan = readFillerSlateToPlan(plan, channel.FillerSlate) - - plan = readOutputsToPlan(plan, channel.Outputs) - - plan = readOptionalValuesToPlan(plan, channel.PlaybackMode, channel.Tags, channel.Tier) - - return plan -} - -func readChannelToState(state channelModel, channel mediatailor.DescribeChannelOutput) channelModel { - - state = readChannelComputedValuesToPlan(state, channel.Arn, channel.ChannelName, channel.CreationTime, channel.LastModifiedTime) - - state = readFillerSlateToPlan(state, channel.FillerSlate) - - state = readOutputsToPlan(state, channel.Outputs) - - state = readOptionalValuesToPlan(state, channel.PlaybackMode, channel.Tags, channel.Tier) - - return state -} - -// POLICY -func createChannelPolicy(channelName *string, policy *string, client *mediatailor.MediaTailor) error { - putChannelPolicyParams := mediatailor.PutChannelPolicyInput{ - ChannelName: channelName, - Policy: policy, - } - _, err := client.PutChannelPolicy(&putChannelPolicyParams) - if err != nil { - return err - } - return err -} - -// UPDATE CHANNEL -func getUpdateChannelInput(plan channelModel) mediatailor.UpdateChannelInput { +func buildUpdateChannelInput(plan channelModel) mediatailor.UpdateChannelInput { var input mediatailor.UpdateChannelInput input.ChannelName, input.Outputs, input.FillerSlate = newChannelInputBuilder(plan.Name, plan.Outputs, plan.FillerSlate) return input } -// GET OUTPUTS FROM PLAN -func getOutputsFromPlan(outputsFromPlan []outputsModel) []*mediatailor.RequestOutputItem { - var outputFromPlan []*mediatailor.RequestOutputItem +func buildRequestOutput(outputsFromPlan []outputsModel) []*mediatailor.RequestOutputItem { + var res []*mediatailor.RequestOutputItem for _, output := range outputsFromPlan { outputs := &mediatailor.RequestOutputItem{} if output.DashPlaylistSettings != nil { - outputs.DashPlaylistSettings = getDashPlaylistSettings(output.DashPlaylistSettings) + outputs.DashPlaylistSettings = buildDashPlaylistSettings(output.DashPlaylistSettings) } if output.HlsPlaylistSettings != nil { - outputs.HlsPlaylistSettings = getHLSPlaylistSettings(output.HlsPlaylistSettings) + outputs.HlsPlaylistSettings = buildHLSPlaylistSettings(output.HlsPlaylistSettings) } if output.ManifestName != nil { outputs.ManifestName = output.ManifestName } + if output.SourceGroup != nil { outputs.SourceGroup = output.SourceGroup } - outputFromPlan = append(outputFromPlan, outputs) + res = append(res, outputs) } - return outputFromPlan + return res } -func getDashPlaylistSettings(settings *dashPlaylistSettingsModel) *mediatailor.DashPlaylistSettings { +func buildDashPlaylistSettings(settings *dashPlaylistSettingsModel) *mediatailor.DashPlaylistSettings { dashSettings := &mediatailor.DashPlaylistSettings{} if settings.ManifestWindowSeconds != nil { dashSettings.ManifestWindowSeconds = settings.ManifestWindowSeconds @@ -129,12 +135,11 @@ func getDashPlaylistSettings(settings *dashPlaylistSettingsModel) *mediatailor.D return dashSettings } -func getHLSPlaylistSettings(settings *hlsPlaylistSettingsModel) *mediatailor.HlsPlaylistSettings { +func buildHLSPlaylistSettings(settings *hlsPlaylistSettingsModel) *mediatailor.HlsPlaylistSettings { hlsSettings := &mediatailor.HlsPlaylistSettings{} if settings.AdMarkupType != nil && len(settings.AdMarkupType) > 0 { for _, value := range settings.AdMarkupType { - temp := value - hlsSettings.AdMarkupType = append(hlsSettings.AdMarkupType, temp) + hlsSettings.AdMarkupType = append(hlsSettings.AdMarkupType, value) } } else if settings.AdMarkupType == nil { temp := "DATERANGE" @@ -146,7 +151,7 @@ func getHLSPlaylistSettings(settings *hlsPlaylistSettingsModel) *mediatailor.Hls return hlsSettings } -func getFillerSlateFromPlan(fillerSlate *fillerSlateModel) *mediatailor.SlateSource { +func buildSlateSource(fillerSlate *fillerSlateModel) *mediatailor.SlateSource { var slateSource *mediatailor.SlateSource if fillerSlate != nil { slateSource = &mediatailor.SlateSource{} @@ -160,8 +165,9 @@ func getFillerSlateFromPlan(fillerSlate *fillerSlateModel) *mediatailor.SlateSou return slateSource } -// READ COMPUTED VALUES TO PLAN -func readChannelComputedValuesToPlan(plan channelModel, arn *string, channelName *string, creationTime *time.Time, lastModifiedTime *time.Time) channelModel { +// Functions used to read MediaTailor resources to plan and state + +func readChannelComputedValues(plan channelModel, arn *string, channelName *string, creationTime *time.Time, lastModifiedTime *time.Time) channelModel { plan.ID = types.StringValue(*channelName) if arn != nil { @@ -181,8 +187,7 @@ func readChannelComputedValuesToPlan(plan channelModel, arn *string, channelName return plan } -// READ FILLER SLATE TO PLAN -func readFillerSlateToPlan(plan channelModel, channel *mediatailor.SlateSource) channelModel { +func readFillerSlate(plan channelModel, channel *mediatailor.SlateSource) channelModel { if channel != nil { plan.FillerSlate = &fillerSlateModel{} if channel.SourceLocationName != nil { @@ -195,29 +200,31 @@ func readFillerSlateToPlan(plan channelModel, channel *mediatailor.SlateSource) return plan } -// READ OUTPUTS TO PLAN -func readOutputsToPlan(plan channelModel, channel []*mediatailor.ResponseOutputItem) channelModel { - if channel != nil { - plan.Outputs = []outputsModel{} - for _, output := range channel { - outputs := outputsModel{} - if output.DashPlaylistSettings != nil { - outputs.DashPlaylistSettings = &dashPlaylistSettingsModel{} - dashPlaylistSettings := readDashPlaylistConfigurationsToPlan(output) - outputs.DashPlaylistSettings = dashPlaylistSettings +func readOutputs(plan channelModel, channel []*mediatailor.ResponseOutputItem) channelModel { - } - if output.HlsPlaylistSettings != nil { - outputs.HlsPlaylistSettings = &hlsPlaylistSettingsModel{} - hlsPlaylistSettings := readHlsPlaylistConfigurationsToPlan(output) - outputs.HlsPlaylistSettings = hlsPlaylistSettings + if channel == nil { + return plan + } + var tempOutputs []outputsModel + for i, output := range channel { + outputs := outputsModel{} + if output.DashPlaylistSettings != nil { + outputs.DashPlaylistSettings = readDashPlaylistConfigurationsToPlan(output) + } + if output.HlsPlaylistSettings != nil { + if len(plan.Outputs) > 0 && i <= len(plan.Outputs) { + outputs.HlsPlaylistSettings = readHlsPlaylistConfigurationsToPlan(output, plan.Outputs[i]) + } else { + outputs.HlsPlaylistSettings = readHlsPlaylistConfigurationsToPlanDS(output) } - outputs.ManifestName, outputs.PlaybackUrl, outputs.SourceGroup = readRMPS(output.ManifestName, output.PlaybackUrl, output.SourceGroup) - plan.Outputs = append(plan.Outputs, outputs) } + outputs.ManifestName, outputs.PlaybackUrl, outputs.SourceGroup = readRMPS(output.ManifestName, output.PlaybackUrl, output.SourceGroup) + tempOutputs = append(tempOutputs, outputs) } + plan.Outputs = tempOutputs + return plan } @@ -252,12 +259,24 @@ func readDashPlaylistConfigurationsToPlan(output *mediatailor.ResponseOutputItem return outputs } -func readHlsPlaylistConfigurationsToPlan(output *mediatailor.ResponseOutputItem) *hlsPlaylistSettingsModel { +func readHlsPlaylistConfigurationsToPlan(output *mediatailor.ResponseOutputItem, stateOutput outputsModel) *hlsPlaylistSettingsModel { + outputs := &hlsPlaylistSettingsModel{} + if stateOutput.HlsPlaylistSettings.AdMarkupType != nil && output.HlsPlaylistSettings.AdMarkupType != nil && len(output.HlsPlaylistSettings.AdMarkupType) > 0 { + for _, value := range output.HlsPlaylistSettings.AdMarkupType { + outputs.AdMarkupType = append(outputs.AdMarkupType, value) + } + } + if stateOutput.HlsPlaylistSettings.ManifestWindowSeconds != nil && output.HlsPlaylistSettings.ManifestWindowSeconds != nil { + outputs.ManifestWindowSeconds = output.HlsPlaylistSettings.ManifestWindowSeconds + } + return outputs +} + +func readHlsPlaylistConfigurationsToPlanDS(output *mediatailor.ResponseOutputItem) *hlsPlaylistSettingsModel { outputs := &hlsPlaylistSettingsModel{} if output.HlsPlaylistSettings.AdMarkupType != nil && len(output.HlsPlaylistSettings.AdMarkupType) > 0 { for _, value := range output.HlsPlaylistSettings.AdMarkupType { - temp := value - outputs.AdMarkupType = append(outputs.AdMarkupType, temp) + outputs.AdMarkupType = append(outputs.AdMarkupType, value) } } if output.HlsPlaylistSettings.ManifestWindowSeconds != nil { @@ -266,8 +285,7 @@ func readHlsPlaylistConfigurationsToPlan(output *mediatailor.ResponseOutputItem) return outputs } -// READ OPTIONAL VALUES TO PLAN -func readOptionalValuesToPlan(plan channelModel, playbackMode *string, tags map[string]*string, tier *string) channelModel { +func readOptionalValues(plan channelModel, playbackMode *string, tags map[string]*string, tier *string) channelModel { if playbackMode != nil { plan.PlaybackMode = playbackMode } @@ -282,34 +300,28 @@ func readOptionalValuesToPlan(plan channelModel, playbackMode *string, tags map[ return plan } -func stopChannel(state *string, channelName *string, client *mediatailor.MediaTailor) error { - if *state == "RUNNING" { - _, err := client.StopChannel(&mediatailor.StopChannelInput{ChannelName: channelName}) - if err != nil { - return err - } - } - return nil +func writeChannelToPlan(plan channelModel, channel mediatailor.CreateChannelOutput) channelModel { + + plan = readChannelComputedValues(plan, channel.Arn, channel.ChannelName, channel.CreationTime, channel.LastModifiedTime) + + plan = readFillerSlate(plan, channel.FillerSlate) + + plan = readOutputs(plan, channel.Outputs) + + plan = readOptionalValues(plan, channel.PlaybackMode, channel.Tags, channel.Tier) + + return plan } -func updatePolicy(plan *channelModel, channelName *string, oldPolicy jsontypes.Normalized, newPolicy jsontypes.Normalized, client *mediatailor.MediaTailor) (channelModel, error) { - if !reflect.DeepEqual(oldPolicy, newPolicy) { - if !newPolicy.IsNull() { - policy := newPolicy.ValueString() - plan.Policy = newPolicy - _, err := client.PutChannelPolicy(&mediatailor.PutChannelPolicyInput{ChannelName: channelName, Policy: &policy}) - if err != nil { - return *plan, err - } - } else if newPolicy.IsNull() { - plan.Policy = jsontypes.NewNormalizedNull() - _, err := client.DeleteChannelPolicy(&mediatailor.DeleteChannelPolicyInput{ChannelName: channelName}) - if err != nil { - return *plan, err - } - } - } else { - plan.Policy = oldPolicy - } - return *plan, nil +func writeChannelToState(state channelModel, channel mediatailor.DescribeChannelOutput) channelModel { + + state = readChannelComputedValues(state, channel.Arn, channel.ChannelName, channel.CreationTime, channel.LastModifiedTime) + + state = readFillerSlate(state, channel.FillerSlate) + + state = readOutputs(state, channel.Outputs) + + state = readOptionalValues(state, channel.PlaybackMode, channel.Tags, channel.Tier) + + return state } diff --git a/awsmt/resource_channel.go b/awsmt/resource_channel.go index 9feb0d6..3fb2197 100644 --- a/awsmt/resource_channel.go +++ b/awsmt/resource_channel.go @@ -130,7 +130,7 @@ func (r *resourceChannel) Create(ctx context.Context, req resource.CreateRequest return } - input := channelInput(plan) + input := buildChannelInput(plan) channel, err := r.client.CreateChannel(&input) if err != nil { @@ -154,9 +154,9 @@ func (r *resourceChannel) Create(ctx context.Context, req resource.CreateRequest } } - plan = readChannelToPlan(plan, *channel) + newPlan := writeChannelToPlan(plan, *channel) - diags = resp.State.Set(ctx, plan) + diags = resp.State.Set(ctx, newPlan) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -196,7 +196,7 @@ func (r *resourceChannel) Read(ctx context.Context, req resource.ReadRequest, re state.Policy = jsontypes.NewNormalizedNull() } - state = readChannelToState(state, *channel) + state = writeChannelToState(state, *channel) if state.ChannelState != nil { state.ChannelState = channel.ChannelState @@ -267,7 +267,7 @@ func (r *resourceChannel) Update(ctx context.Context, req resource.UpdateRequest ) } - var params = getUpdateChannelInput(plan) + var params = buildUpdateChannelInput(plan) updatedChannel, err := r.client.UpdateChannel(¶ms) if err != nil { resp.Diagnostics.AddError( @@ -288,7 +288,7 @@ func (r *resourceChannel) Update(ctx context.Context, req resource.UpdateRequest plan.ChannelState = newState - plan = readChannelToPlan(plan, mediatailor.CreateChannelOutput(*updatedChannel)) + plan = writeChannelToPlan(plan, mediatailor.CreateChannelOutput(*updatedChannel)) // @ADR // Context: The official AWS Mediatailor Go SDK states that the PlaybackMode is part of the UpdateChannelOutput, diff --git a/awsmt/resource_channel_test.go b/awsmt/resource_channel_test.go index 870f452..97b7121 100644 --- a/awsmt/resource_channel_test.go +++ b/awsmt/resource_channel_test.go @@ -167,7 +167,7 @@ func TestAccChannelValuesNotFlickering(t *testing.T) { Config: hlsChannelNoManifestWindowSeconds(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("awsmt_channel.test", "channel_state", "STOPPED"), - resource.TestCheckResourceAttr("data.awsmt_channel.test", "outputs.0.hls_playlist_settings.ad_markup_type", "[DATERANGE]"), + resource.TestCheckResourceAttr("data.awsmt_channel.test", "outputs.0.hls_playlist_settings.ad_markup_type.0", "DATERANGE"), ), }, },