From 3188a0086220dc64357b3b61148fa4bf2b332ee1 Mon Sep 17 00:00:00 2001 From: "madhushreeray@30" Date: Mon, 30 Oct 2023 16:32:48 +0530 Subject: [PATCH 1/4] Add table `azure_api_management_backend` --- azure/plugin.go | 1 + azure/table_azure_api_management_backend.go | 225 ++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 azure/table_azure_api_management_backend.go diff --git a/azure/plugin.go b/azure/plugin.go index 5b25c049..10859296 100644 --- a/azure/plugin.go +++ b/azure/plugin.go @@ -32,6 +32,7 @@ func Plugin(ctx context.Context) *plugin.Plugin { "azure_ad_service_principal": tableAzureAdServicePrincipal(ctx), "azure_ad_user": tableAzureAdUser(ctx), "azure_api_management": tableAzureAPIManagement(ctx), + "azure_api_management_backend": tableAzureAPIManagementBackend(ctx), "azure_app_configuration": tableAzureAppConfiguration(ctx), "azure_app_service_environment": tableAzureAppServiceEnvironment(ctx), "azure_app_service_function_app": tableAzureAppServiceFunctionApp(ctx), diff --git a/azure/table_azure_api_management_backend.go b/azure/table_azure_api_management_backend.go new file mode 100644 index 00000000..5660add2 --- /dev/null +++ b/azure/table_azure_api_management_backend.go @@ -0,0 +1,225 @@ +package azure + +import ( + "context" + "strings" + + "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2020-12-01/apimanagement" + "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" + "github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform" + + "github.com/turbot/steampipe-plugin-sdk/v5/plugin" +) + +//// TABLE DEFINITION //// + +func tableAzureAPIManagementBackend(_ context.Context) *plugin.Table { + return &plugin.Table{ + Name: "azure_api_management_backend", + Description: "Azure API Management Backend", + Get: &plugin.GetConfig{ + KeyColumns: plugin.AllColumns([]string{"backend_id", "resource_group", "service_name"}), + Hydrate: getAPIManagementBackend, + // IgnoreConfig: &plugin.IgnoreConfig{ + // ShouldIgnoreErrorFunc: isNotFoundError([]string{"ResourceNotFound", "InvalidApiVersionParameter", "ResourceGroupNotFound"}), + // }, + }, + List: &plugin.ListConfig{ + ParentHydrate: listAPIManagements, + Hydrate: listAPIManagementBackends, + }, + Columns: azureColumns([]*plugin.Column{ + { + Name: "name", + Type: proto.ColumnType_STRING, + Description: "A friendly name that identifies an API management backend.", + }, + { + Name: "id", + Description: "Contains ID to identify an API management backend uniquely.", + Type: proto.ColumnType_STRING, + Transform: transform.FromGo(), + }, + { + Name: "url", + Description: "Runtime Url of the Backend.", + Type: proto.ColumnType_STRING, + Transform: transform.FromField("BackendContractProperties.URL"), + }, + { + Name: "type", + Description: "Resource type for API Management resource.", + Type: proto.ColumnType_STRING, + }, + { + Name: "protocol", + Description: "Backend communication protocol. Possible values include: 'BackendProtocolHTTP', 'BackendProtocolSoap'.", + Type: proto.ColumnType_STRING, + Transform: transform.FromField("BackendContractProperties.Protocol"), + }, + { + Name: "description", + Description: "Backend Description.", + Type: proto.ColumnType_STRING, + Transform: transform.FromField("BackendContractProperties.Description"), + }, + { + Name: "resource_id", + Description: "Backend Description.", + Type: proto.ColumnType_STRING, + Transform: transform.FromField("BackendContractProperties.ResourceID"), + }, + { + Name: "properties", + Description: "Backend Properties contract.", + Type: proto.ColumnType_JSON, + Transform: transform.FromField("BackendContractProperties.Properties"), + }, + { + Name: "credentials", + Description: "Backend Credentials Contract Properties.", + Type: proto.ColumnType_JSON, + Transform: transform.FromField("BackendContractProperties.Credentials"), + }, + { + Name: "proxy", + Description: "Backend Proxy Contract Properties.", + Type: proto.ColumnType_JSON, + Transform: transform.FromField("BackendContractProperties.Proxy"), + }, + { + Name: "tls", + Description: "Backend TLS Properties.", + Type: proto.ColumnType_JSON, + Transform: transform.FromField("BackendContractProperties.TLS"), + }, + { + Name: "service_name", + Description: "Name of the API management service", + Type: proto.ColumnType_STRING, + }, + // We have added this as an extra column because the get call takes only the last path of the id as the backend_id which we do not get from the API + { + Name: "backend_id", + Description: "Name of the API management service", + Type: proto.ColumnType_STRING, + Transform: transform.FromField("ID").Transform(lastPathElement), + }, + + // Steampipe standard columns + { + Name: "title", + Description: ColumnDescriptionTitle, + Type: proto.ColumnType_STRING, + Transform: transform.FromField("Name"), + }, + { + Name: "akas", + Description: ColumnDescriptionAkas, + Type: proto.ColumnType_JSON, + Transform: transform.FromField("ID").Transform(idToAkas), + }, + + // Azure standard columns + { + Name: "resource_group", + Description: ColumnDescriptionResourceGroup, + Type: proto.ColumnType_STRING, + Transform: transform.FromField("ID").Transform(extractResourceGroupFromID), + }, + }), + } +} + +type BackendWithServiceName struct { + apimanagement.BackendContract + ServiceName string +} + +//// LIST FUNCTION + +func listAPIManagementBackends(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + serviceInfo := h.Item.(apimanagement.ServiceResource) + serviceName := *serviceInfo.Name + resourceGroup := strings.Split(*serviceInfo.ID, "/")[4] + + session, err := GetNewSession(ctx, d, "MANAGEMENT") + if err != nil { + return nil, err + } + subscriptionID := session.SubscriptionID + + apiManagementBackendClient := apimanagement.NewBackendClientWithBaseURI(session.ResourceManagerEndpoint, subscriptionID) + apiManagementBackendClient.Authorizer = session.Authorizer + + result, err := apiManagementBackendClient.ListByService(ctx, resourceGroup, serviceName, "", nil, nil) + if err != nil { + plugin.Logger(ctx).Error("listAPIManagementBackends", "list", err) + return nil, err + } + for _, apiManagementBackend := range result.Values() { + backendWithService := &BackendWithServiceName{ + apiManagementBackend, + serviceName, + } + d.StreamListItem(ctx, backendWithService) + // Check if context has been cancelled or if the limit has been hit (if specified) + // if there is a limit, it will return the number of rows required to reach this limit + if d.RowsRemaining(ctx) == 0 { + return nil, nil + } + } + + for result.NotDone() { + err = result.NextWithContext(ctx) + if err != nil { + plugin.Logger(ctx).Error("listAPIManagementBackends", "list_paging", err) + return nil, err + } + + for _, apiManagementBackend := range result.Values() { + d.StreamListItem(ctx, apiManagementBackend) + // Check if context has been cancelled or if the limit has been hit (if specified) + // if there is a limit, it will return the number of rows required to reach this limit + if d.RowsRemaining(ctx) == 0 { + return nil, nil + } + } + } + + return nil, err +} + +//// HYDRATE FUNCTIONS + +func getAPIManagementBackend(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + plugin.Logger(ctx).Debug("getAPIManagementBackend") + + backendID := d.EqualsQualString("backend_id") + serviceName := d.EqualsQualString("service_name") + resourceGroup := d.EqualsQualString("resource_group") + + // resourceGroupName can't be empty + // Error: pq: rpc error: code = Unknown desc = apimanagement.ServiceClient#Get: Invalid input: autorest/validation: validation failed: parameter=serviceName + // constraint=MinLength value="" details: value length must be greater than or equal to 1 + if len(backendID) < 1 { + return nil, nil + } + + session, err := GetNewSession(ctx, d, "MANAGEMENT") + if err != nil { + return nil, err + } + subscriptionID := session.SubscriptionID + + apiManagementBackendClient := apimanagement.NewBackendClientWithBaseURI(session.ResourceManagerEndpoint, subscriptionID) + apiManagementBackendClient.Authorizer = session.Authorizer + + op, err := apiManagementBackendClient.Get(ctx, resourceGroup, serviceName, backendID) + if err != nil { + plugin.Logger(ctx).Error("getAPIManagementBackend", "get", err) + return nil, err + } + + return BackendWithServiceName{op, serviceName}, nil +} \ No newline at end of file From 1efc8cc48297c425dd5f2165e1c0913da82459d6 Mon Sep 17 00:00:00 2001 From: "madhushreeray@30" Date: Mon, 30 Oct 2023 17:46:00 +0530 Subject: [PATCH 2/4] add example queries --- azure/table_azure_api_management_backend.go | 12 ++--- docs/tables/azure_api_management_backend.md | 59 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 docs/tables/azure_api_management_backend.md diff --git a/azure/table_azure_api_management_backend.go b/azure/table_azure_api_management_backend.go index 5660add2..518afad3 100644 --- a/azure/table_azure_api_management_backend.go +++ b/azure/table_azure_api_management_backend.go @@ -20,9 +20,9 @@ func tableAzureAPIManagementBackend(_ context.Context) *plugin.Table { Get: &plugin.GetConfig{ KeyColumns: plugin.AllColumns([]string{"backend_id", "resource_group", "service_name"}), Hydrate: getAPIManagementBackend, - // IgnoreConfig: &plugin.IgnoreConfig{ - // ShouldIgnoreErrorFunc: isNotFoundError([]string{"ResourceNotFound", "InvalidApiVersionParameter", "ResourceGroupNotFound"}), - // }, + IgnoreConfig: &plugin.IgnoreConfig{ + ShouldIgnoreErrorFunc: isNotFoundError([]string{"ResourceNotFound", "ResourceGroupNotFound"}), + }, }, List: &plugin.ListConfig{ ParentHydrate: listAPIManagements, @@ -95,13 +95,13 @@ func tableAzureAPIManagementBackend(_ context.Context) *plugin.Table { }, { Name: "service_name", - Description: "Name of the API management service", + Description: "Name of the API management service.", Type: proto.ColumnType_STRING, }, - // We have added this as an extra column because the get call takes only the last path of the id as the backend_id which we do not get from the API + // We have added this as an extra column because the get call takes only the last path of the id as the backend_id which we do not get from the API { Name: "backend_id", - Description: "Name of the API management service", + Description: "The API management backend ID.", Type: proto.ColumnType_STRING, Transform: transform.FromField("ID").Transform(lastPathElement), }, diff --git a/docs/tables/azure_api_management_backend.md b/docs/tables/azure_api_management_backend.md new file mode 100644 index 00000000..db041582 --- /dev/null +++ b/docs/tables/azure_api_management_backend.md @@ -0,0 +1,59 @@ +# Table: azure_api_management_backend + +The "Backend" in API Management represents the configuration of the web service/API on the backend that the gateway will forward the request to, after the request has been accepted and processed by APIM's policies. An API Management Backend provides details about the destination of the API requests. Backends in APIM can be, for instance, a web service running on Azure App Service, a virtual machine, or even an external API hosted outside of Azure. They play a critical role in the end-to-end API request and response lifecycle within APIM. + +## Examples + +### Basic Info + +```sql +select + name, + id, + protocol, + service_name, + url, + type +from + azure_api_management_backend; +``` + +### List the backend credential contract properties + +```sql +select + name, + id, + credentials -> 'authorization' ->> 'parameter' as parameter, + credentials -> 'authorization' ->> 'scheme' as scheme +from + azure_api_management_backend; +``` + +### Get the TLS configuration for a particular backend service + +```sql +select + name, + id, + tls -> 'validateCertificateChain' as tls_validate_certificate_chain, + tls -> 'validateCertificateName' as tls_validate_certificate_name, +from + azure_api_management_backend; +``` + +### List backends that follow http protocol + +```sql +select + name, + id, + protocol, + service_name, + url, + type +from + azure_api_management_backend +where + protocol = 'http'; +``` \ No newline at end of file From 39e8148a2f45562e7534272d3882cc8b4bdc3503 Mon Sep 17 00:00:00 2001 From: ParthaI Date: Mon, 29 Jan 2024 20:49:52 +0530 Subject: [PATCH 3/4] Made changes as per the suggestion --- azure/table_azure_api_management_backend.go | 90 +++++++++++++++++---- docs/tables/azure_api_management_backend.md | 81 ++++++++++++++++--- 2 files changed, 145 insertions(+), 26 deletions(-) diff --git a/azure/table_azure_api_management_backend.go b/azure/table_azure_api_management_backend.go index 518afad3..e7c2a30b 100644 --- a/azure/table_azure_api_management_backend.go +++ b/azure/table_azure_api_management_backend.go @@ -2,6 +2,7 @@ package azure import ( "context" + "fmt" "strings" "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2020-12-01/apimanagement" @@ -27,6 +28,28 @@ func tableAzureAPIManagementBackend(_ context.Context) *plugin.Table { List: &plugin.ListConfig{ ParentHydrate: listAPIManagements, Hydrate: listAPIManagementBackends, + KeyColumns: plugin.KeyColumnSlice{ + { + Name: "service_name", + Require: plugin.Optional, + Operators: []string{"="}, + }, + { + Name: "name", + Require: plugin.Optional, + Operators: []string{"=", "<>"}, + }, + { + Name: "url", + Require: plugin.Optional, + Operators: []string{"=", "<>"}, + }, + { + Name: "resource_group", + Require: plugin.Optional, + Operators: []string{"="}, + }, + }, }, Columns: azureColumns([]*plugin.Column{ { @@ -42,7 +65,7 @@ func tableAzureAPIManagementBackend(_ context.Context) *plugin.Table { }, { Name: "url", - Description: "Runtime Url of the Backend.", + Description: "Runtime Url of the API management backend.", Type: proto.ColumnType_STRING, Transform: transform.FromField("BackendContractProperties.URL"), }, @@ -53,43 +76,43 @@ func tableAzureAPIManagementBackend(_ context.Context) *plugin.Table { }, { Name: "protocol", - Description: "Backend communication protocol. Possible values include: 'BackendProtocolHTTP', 'BackendProtocolSoap'.", + Description: "API management backend communication protocol. Possible values include: 'BackendProtocolHTTP', 'BackendProtocolSoap'.", Type: proto.ColumnType_STRING, Transform: transform.FromField("BackendContractProperties.Protocol"), }, { Name: "description", - Description: "Backend Description.", + Description: "The API management backend Description.", Type: proto.ColumnType_STRING, Transform: transform.FromField("BackendContractProperties.Description"), }, { Name: "resource_id", - Description: "Backend Description.", + Description: "Management Uri of the Resource in External System. This url can be the Arm Resource Id of Logic Apps, Function Apps or Api Apps.", Type: proto.ColumnType_STRING, Transform: transform.FromField("BackendContractProperties.ResourceID"), }, { Name: "properties", - Description: "Backend Properties contract.", + Description: "The API management backend Properties contract.", Type: proto.ColumnType_JSON, Transform: transform.FromField("BackendContractProperties.Properties"), }, { Name: "credentials", - Description: "Backend Credentials Contract Properties.", + Description: "The API management backend credentials contract properties.", Type: proto.ColumnType_JSON, Transform: transform.FromField("BackendContractProperties.Credentials"), }, { Name: "proxy", - Description: "Backend Proxy Contract Properties.", + Description: "The API management backend proxy contract properties.", Type: proto.ColumnType_JSON, Transform: transform.FromField("BackendContractProperties.Proxy"), }, { Name: "tls", - Description: "Backend TLS Properties.", + Description: "The API management backend TLS properties.", Type: proto.ColumnType_JSON, Transform: transform.FromField("BackendContractProperties.TLS"), }, @@ -117,7 +140,7 @@ func tableAzureAPIManagementBackend(_ context.Context) *plugin.Table { Name: "akas", Description: ColumnDescriptionAkas, Type: proto.ColumnType_JSON, - Transform: transform.FromField("ID").Transform(idToAkas), + Transform: transform.FromField("ID").Transform(transform.EnsureStringArray), }, // Azure standard columns @@ -143,8 +166,18 @@ func listAPIManagementBackends(ctx context.Context, d *plugin.QueryData, h *plug serviceName := *serviceInfo.Name resourceGroup := strings.Split(*serviceInfo.ID, "/")[4] + if d.EqualsQualString("service_name") != "" || d.EqualsQualString("resource_group") != "" { + if d.EqualsQualString("service_name") != "" && d.EqualsQualString("service_name") != serviceName { + return nil, nil + } + if d.EqualsQualString("resource_group") != "" && d.EqualsQualString("resource_group") != resourceGroup { + return nil, nil + } + } + session, err := GetNewSession(ctx, d, "MANAGEMENT") if err != nil { + plugin.Logger(ctx).Error("azure_api_management_backend.listAPIManagementBackends", "session_error", err) return nil, err } subscriptionID := session.SubscriptionID @@ -152,9 +185,36 @@ func listAPIManagementBackends(ctx context.Context, d *plugin.QueryData, h *plug apiManagementBackendClient := apimanagement.NewBackendClientWithBaseURI(session.ResourceManagerEndpoint, subscriptionID) apiManagementBackendClient.Authorizer = session.Authorizer - result, err := apiManagementBackendClient.ListByService(ctx, resourceGroup, serviceName, "", nil, nil) + // Build filter string + filter := "" + if d.EqualsQualString("name") != "" || d.EqualsQualString("url") != "" { + filterQuals := []string{"name", "url"} + for _, columnName := range filterQuals { + if d.Quals[columnName] != nil { + quals := d.Quals[columnName].Quals + for _, q := range quals { + switch q.Operator { + case "=": + if filter == "" { + filter = fmt.Sprintf(columnName+" eq '%s' ", q.Value.GetStringValue()) + } else { + filter = filter + " and " + fmt.Sprintf(columnName+" eq '%s' ", q.Value.GetStringValue()) + } + case "<>": + if filter == "" { + filter = fmt.Sprintf(columnName+" ne '%s' ", q.Value.GetStringValue()) + } else { + filter = filter + " and " + fmt.Sprintf(columnName+" ne '%s' ", q.Value.GetStringValue()) + } + } + } + } + } + } + + result, err := apiManagementBackendClient.ListByService(ctx, resourceGroup, serviceName, filter, nil, nil) if err != nil { - plugin.Logger(ctx).Error("listAPIManagementBackends", "list", err) + plugin.Logger(ctx).Error("azure_api_management_backend.listAPIManagementBackends", "api_error", err) return nil, err } for _, apiManagementBackend := range result.Values() { @@ -173,7 +233,7 @@ func listAPIManagementBackends(ctx context.Context, d *plugin.QueryData, h *plug for result.NotDone() { err = result.NextWithContext(ctx) if err != nil { - plugin.Logger(ctx).Error("listAPIManagementBackends", "list_paging", err) + plugin.Logger(ctx).Error("azure_api_management_backend.listAPIManagementBackends", "list_paging", err) return nil, err } @@ -193,7 +253,6 @@ func listAPIManagementBackends(ctx context.Context, d *plugin.QueryData, h *plug //// HYDRATE FUNCTIONS func getAPIManagementBackend(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { - plugin.Logger(ctx).Debug("getAPIManagementBackend") backendID := d.EqualsQualString("backend_id") serviceName := d.EqualsQualString("service_name") @@ -208,6 +267,7 @@ func getAPIManagementBackend(ctx context.Context, d *plugin.QueryData, h *plugin session, err := GetNewSession(ctx, d, "MANAGEMENT") if err != nil { + plugin.Logger(ctx).Error("azure_api_management_backend.listAPIManagementBackends", "session_error", err) return nil, err } subscriptionID := session.SubscriptionID @@ -217,9 +277,9 @@ func getAPIManagementBackend(ctx context.Context, d *plugin.QueryData, h *plugin op, err := apiManagementBackendClient.Get(ctx, resourceGroup, serviceName, backendID) if err != nil { - plugin.Logger(ctx).Error("getAPIManagementBackend", "get", err) + plugin.Logger(ctx).Error("azure_api_management_backend.listAPIManagementBackends", "api_error", err) return nil, err } return BackendWithServiceName{op, serviceName}, nil -} \ No newline at end of file +} diff --git a/docs/tables/azure_api_management_backend.md b/docs/tables/azure_api_management_backend.md index db041582..d0e73a5a 100644 --- a/docs/tables/azure_api_management_backend.md +++ b/docs/tables/azure_api_management_backend.md @@ -1,12 +1,22 @@ -# Table: azure_api_management_backend +--- +title: "Steampipe Table: azure_api_management_backend - Query Azure API Management Backends using SQL" +description: "Allows users to query Azure API Management Backends, specifically providing access to configuration details, service details, and backend settings." +--- -The "Backend" in API Management represents the configuration of the web service/API on the backend that the gateway will forward the request to, after the request has been accepted and processed by APIM's policies. An API Management Backend provides details about the destination of the API requests. Backends in APIM can be, for instance, a web service running on Azure App Service, a virtual machine, or even an external API hosted outside of Azure. They play a critical role in the end-to-end API request and response lifecycle within APIM. +# Table: azure_api_management_backend - Query API Management Backend Configurations using SQL + +In Azure API Management (APIM), a "Backend" represents the configuration of a web service or API that is the destination for API requests processed by APIM's policies. This includes various types of backends, such as services running on Azure App Service, virtual machines, or external APIs hosted outside of Azure. Understanding the backend configurations is crucial for managing the API request and response lifecycle within APIM. + +## Table Usage Guide + +The `azure_api_management_backend` table provides insights into the backend configurations within Azure API Management. Use this table to gain detailed information about how API requests are routed and managed, including the protocol used, service details, and security configurations. ## Examples ### Basic Info +Gain a general understanding of the backend configurations in your API Management service. This query is essential for a quick overview of how your APIs are set up in terms of endpoints and protocols. -```sql +```sql+postgres select name, id, @@ -18,9 +28,22 @@ from azure_api_management_backend; ``` -### List the backend credential contract properties +```sql+sqlite +select + name, + id, + protocol, + service_name, + url, + type +from + azure_api_management_backend; +``` + +### List the Backend Credential Contract Properties +Review the authorization credentials for backends. This is crucial for understanding and managing security configurations for your API backends. -```sql +```sql+postgres select name, id, @@ -30,21 +53,43 @@ from azure_api_management_backend; ``` -### Get the TLS configuration for a particular backend service +```sql+sqlite +select + name, + id, + json_extract(json_extract(credentials, '$.authorization'), '$.parameter') as parameter, + json_extract(json_extract(credentials, '$.authorization'), '$.scheme') as scheme +from + azure_api_management_backend; +``` + +### Get the TLS Configuration for a Particular Backend Service +Examine the TLS (Transport Layer Security) configurations for backend services. This query helps ensure that secure communication protocols are in place. -```sql +```sql+postgres select name, id, tls -> 'validateCertificateChain' as tls_validate_certificate_chain, - tls -> 'validateCertificateName' as tls_validate_certificate_name, + tls -> 'validateCertificateName' as tls_validate_certificate_name from azure_api_management_backend; ``` -### List backends that follow http protocol +```sql+sqlite +select + name, + id, + json_extract(tls, '$.validateCertificateChain') as tls_validate_certificate_chain, + json_extract(tls, '$.validateCertificateName') as tls_validate_certificate_name +from + azure_api_management_backend; +``` -```sql +### List Backends That Follow HTTP Protocol +Identify backends using the HTTP protocol. This can be important for reviewing API security, as HTTP lacks the encryption of HTTPS. + +```sql+postgres select name, id, @@ -56,4 +101,18 @@ from azure_api_management_backend where protocol = 'http'; -``` \ No newline at end of file +``` + +```sql+sqlite +select + name, + id, + protocol, + service_name, + url, + type +from + azure_api_management_backend +where + protocol = 'http'; +``` From f5675b5400a265ea19b9d3916df7007ec7e1cf12 Mon Sep 17 00:00:00 2001 From: ParthaI Date: Tue, 30 Jan 2024 10:48:37 +0530 Subject: [PATCH 4/4] Handle InvalidOperation error for list API call. --- azure/table_azure_api_management_backend.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azure/table_azure_api_management_backend.go b/azure/table_azure_api_management_backend.go index e7c2a30b..f9fa98ba 100644 --- a/azure/table_azure_api_management_backend.go +++ b/azure/table_azure_api_management_backend.go @@ -214,6 +214,11 @@ func listAPIManagementBackends(ctx context.Context, d *plugin.QueryData, h *plug result, err := apiManagementBackendClient.ListByService(ctx, resourceGroup, serviceName, filter, nil, nil) if err != nil { + // API throws error during the resource creation with status code 400. + // azure: apimanagement.BackendClient#ListByService: Failure responding to request: StatusCode=400 -- Original Error: autorest/azure: Service returned an error. Status=400 Code="InvalidOperation" Message="API Management service is activating" (SQLSTATE HV000) + if strings.Contains(err.Error(), "API Management service is activating") { + return nil, nil + } plugin.Logger(ctx).Error("azure_api_management_backend.listAPIManagementBackends", "api_error", err) return nil, err }