Skip to content

how to export iothub devices #25673

@aohanhongzhi

Description

@aohanhongzhi

I've already reviewed the relevant permission configurations with engineers from Microsoft China, and everything appears to be correct. They mentioned that they're not sure how the Go SDK invokes the API, as there are many versions of the API available. Therefore, they suggested that I report this issue directly here on GitHub Issues.

Bug Report

package iothub

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/iothub/armiothub"
	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
	log "github.com/sirupsen/logrus"
)

// ExportDevicesClient 用于导出设备的客户端
type ExportDevicesClient struct {
	subscriptionID string
	resourceGroup  string
	iotHubName     string
	storageAccount string // 存储账户名称
	containerName  string // 容器名称
	sasToken       string // 存储容器的SAS Token
}

// NewExportDevicesClient 创建导出设备客户端
func NewExportDevicesClient(subscriptionID, resourceGroup, iotHubName, storageAccount, containerName, sasToken string) *ExportDevicesClient {
	return &ExportDevicesClient{
		subscriptionID: subscriptionID,
		resourceGroup:  resourceGroup,
		iotHubName:     iotHubName,
		storageAccount: storageAccount,
		containerName:  containerName,
		sasToken:       sasToken,
	}
}

// 导出所有设备到Blob Storage
func (c *ExportDevicesClient) ExportAllDevices(ctx context.Context) error {
	clientOptions := azcore.ClientOptions{
		Cloud: cloud.AzureChina,
		Logging: policy.LogOptions{
			IncludeBody: true,
		},
	}
	options := azidentity.DefaultAzureCredentialOptions{
		ClientOptions: clientOptions,
	}
	cred, err := azidentity.NewDefaultAzureCredential(&options)
	if err != nil {
		return fmt.Errorf("failed to obtain a credential: %v", err)
	}

	client, err := armiothub.NewResourceClient(c.subscriptionID, cred, &arm.ClientOptions{
		ClientOptions: policy.ClientOptions{
			Cloud: cloud.AzureChina,
			Logging: policy.LogOptions{
				IncludeBody: true,
			},
		},
	})
	if err != nil {
		return fmt.Errorf("failed to create client: %v", err)
	}

	// 这里是正常可用的
	res, err := client.CheckNameAvailability(ctx, armiothub.OperationInputs{
		Name: to.Ptr("test-request"),
	}, nil)
	if err != nil {
		log.Fatalf("failed to finish the request: %v", err)
	}
	// You could use response here. We use blank identifier for just demo purposes.
	log.Info(res)

	// 构建导出设备的URI (包含SAS Token)
	// 格式: https://{storageAccount}.blob.core.chinacloudapi.cn/{containerName}?{sasToken}
	exportURI := fmt.Sprintf("https://%s.blob.core.chinacloudapi.cn/%s?%s", c.storageAccount, c.containerName, c.sasToken)
	log.Infof("导出URL %v", exportURI)
	log.Infof("Starting device export for IoT Hub: %s (Azure China)", c.iotHubName)

	// ExportDevices 返回 *armiothub.ResourceClientExportDevicesResponse, error
	// 它是长时间运行的操作吗?查看源码,它没有Begin前缀,可能不是LRO,但通常导出是大任务
	// 根据文档,ExportDevices 返回的是 ResourceClientExportDevicesResponse
	// 如果它是LRO,应该返回 Poller
	// 再次检查文档: func (client *ResourceClient) ExportDevices(...) (ResourceClientExportDevicesResponse, error)
	// 看起来它不是基于Poller的LRO,或者SDK版本差异。
	// 我们直接调用它

	// Traceid 获取。 方便开发调试,可能与版本有关系。
	_, err = client.ExportDevices(ctx, c.resourceGroup, c.iotHubName, armiothub.ExportDevicesRequest{
		ExcludeKeys:            to.Ptr(false),
		ExportBlobContainerURI: to.Ptr(exportURI),
	}, nil)

	if err != nil {
		return fmt.Errorf("failed to start device export: %v", err)
	}

	log.Info("Device export job started successfully.")

	// 因为 ExportDevices 是异步的,我们需要轮询Job状态
	// 使用 NewListJobsPager 查找导出任务状态
	// 或者我们简单等待一段时间,或者实现Job查询逻辑
	// 这里我们简化处理,只返回启动成功
	return nil
}

The following code snippet executes and returns correct results, indicating that authentication should be working properly and no permission errors are being reported.

	// 这里是正常可用的
	res, err := client.CheckNameAvailability(ctx, armiothub.OperationInputs{
		Name: to.Ptr("test-request"),
	}, nil)
	if err != nil {
		log.Fatalf("failed to finish the request: %v", err)
	}

It starts throwing an error when executing the code below.

	// Traceid 获取。 方便开发调试,可能与版本有关系。
	_, err = client.ExportDevices(ctx, c.resourceGroup, c.iotHubName, armiothub.ExportDevicesRequest{
		ExcludeKeys:            to.Ptr(false),
		ExportBlobContainerURI: to.Ptr(exportURI),
	}, nil)

	if err != nil {
		return fmt.Errorf("failed to start device export: %v", err)
	}
  • What happened?
POST https://management.chinacloudapi.cn/subscriptions/75a2691b-c0a3-410f-9ea1-2aff67fcb91c/resourceGroups/RBLC_GROW/providers/Microsoft.Devices/IotHubs/boschcrib/exportDevices
--------------------------------------------------------------------------------
RESPONSE 403: 403 Forbidden
ERROR CODE: AuthorizationFailed
--------------------------------------------------------------------------------
{
  "error": {
    "code": "AuthorizationFailed",
    "message": "The client '81d8d7de-31db-476e-a208-086b96c60a9b' with object id '3e743de1-81c1-4cc4-a0f3-4055a21b1d1f' does not have authorization to perform action 'Microsoft.Devices/IotHubs/exportDevices/action' over scope '/subscriptions/75a2691b-c0a3-410f-9ea1-2aff67fcb91c/resourceGroups/RBLC_GROW/providers/Microsoft.Devices/IotHubs/boschcrib' or the scope is invalid. If access was recently granted, please refresh your credentials."
  }
}
--------------------------------------------------------------------------------
  • What did you expect or want to happen?

export devices

  • How can we reproduce it?

refer my code

  • Anything we should know about your environment.

china cloud

FYI

I use java sdk to export it successfully.

https://github.com/Azure/azure-iot-service-sdk-java

Image

Metadata

Metadata

Assignees

Labels

IoTMgmtThis issue is related to a management-plane library.Service AttentionWorkflow: This issue is responsible by Azure service team.customer-reportedIssues that are reported by GitHub users external to the Azure organization.needs-team-attentionWorkflow: This issue needs attention from Azure service team or SDK teamquestionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions