Skip to content

Commit 3bf5651

Browse files
authored
Add plural data source for retrieving Artifact Registry versions (#14727)
1 parent 4fde73f commit 3bf5651

File tree

4 files changed

+339
-0
lines changed

4 files changed

+339
-0
lines changed

mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
4242
"google_artifact_registry_tag": artifactregistry.DataSourceArtifactRegistryTag(),
4343
"google_artifact_registry_tags": artifactregistry.DataSourceArtifactRegistryTags(),
4444
"google_artifact_registry_version": artifactregistry.DataSourceArtifactRegistryVersion(),
45+
"google_artifact_registry_versions": artifactregistry.DataSourceArtifactRegistryVersions(),
4546
"google_apphub_discovered_workload": apphub.DataSourceApphubDiscoveredWorkload(),
4647
"google_app_engine_default_service_account": appengine.DataSourceGoogleAppEngineDefaultServiceAccount(),
4748
"google_apphub_application": apphub.DataSourceGoogleApphubApplication(),
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package artifactregistry
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"net/url"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
10+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
11+
)
12+
13+
func DataSourceArtifactRegistryVersions() *schema.Resource {
14+
return &schema.Resource{
15+
Read: dataSourceArtifactRegistryVersionsRead,
16+
Schema: map[string]*schema.Schema{
17+
"location": {
18+
Type: schema.TypeString,
19+
Required: true,
20+
},
21+
"repository_id": {
22+
Type: schema.TypeString,
23+
Required: true,
24+
},
25+
"package_name": {
26+
Type: schema.TypeString,
27+
Required: true,
28+
},
29+
"filter": {
30+
Type: schema.TypeString,
31+
Optional: true,
32+
},
33+
"view": {
34+
Type: schema.TypeString,
35+
Optional: true,
36+
Default: "BASIC",
37+
ValidateFunc: validateViewArtifactRegistryVersions,
38+
},
39+
"project": {
40+
Type: schema.TypeString,
41+
Optional: true,
42+
},
43+
"versions": {
44+
Type: schema.TypeList,
45+
Computed: true,
46+
Elem: &schema.Resource{
47+
Schema: map[string]*schema.Schema{
48+
"name": {
49+
Type: schema.TypeString,
50+
Computed: true,
51+
},
52+
"description": {
53+
Type: schema.TypeString,
54+
Computed: true,
55+
},
56+
"related_tags": {
57+
Type: schema.TypeList,
58+
Computed: true,
59+
Elem: &schema.Resource{
60+
Schema: map[string]*schema.Schema{
61+
"name": {
62+
Type: schema.TypeString,
63+
Computed: true,
64+
},
65+
"version": {
66+
Type: schema.TypeString,
67+
Computed: true,
68+
},
69+
},
70+
},
71+
},
72+
"create_time": {
73+
Type: schema.TypeString,
74+
Computed: true,
75+
},
76+
"update_time": {
77+
Type: schema.TypeString,
78+
Computed: true,
79+
},
80+
"annotations": {
81+
Type: schema.TypeMap,
82+
Computed: true,
83+
Elem: &schema.Schema{Type: schema.TypeString},
84+
},
85+
},
86+
},
87+
},
88+
},
89+
}
90+
}
91+
92+
func dataSourceArtifactRegistryVersionsRead(d *schema.ResourceData, meta interface{}) error {
93+
config := meta.(*transport_tpg.Config)
94+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
95+
if err != nil {
96+
return err
97+
}
98+
99+
project, err := tpgresource.GetProject(d, config)
100+
if err != nil {
101+
return err
102+
}
103+
104+
basePath, err := tpgresource.ReplaceVars(d, config, "{{ArtifactRegistryBasePath}}")
105+
if err != nil {
106+
return fmt.Errorf("Error setting Artifact Registry base path: %s", err)
107+
}
108+
109+
resourcePath, err := tpgresource.ReplaceVars(d, config, fmt.Sprintf("projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/packages/{{package_name}}/versions"))
110+
if err != nil {
111+
return fmt.Errorf("Error setting resource path: %s", err)
112+
}
113+
114+
view := d.Get("view").(string)
115+
116+
urlRequest := basePath + resourcePath
117+
118+
u, err := url.Parse(urlRequest)
119+
if err != nil {
120+
return fmt.Errorf("Error parsing URL: %s", err)
121+
}
122+
123+
q := u.Query()
124+
q.Set("view", view)
125+
126+
filter := ""
127+
if v, ok := d.GetOk("filter"); ok {
128+
filter = v.(string)
129+
q.Set("filter", filter)
130+
}
131+
132+
u.RawQuery = q.Encode()
133+
urlRequest = u.String()
134+
135+
headers := make(http.Header)
136+
versions := make([]map[string]interface{}, 0)
137+
pageToken := ""
138+
139+
for {
140+
u, err := url.Parse(urlRequest)
141+
if err != nil {
142+
return fmt.Errorf("Error parsing URL: %s", err)
143+
}
144+
145+
q := u.Query()
146+
if pageToken != "" {
147+
q.Set("pageToken", pageToken)
148+
}
149+
u.RawQuery = q.Encode()
150+
151+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
152+
Config: config,
153+
Method: "GET",
154+
RawURL: u.String(),
155+
UserAgent: userAgent,
156+
Headers: headers,
157+
})
158+
159+
if err != nil {
160+
return fmt.Errorf("Error listing Artifact Registry versions: %s", err)
161+
}
162+
163+
if items, ok := res["versions"].([]interface{}); ok {
164+
for _, item := range items {
165+
version := item.(map[string]interface{})
166+
167+
var relatedTags []map[string]interface{}
168+
if rawTags, ok := version["relatedTags"].([]interface{}); ok {
169+
for _, rawTag := range rawTags {
170+
if tagMap, ok := rawTag.(map[string]interface{}); ok {
171+
entry := map[string]interface{}{
172+
"name": tagMap["name"],
173+
"version": tagMap["version"],
174+
}
175+
relatedTags = append(relatedTags, entry)
176+
}
177+
}
178+
}
179+
180+
annotations := make(map[string]string)
181+
if anno, ok := version["annotations"].(map[string]interface{}); ok {
182+
for k, v := range anno {
183+
if val, ok := v.(string); ok {
184+
annotations[k] = val
185+
}
186+
}
187+
}
188+
189+
getString := func(m map[string]interface{}, key string) string {
190+
if v, ok := m[key].(string); ok {
191+
return v
192+
}
193+
return ""
194+
}
195+
196+
versions = append(versions, map[string]interface{}{
197+
"name": getString(version, "name"),
198+
"description": getString(version, "description"),
199+
"related_tags": relatedTags,
200+
"create_time": getString(version, "createTime"),
201+
"update_time": getString(version, "updateTime"),
202+
"annotations": annotations,
203+
})
204+
}
205+
}
206+
207+
if nextToken, ok := res["nextPageToken"].(string); ok && nextToken != "" {
208+
pageToken = nextToken
209+
} else {
210+
break
211+
}
212+
}
213+
214+
if err := d.Set("project", project); err != nil {
215+
return fmt.Errorf("Error setting project: %s", err)
216+
}
217+
218+
if err := d.Set("versions", versions); err != nil {
219+
return fmt.Errorf("Error setting Artifact Registry versions: %s", err)
220+
}
221+
222+
d.SetId(resourcePath)
223+
224+
return nil
225+
}
226+
227+
func validateViewArtifactRegistryVersions(val interface{}, key string) ([]string, []error) {
228+
v := val.(string)
229+
var errs []error
230+
231+
if v != "BASIC" && v != "FULL" {
232+
errs = append(errs, fmt.Errorf("%q must be either 'BASIC' or 'FULL', got %q", key, v))
233+
}
234+
235+
return nil, errs
236+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package artifactregistry_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
7+
"github.com/hashicorp/terraform-provider-google/google/acctest"
8+
)
9+
10+
func TestAccDataSourceArtifactRegistryVersions_basic(t *testing.T) {
11+
t.Parallel()
12+
13+
acctest.VcrTest(t, resource.TestCase{
14+
PreCheck: func() { acctest.AccTestPreCheck(t) },
15+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
16+
Steps: []resource.TestStep{
17+
{
18+
Config: testAccDataSourceArtifactRegistryVersionsConfig,
19+
Check: resource.ComposeTestCheckFunc(
20+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_versions.this", "project"),
21+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_versions.this", "location"),
22+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_versions.this", "repository_id"),
23+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_versions.this", "package_name"),
24+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_versions.this", "versions.0.name"),
25+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_versions.this", "versions.0.create_time"),
26+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_versions.this", "versions.0.update_time"),
27+
),
28+
},
29+
},
30+
})
31+
}
32+
33+
// Test the data source against the public AR repos
34+
// https://console.cloud.google.com/artifacts/docker/cloudrun/us/container
35+
// https://console.cloud.google.com/artifacts/docker/go-containerregistry/us/gcr.io
36+
const testAccDataSourceArtifactRegistryVersionsConfig = `
37+
data "google_artifact_registry_versions" "this" {
38+
project = "go-containerregistry"
39+
location = "us"
40+
repository_id = "gcr.io"
41+
package_name = "gcrane"
42+
filter = "name=\"projects/go-containerregistry/locations/us/repositories/gcr.io/packages/gcrane/versions/*:b*\""
43+
view = "FULL"
44+
}
45+
`
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
subcategory: "Artifact Registry"
3+
description: |-
4+
Get information about versions within a Google Artifact Registry package.
5+
---
6+
7+
# google_artifact_registry_versions
8+
9+
Get information about Artifact Registry versions.
10+
See [the official documentation](https://cloud.google.com/artifact-registry/docs/overview)
11+
and [API](https://cloud.google.com/artifact-registry/docs/reference/rest/v1/projects.locations.repositories.packages.versions/list).
12+
13+
## Example Usage
14+
15+
```hcl
16+
data "google_artifact_registry_versions" "my_versions" {
17+
location = "us-central1"
18+
repository_id = "example-repo"
19+
package_name = "example-package"
20+
}
21+
```
22+
23+
## Argument Reference
24+
25+
The following arguments are supported:
26+
27+
* `location` - (Required) The location of the artifact registry.
28+
29+
* `repository_id` - (Required) The last part of the repository name to fetch from.
30+
31+
* `package_name` - (Required) The name of the package.
32+
33+
* `filter` - (Optional) An expression for filtering the results of the request. Filter rules are case insensitive. The fields eligible for filtering are `name` and `version`. Further information can be found in the [REST API](https://cloud.google.com/artifact-registry/docs/reference/rest/v1/projects.locations.repositories.packages.versions/list#query-parameters).
34+
35+
* `view` - (Optional) The view, which determines what version information is returned in a response. Possible values are `"BASIC"` and `"FULL"`. Defaults to `"BASIC"`.
36+
37+
* `project` - (Optional) The project ID in which the resource belongs. If it is not provided, the provider project is used.
38+
39+
## Attributes Reference
40+
41+
The following attributes are exported:
42+
43+
* `versions` - A list of all retrieved Artifact Registry versions. Structure is [defined below](#nested_versions).
44+
45+
<a name="nested_versions"></a>The `versions` block supports:
46+
47+
* `name` - The name of the version, for example: `projects/p1/locations/us-central1/repositories/repo1/packages/pkg1/versions/version1`. If the package part contains slashes, the slashes are escaped.
48+
49+
* `description` - Description of the version, as specified in its metadata.
50+
51+
* `related_tags` - A list of related tags. Will contain up to 100 tags that reference this version.
52+
53+
* `create_time` - The time, as a RFC 3339 string, this package was created.
54+
55+
* `update_time` - The time, as a RFC 3339 string, this package was last updated. This includes publishing a new version of the package.
56+
57+
* `annotations` - Client specified annotations.

0 commit comments

Comments
 (0)