diff --git a/docs/data-sources/workspace_app_image_servers.md b/docs/data-sources/workspace_app_image_servers.md
new file mode 100644
index 0000000000..feffcae4b2
--- /dev/null
+++ b/docs/data-sources/workspace_app_image_servers.md
@@ -0,0 +1,106 @@
+---
+subcategory: "Workspace"
+layout: "huaweicloud"
+page_title: "HuaweiCloud: huaweicloud_workspace_app_image_servers"
+description: |-
+ Use this data source to get the list of the image servers within HuaweiCloud.
+---
+
+# huaweicloud_workspace_app_image_servers
+
+Use this data source to get the list of the image servers within HuaweiCloud.
+
+## Example Usage
+
+### Query all image servers
+
+```hcl
+data "huaweicloud_workspace_app_image_servers" "test" {}
+```
+
+### Query image server with the specified image server ID
+
+```hcl
+variable "image_server_id" {}
+
+data "huaweicloud_workspace_app_image_servers" "test" {
+ server_id = var.image_server_id
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `region` - (Optional, String) Specifies the region in which to query the resource.
+ If omitted, the provider-level region will be used.
+
+* `name` - (Optional, String) Specified the name of the image server.
+ Fuzzy search is supported.
+
+* `server_id` - (Optional, String) Specified the ID of the image server.
+
+* `enterprise_project_id` - (Optional, String) Specifies the ID of the enterprise project to which the image server belongs.
+ This parameter is only valid for enterprise users, if omitted, all enterprise project IDs will be queried.
+
+## Attribute Reference
+
+In addition to all arguments above, the following attributes are exported:
+
+* `id` - The data source ID.
+
+* `servers` - All image servers that match the filter parameters.
+
+ The [servers](#app_image_servers) structure is documented below.
+
+
+The `servers` block supports:
+
+* `id` - The ID of the image server.
+
+* `name` - The name of the image server.
+
+* `description` - The description of the image server.
+
+* `image_generated_product_id` - The ID of the generated image product.
+
+* `image_id` - The ID of the basic image to which the image server belongs.
+
+* `image_type` - The type of the basic image to which the image server belongs.
+ + **gold**: The market image.
+ + **public**: The public image.
+ + **private**: The private image.
+ + **shared**: The shared image.
+ + **other**
+
+* `spce_code` - The specification code of the basic image to which the image server belongs.
+
+* `aps_server_group_id` - The ID of the APS server group associated with the image server.
+
+* `aps_server_id` - The ID of the APS server associated with the image server.
+
+* `app_group_id` - The ID of the application group associated with the image server.
+
+* `status` - The current status of the image server.
+ + **ACTIVE**
+ + **BUILT**: Image task is finished.
+ + **ERROR**
+
+* `authorize_accounts` - The list of authorized users of the application group associated with the image server.
+
+ The [authorize_accounts](#servers_authorize_accounts_struct) structure is documented below.
+
+* `enterprise_project_id` - The enterprise project ID to which the image server belongs.
+
+* `created_at` - The creation time of the image server, in RFC3339 format.
+
+* `updated_at` - The latest update time of the image server, in RFC3339 format.
+
+
+The `authorize_accounts` block supports:
+
+* `account` - The name of the account.
+
+* `type` - The type of the account.
+
+* `domain` - The domain name of the Workspace service.
diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go
index 0962e495f0..dd735a6463 100644
--- a/huaweicloud/provider.go
+++ b/huaweicloud/provider.go
@@ -1198,6 +1198,7 @@ func Provider() *schema.Provider {
"huaweicloud_workspace_app_group_authorizations": workspace.DataSourceWorkspaceAppGroupAuthorizations(),
"huaweicloud_workspace_app_groups": workspace.DataSourceWorkspaceAppGroups(),
+ "huaweicloud_workspace_app_image_servers": workspace.DataSourceWorkspaceAppImageServers(),
"huaweicloud_workspace_app_nas_storages": workspace.DataSourceAppNasStorages(),
"huaweicloud_workspace_app_publishable_apps": workspace.DataSourceWorkspaceAppPublishableApps(),
"huaweicloud_workspace_app_storage_policies": workspace.DataSourceAppStoragePolicies(),
diff --git a/huaweicloud/services/acceptance/workspace/data_source_huaweicloud_workspace_app_image_servers_test.go b/huaweicloud/services/acceptance/workspace/data_source_huaweicloud_workspace_app_image_servers_test.go
new file mode 100644
index 0000000000..ac054e9aa4
--- /dev/null
+++ b/huaweicloud/services/acceptance/workspace/data_source_huaweicloud_workspace_app_image_servers_test.go
@@ -0,0 +1,130 @@
+package workspace
+
+import (
+ "fmt"
+ "regexp"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
+)
+
+func TestAccDataSourceAppImageServers_basic(t *testing.T) {
+ var (
+ dataSource = "data.huaweicloud_workspace_app_image_servers.test"
+ rName = acceptance.RandomAccResourceName()
+ dc = acceptance.InitDataSourceCheck(dataSource)
+
+ byServerId = "data.huaweicloud_workspace_app_image_servers.filter_by_server_id"
+ dcByServerId = acceptance.InitDataSourceCheck(byServerId)
+
+ byName = "data.huaweicloud_workspace_app_image_servers.filter_by_name"
+ dcByName = acceptance.InitDataSourceCheck(byName)
+
+ byEpsId = "data.huaweicloud_workspace_app_image_servers.filter_by_eps_id"
+ dcByEpsId = acceptance.InitDataSourceCheck(byEpsId)
+ )
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() {
+ acceptance.TestAccPreCheck(t)
+ acceptance.TestAccPreCheckWorkspaceAppServerGroup(t)
+ acceptance.TestAccPreCheckWorkspaceAppImageSpecCode(t)
+ acceptance.TestAccPrecheckWorkspaceUserNames(t)
+ acceptance.TestAccPreCheckWorkspaceOUName(t)
+ acceptance.TestAccPreCheckWorkspaceADDomainNames(t)
+ },
+ ProviderFactories: acceptance.TestAccProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testDataSourceAppImageServers_basic(rName),
+ Check: resource.ComposeTestCheckFunc(
+ dc.CheckResourceExists(),
+ resource.TestMatchResourceAttr(dataSource, "servers.#", regexp.MustCompile(`^[1-9]([0-9]*)?$`)),
+ dcByServerId.CheckResourceExists(),
+ resource.TestCheckResourceAttrSet(byServerId, "servers.0.image_id"),
+ resource.TestCheckResourceAttrSet(byServerId, "servers.0.image_type"),
+ resource.TestCheckResourceAttrSet(byServerId, "servers.0.spce_code"),
+ resource.TestCheckResourceAttrSet(byServerId, "servers.0.aps_server_group_id"),
+ resource.TestCheckResourceAttrSet(byServerId, "servers.0.aps_server_id"),
+ resource.TestCheckResourceAttrSet(byServerId, "servers.0.app_group_id"),
+ resource.TestCheckResourceAttrSet(byServerId, "servers.0.status"),
+ resource.TestCheckResourceAttr(byServerId, "servers.0.authorize_accounts.#", "1"),
+ resource.TestCheckResourceAttr(byServerId, "servers.0.authorize_accounts.0.type", "USER"),
+ resource.TestCheckResourceAttrSet(byServerId, "servers.0.authorize_accounts.0.domain"),
+ resource.TestCheckOutput("is_server_id_filter_useful", "true"),
+ resource.TestMatchResourceAttr(byServerId, "servers.0.created_at",
+ regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?(Z|([+-]\d{2}:\d{2}))$`)),
+ resource.TestMatchResourceAttr(byServerId, "servers.0.updated_at",
+ regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?(Z|([+-]\d{2}:\d{2}))$`)),
+ dcByName.CheckResourceExists(),
+ resource.TestCheckOutput("is_name_filter_useful", "true"),
+ dcByEpsId.CheckResourceExists(),
+ resource.TestCheckOutput("is_eps_id_filter_useful", "true"),
+ ),
+ },
+ },
+ })
+}
+
+func testDataSourceAppImageServers_basic(name string) string {
+ return fmt.Sprintf(`
+%[1]s
+
+data "huaweicloud_workspace_app_image_servers" "test" {
+ depends_on = [huaweicloud_workspace_app_image_server.test]
+}
+
+locals {
+ server_id = huaweicloud_workspace_app_image_server.test.id
+ server_name = huaweicloud_workspace_app_image_server.test.name
+ eps_id = huaweicloud_workspace_app_image_server.test.enterprise_project_id
+}
+
+data "huaweicloud_workspace_app_image_servers" "filter_by_server_id" {
+ depends_on = [huaweicloud_workspace_app_image_server.test]
+
+ server_id = local.server_id
+}
+
+locals {
+ server_id_filter_result = [for v in data.huaweicloud_workspace_app_image_servers.filter_by_server_id.servers[*].id :
+ v == local.server_id]
+}
+
+output "is_server_id_filter_useful" {
+ value = length(local.server_id_filter_result) == 1 && alltrue(local.server_id_filter_result)
+}
+
+# Fuzzy search is supported.
+data "huaweicloud_workspace_app_image_servers" "filter_by_name" {
+ depends_on = [huaweicloud_workspace_app_image_server.test]
+
+ name = local.server_name
+}
+
+locals {
+ name_filter_result = [for v in data.huaweicloud_workspace_app_image_servers.filter_by_name.servers : strcontains(v.name, local.server_name)]
+}
+
+output "is_name_filter_useful" {
+ value = length(local.name_filter_result) > 0 && alltrue(local.name_filter_result)
+}
+
+data "huaweicloud_workspace_app_image_servers" "filter_by_eps_id" {
+ depends_on = [huaweicloud_workspace_app_image_server.test]
+
+ enterprise_project_id = local.eps_id
+}
+
+locals {
+ eps_id_filter_result = [for v in data.huaweicloud_workspace_app_image_servers.filter_by_eps_id.servers[*].enterprise_project_id :
+ v == local.eps_id]
+}
+
+output "is_eps_id_filter_useful" {
+ value = length(local.eps_id_filter_result) > 0 && alltrue(local.eps_id_filter_result)
+}
+`, testResourceAppImageServer_basic(name, "Data source test"))
+}
diff --git a/huaweicloud/services/acceptance/workspace/resource_huaweicloud_workspace_app_image_server_test.go b/huaweicloud/services/acceptance/workspace/resource_huaweicloud_workspace_app_image_server_test.go
index 21aa1bf3b2..d95e127bde 100644
--- a/huaweicloud/services/acceptance/workspace/resource_huaweicloud_workspace_app_image_server_test.go
+++ b/huaweicloud/services/acceptance/workspace/resource_huaweicloud_workspace_app_image_server_test.go
@@ -123,7 +123,7 @@ resource "huaweicloud_workspace_app_image_server" "test" {
authorize_accounts {
account = split(",", "%[8]s")[0]
type = "USER"
- domain = element(split("%[9]s", ","), 0)
+ domain = element(split(",", "%[9]s"), 0)
}
root_volume {
diff --git a/huaweicloud/services/workspace/data_source_huaweicloud_workspace_app_image_servers.go b/huaweicloud/services/workspace/data_source_huaweicloud_workspace_app_image_servers.go
new file mode 100644
index 0000000000..01064ff91f
--- /dev/null
+++ b/huaweicloud/services/workspace/data_source_huaweicloud_workspace_app_image_servers.go
@@ -0,0 +1,251 @@
+// Generated by PMS #445
+package workspace
+
+import (
+ "context"
+
+ "github.com/hashicorp/go-multierror"
+ "github.com/hashicorp/go-uuid"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/tidwall/gjson"
+
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/helper/httphelper"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/helper/schemas"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
+)
+
+func DataSourceWorkspaceAppImageServers() *schema.Resource {
+ return &schema.Resource{
+ ReadContext: dataSourceWorkspaceAppImageServersRead,
+
+ Schema: map[string]*schema.Schema{
+ "region": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ Description: `Specifies the region in which to query the resource. If omitted, the provider-level region will be used.`,
+ },
+ "name": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: `Specified the name of the image server.`,
+ },
+ "server_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: `Specified the ID of the image server.`,
+ },
+ "enterprise_project_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: `Specifies the ID of the enterprise project to which the image server belong.`,
+ },
+ "servers": {
+ Type: schema.TypeList,
+ Computed: true,
+ Description: `All image servers that match the filter parameters.`,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The ID of the image server.`,
+ },
+ "name": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The name of the image server.`,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The description of the image server.`,
+ },
+ "image_generated_product_id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The ID of the generated image product.`,
+ },
+ "image_id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The ID of the basic image to which the image server belongs.`,
+ },
+ "image_type": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The type of the basic image to which the image server belongs.`,
+ },
+ "spce_code": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The specification code of the basic image to which the image server belongs.`,
+ },
+ "aps_server_group_id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The ID of the APS server group associated with the image server.`,
+ },
+ "aps_server_id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The ID of the APS server associated with the image server.`,
+ },
+ "app_group_id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The ID of the application group associated with the image server.`,
+ },
+ "status": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The current status of the image server.`,
+ },
+ "authorize_accounts": {
+ Type: schema.TypeList,
+ Computed: true,
+ Description: `The list of authorized users of the application group associated with the image server.`,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "account": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The name of the account.`,
+ },
+ "type": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The type of the account.`,
+ },
+ "domain": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The domain name of the Workspace service.`,
+ },
+ },
+ },
+ },
+ "enterprise_project_id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The enterprise project ID to which the image server belongs.`,
+ },
+ "created_at": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The creation time of the image server, in RFC3339 format.`,
+ },
+ "updated_at": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: `The latest update time of the image server, in RFC3339 format.`,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+type AppImageServersDSWrapper struct {
+ *schemas.ResourceDataWrapper
+ Config *config.Config
+}
+
+func newAppImageServersDSWrapper(d *schema.ResourceData, meta interface{}) *AppImageServersDSWrapper {
+ return &AppImageServersDSWrapper{
+ ResourceDataWrapper: schemas.NewSchemaWrapper(d),
+ Config: meta.(*config.Config),
+ }
+}
+
+func dataSourceWorkspaceAppImageServersRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ wrapper := newAppImageServersDSWrapper(d, meta)
+ listImageServersRst, err := wrapper.ListImageServers()
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ id, err := uuid.GenerateUUID()
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ d.SetId(id)
+
+ err = wrapper.listImageServersToSchema(listImageServersRst)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ return nil
+}
+
+// @API Workspace GET /v1/{project_id}/image-servers
+func (w *AppImageServersDSWrapper) ListImageServers() (*gjson.Result, error) {
+ client, err := w.NewClient(w.Config, "appstream")
+ if err != nil {
+ return nil, err
+ }
+
+ uri := "/v1/{project_id}/image-servers"
+ params := map[string]any{
+ "server_name": w.Get("name"),
+ "server_id": w.Get("server_id"),
+ "enterprise_project_id": w.Get("enterprise_project_id"),
+ }
+ params = utils.RemoveNil(params)
+ return httphelper.New(client).
+ Method("GET").
+ URI(uri).
+ Query(params).
+ OffsetPager("items", "offset", "limit", 100).
+ Request().
+ Result()
+}
+
+func (w *AppImageServersDSWrapper) listImageServersToSchema(body *gjson.Result) error {
+ d := w.ResourceData
+ mErr := multierror.Append(nil,
+ d.Set("region", w.Config.GetRegion(w.ResourceData)),
+ d.Set("servers", schemas.SliceToList(body.Get("items"),
+ func(servers gjson.Result) any {
+ return map[string]any{
+ "image_id": servers.Get("image_ref.id").Value(),
+ "image_type": servers.Get("image_ref.image_type").Value(),
+ "spce_code": servers.Get("image_ref.spce_code").Value(),
+ "id": servers.Get("id").Value(),
+ "name": servers.Get("name").Value(),
+ "description": servers.Get("description").Value(),
+ "image_generated_product_id": servers.Get("image_id").Value(),
+ "aps_server_group_id": servers.Get("server_group_id").Value(),
+ "aps_server_id": servers.Get("server_id").Value(),
+ "app_group_id": servers.Get("app_group_id").Value(),
+ "status": servers.Get("status").Value(),
+ "authorize_accounts": schemas.SliceToList(servers.Get("authorize_accounts"),
+ func(authorizeAccounts gjson.Result) any {
+ return map[string]any{
+ "account": authorizeAccounts.Get("account").Value(),
+ "type": authorizeAccounts.Get("account_type").Value(),
+ "domain": authorizeAccounts.Get("domain").Value(),
+ }
+ },
+ ),
+ "enterprise_project_id": servers.Get("enterprise_project_id").Value(),
+ "created_at": w.setItemsCreateTime(servers),
+ "updated_at": w.setItemsUpdateTime(servers),
+ }
+ },
+ )),
+ )
+ return mErr.ErrorOrNil()
+}
+
+func (*AppImageServersDSWrapper) setItemsCreateTime(data gjson.Result) string {
+ return utils.FormatTimeStampRFC3339(utils.ConvertTimeStrToNanoTimestamp(data.Get("create_time").String())/1000, false)
+}
+
+func (*AppImageServersDSWrapper) setItemsUpdateTime(data gjson.Result) string {
+ return utils.FormatTimeStampRFC3339(utils.ConvertTimeStrToNanoTimestamp(data.Get("update_time").String())/1000, false)
+}