Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

azurerm_windows_function_app, azurerm_linux_function_app - fix content share not being created automatically issue #18258

Merged
merged 19 commits into from
Mar 15, 2023

Conversation

xiaxyi
Copy link
Contributor

@xiaxyi xiaxyi commented Sep 6, 2022

Fix content share not being created automatically if WEBSITE_CONTENTOVERVNET sets to 1.

According to the official guidance, "There are scenarios where you must set the WEBSITE_CONTENTSHARE value to a predefined share, such as when you use a secured storage account in a virtual network. In this case, you must set a unique share name for the main function app and the app for each deployment slot."
If the property WEBSITE_CONTENTOVERVNET set to 1 in app_setting while the users don't specify or specify a non-existed storage file share, they get the error message:

reading logs configuration for Windows Function App: (Site Name "xxx" / Resource Group "xxx"): web.AppsClient#GetDiagnosticLogsConfiguration: Failure responding to request: StatusCode=503 -- Original Error: autorest/azure: Service returned an error. Status=503 Code="ServiceUnavailable" Message="The operation timed out and could not be completed. Please retry the action or try again later." Details=[{"Message":"The operation timed out and could not be completed. Please retry the action or try again later."},{"Code":"ServiceUnavailable"},{"ErrorEntity":{"Code":"ServiceUnavailable","ExtendedCode":"51007","Message":"The operation timed out and could not be completed. Please retry the action or try again later.","MessageTemplate":"The operation timed out and could not be completed. Please retry the action or try again later."}}]
│

fix #17254
fix #14167
fix #19134

@xiaxyi xiaxyi changed the title fix contentshare property for function apps azurerm_windows_function_app, azurerm_linux_function_app: fix content share not being created automatically issue Sep 6, 2022
Copy link
Member

@jackofallops jackofallops left a comment

Choose a reason for hiding this comment

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

Hi @xiaxyi - Thanks for this PR.

I've left some comments inline below that will need to be addressed before we can continue review. I think this PR should probably have been split into smaller specific PRs to address the disparate concerns as the changes do not fully match the description / title, which makes the changes difficult to review and will unfortunately slow the process. That said, if you can make the changes here we can get this moving.

Thanks!

@@ -137,7 +137,7 @@ func PlanTypeFromSku(input string) string {
}

// ServicePlanInfoForApp returns the OS type and Service Plan SKU for a given App Service Resource
func ServicePlanInfoForApp(ctx context.Context, metadata sdk.ResourceMetaData, id interface{}) (osType *string, planSku *string, err error) {
func ServicePlanInfoForApp(ctx context.Context, metadata sdk.ResourceMetaData, id interface{}, serviceFarmId string) (osType *string, planSku *string, err error) {
Copy link
Member

Choose a reason for hiding this comment

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

This function is intended to retrieve the Service Plan ID from the App ID, it should not take the ID directly to circumvent this.

Comment on lines 770 to 777
// Some service plan updates are allowed - see customiseDiff for exceptions
var serviceFarmId string
if metadata.ResourceData.HasChange("service_plan_id") {
serviceFarmId = state.ServicePlanId
existing.SiteProperties.ServerFarmID = utils.String(serviceFarmId)
}

_, planSKU, err := helpers.ServicePlanInfoForApp(ctx, metadata, *id, serviceFarmId)
Copy link
Member

Choose a reason for hiding this comment

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

This should be a call to the new service plan to get the SKU, and not repurpose the helper function.

Comment on lines 576 to 612
var storageAccountName, storageFileShare string
if sendContentSettings || helpers.PlanIsConsumption(planSku) {
if appSettingsResp.Properties != nil {
if appSettingsResp.Properties["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] != nil {
saConnectionString := strings.Split(*appSettingsResp.Properties["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"], ";")
for _, part := range saConnectionString {
if strings.Contains(part, "AccountName") {
storageAccountName = strings.TrimPrefix(part, "AccountName=")
break
}
}
}
if appSettingsResp.Properties["WEBSITE_CONTENTSHARE"] != nil {
storageFileShare = *appSettingsResp.Properties["WEBSITE_CONTENTSHARE"]
}
saClient := metadata.Client.Storage
account, err := saClient.FindAccount(ctx, storageAccountName)
if err != nil {
return fmt.Errorf("retrieving Account %q for Share %q: %s", storageAccountName, storageFileShare, err)
}
if account == nil {
return fmt.Errorf("unable to locate Storage Account %s", storageAccountName)
}
saFileShareClient, err := metadata.Client.Storage.FileSharesClient(ctx, *account)
if err != nil {
return fmt.Errorf("building File Share Client: %s", err)
}
exists, err := saFileShareClient.Exists(ctx, account.ResourceGroup, storageAccountName, storageFileShare)
if err != nil {
return fmt.Errorf("checking for existence of Storage Share %q (Account %q) : %+v", storageFileShare, storageAccountName, err)
}
if exists == nil {
return fmt.Errorf("the storage file share %s for function app %s does not exists, please specify an existing one", storageFileShare, id.ID())
}
}
}

Copy link
Member

Choose a reason for hiding this comment

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

As above, this shouldn't be in the Read.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the review, this is to address the timeout issue. if the user doesn't specify a predefined file share and also set the WEBSITE_CONTENTOVERVNET in the app_setting, the provider will timeout by trying to access a non-existence file share. I can add the 4.0 condition to this check block.

Copy link
Contributor

Choose a reason for hiding this comment

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

agreed - this shouldn't be in the Read function - we don't retrieve the file share in the Read, so this is unnecessary

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @tombuildsstuff for the comments. If we don't check the storage file share, shall we just let the read function timeout?

Copy link
Contributor

@tombuildsstuff tombuildsstuff Oct 21, 2022

Choose a reason for hiding this comment

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

@xiaxyi why will the read function timeout? it's calling the App Service ARM API and not interacting with the Storage Account in the read function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The function app is trying to connect to the file share specified in the [WEBSITE_CONTENTSHARE](https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings), Generally, the file share is created by function app automatically, however, the it cannot be created if user specify the key WEBSITE_CONTENTOVERVNET in app_setting, it requires the user to create a valid file share in advance and put the value in WEBSITE_CONTENTSHARE`. We didn't add such notes to user in the current provider, so the function(Read function) times out.

If we don't check the file share in read function, then what's left is to add notes in docs and let the read function timeout.

Comment on lines 769 to 775
var serviceFarmId string
if metadata.ResourceData.HasChange("service_plan_id") {
serviceFarmId = state.ServicePlanId
existing.SiteProperties.ServerFarmID = utils.String(serviceFarmId)
}

_, planSKU, err := helpers.ServicePlanInfoForApp(ctx, metadata, *id, serviceFarmId)
Copy link
Member

Choose a reason for hiding this comment

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

As above, the helper should not be repurposed, and the SKU should be read from the new service plan ID. A new helper for that would be acceptable.

@xiaxyi
Copy link
Contributor Author

xiaxyi commented Oct 20, 2022

Hi @xiaxyi - Thanks for this PR.

I've left some comments inline below that will need to be addressed before we can continue review. I think this PR should probably have been split into smaller specific PRs to address the disparate concerns as the changes do not fully match the description / title, which makes the changes difficult to review and will unfortunately slow the process. That said, if you can make the changes here we can get this moving.

Thanks!

Thanks @jackofallops for the feedbacks. All the code changes in this pr is tend to resolve one issue which is the content share issue under elastic plan.

As I mentioned in the description, if user sets WEBSITE_CONTENTOVERVNET without specifying a predefined storage file share, there will be error accessing that share.

The file share check in read function is to ensure the predefined file share exists, otherwise, we throw error instead of waiting for the read function to time out.

The service plan check is to determine whether the function is elastic plan.

@github-actions github-actions bot added the size/L label Nov 9, 2022
@xiaxyi
Copy link
Contributor Author

xiaxyi commented Nov 9, 2022

@jackofallops @tombuildsstuff , updated th read function, removed the storage file share check.

@xiaxyi xiaxyi changed the title azurerm_windows_function_app, azurerm_linux_function_app: fix content share not being created automatically issue azurerm_windows_function_app, azurerm_linux_function_app - fix content share not being created automatically issue Nov 11, 2022
@github-actions github-actions bot added size/M and removed size/XL labels Mar 7, 2023
Copy link
Member

@jackofallops jackofallops left a comment

Choose a reason for hiding this comment

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

Hi @xiaxyi - apologies for the long overdue re-review on this. I hope you don't mind, but I pushed some changes to simplify the updates and remove the need for re-processing some data. Could you look to add a test to cover the case being addressed here, and I think we'll be good to merge once that's in and passing.

Thanks

@xiaxyi
Copy link
Contributor Author

xiaxyi commented Mar 10, 2023

Thanks @jackofallops for the update, I updated the code and added the test cases for both linux and windows.

feel free to let me know if there is anything else needed.

Copy link
Member

@jackofallops jackofallops left a comment

Choose a reason for hiding this comment

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

Hi @xiaxyi
Thanks for adding the tests. I've re-pushed the changes that were lost during the merge main. The ignores in the test suggest this needs some more work, possibly in the functions I've called out in line below if you can take a look?

Thanks!

@xiaxyi
Copy link
Contributor Author

xiaxyi commented Mar 15, 2023

Thanks @jackofallops for the comments, I applied your change and pushed again, apologize for my mistakes last time.

Regarding the acc test import steps, I think we still need to keep the ignore step for those app setting:

"app_settings.WEBSITE_CONTENTSHARE", "app_settings.WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", "app_settings.%"

As I mentioned in my previous comments, service will try to add the WEBSITE_CONTENTSHARE and WEBSITE_CONTENTAZUREFILECONNECTIONSTRING for the function app instance (in elastic or consumption plan) automatically if no WEBSITE_CONTENTOVERVNET is added by user, which means, we need to determine whether to set those kvp back to state by checking the user's TF config and that's why we need to ignore the changes when doing the import. So I'm not going to change the original unpackappsetting function:https://github.com/hashicorp/terraform-provider-azurerm/blob/main/internal/services/appservice/linux_function_app_resource.go#L1090

@jackofallops
Copy link
Member

Thanks @jackofallops for the comments, I applied your change and pushed again, apologize for my mistakes last time.

Regarding the acc test import steps, I think we still need to keep the ignore step for those app setting:

"app_settings.WEBSITE_CONTENTSHARE", "app_settings.WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", "app_settings.%"

As I mentioned in my previous comments, service will try to add the WEBSITE_CONTENTSHARE and WEBSITE_CONTENTAZUREFILECONNECTIONSTRING for the function app instance (in elastic or consumption plan) automatically if no WEBSITE_CONTENTOVERVNET is added by user, which means, we need to determine whether to set those kvp back to state by checking the user's TF config and that's why we need to ignore the changes when doing the import. So I'm not going to change the original unpackappsetting function:main/internal/services/appservice/linux_function_app_resource.go#L1090

Hi @xiaxyi - Apologies, you are correct. These should be ignored on Import as the service does not manage them if absent. I'll message you offline to discuss.

@jackofallops
Copy link
Member

Tests look good

image

Copy link
Member

@jackofallops jackofallops left a comment

Choose a reason for hiding this comment

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

Thanks @xiaxyi for the updates and patience. This LGTM now 👍

@jackofallops jackofallops merged commit 60264b8 into hashicorp:main Mar 15, 2023
@github-actions github-actions bot added this to the v3.48.0 milestone Mar 15, 2023
jackofallops added a commit that referenced this pull request Mar 15, 2023
@github-actions
Copy link

This functionality has been released in v3.48.0 of the Terraform Provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template. Thank you!

@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.