Skip to content

Commit 2671151

Browse files
authored
Merge pull request #299 from dhavalbhensdadiya-crest/parametermanager
Adding support of Parametermanager in Google Compute Integration
2 parents 7d191c5 + 7623b19 commit 2671151

16 files changed

Lines changed: 919 additions & 63 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
The Parameter Manager data source provides the capability to retrieve the parameters stored in google cloud along with revealed secrets
2+
3+
-> **Note:** Data sources is a feature exclusively available to HCL2 templates.
4+
5+
Basic examples of usage:
6+
7+
```hcl
8+
data "googlecompute-parametermanager" "basic-example" {
9+
project_id = "debian-cloud"
10+
name = "packer_test_parameter"
11+
key = "packer_test_key"
12+
version = "1"
13+
location = "us-east1"
14+
}
15+
16+
# usage example of the data source output
17+
locals {
18+
value = data.googlecompute-parametermanager.basic-example.value
19+
payload = data.googlecompute-parametermanager.basic-example.payload
20+
}
21+
```
22+
23+
Reading key-value pairs from JSON back into a native Packer map can be accomplished
24+
with the [jsondecode() function](/packer/docs/templates/hcl_templates/functions/encoding/jsondecode).
25+
26+
Reading key-value pairs from YAML back into a native Packer map can be accomplished
27+
with the [yamldecode() function](/packer/docs/templates/hcl_templates/functions/encoding/yamldecode).
28+
29+
## Configuration Reference
30+
31+
### Required
32+
33+
<!-- Code generated from the comments of the Config struct in datasource/parametermanager/data.go; DO NOT EDIT MANUALLY -->
34+
35+
- `project_id` (string) - The Google Cloud project ID where the parameter is stored.
36+
37+
- `name` (string) - The name of the parameter within the Parameter Manager.
38+
39+
- `version` (string) - The version of the parameter within the Parameter Manager.
40+
41+
<!-- End of code generated from the comments of the Config struct in datasource/parametermanager/data.go; -->
42+
43+
44+
### Optional
45+
46+
<!-- Code generated from the comments of the Config struct in datasource/parametermanager/data.go; DO NOT EDIT MANUALLY -->
47+
48+
- `location` (string) - The location in which parameter is stored. Defaults to "global" if not specified.
49+
50+
- `key` (string) - A specific key to extract from the parameter payload if it's a JSON or YAML object.
51+
52+
<!-- End of code generated from the comments of the Config struct in datasource/parametermanager/data.go; -->
53+
54+
55+
## Output Data
56+
57+
<!-- Code generated from the comments of the DatasourceOutput struct in datasource/parametermanager/data.go; DO NOT EDIT MANUALLY -->
58+
59+
- `payload` (string) - The raw string payload of the parameter version.
60+
61+
- `value` (string) - The value extracted using the 'key', if provided.
62+
63+
<!-- End of code generated from the comments of the DatasourceOutput struct in datasource/parametermanager/data.go; -->
64+
65+
66+
## Authentication
67+
68+
To authenticate with GCE, this data-source supports everything the plugin does.
69+
To get more information on this, refer to the plugin's description page, under
70+
the [authentication](/packer/integrations/hashicorp/googlecompute#authentication) section.

.web-docs/metadata.hcl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ integration {
1313
name = "Secrets Manager"
1414
slug = "secretsmanager"
1515
}
16+
component {
17+
type = "data-source"
18+
name = "Parameter Manager"
19+
slug = "parametermanager"
20+
}
1621
component {
1722
type = "data-source"
1823
name = "GCE Image"
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
//go:generate packer-sdc struct-markdown
2+
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,DatasourceOutput
3+
4+
package parametermanager
5+
6+
import (
7+
"context"
8+
"encoding/json"
9+
"errors"
10+
"fmt"
11+
12+
"github.com/hashicorp/hcl/v2/hcldec"
13+
"github.com/hashicorp/packer-plugin-sdk/hcl2helper"
14+
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
15+
"github.com/hashicorp/packer-plugin-sdk/template/config"
16+
"github.com/stretchr/testify/assert/yaml"
17+
18+
"github.com/zclconf/go-cty/cty"
19+
20+
parametermanager "cloud.google.com/go/parametermanager/apiv1"
21+
parametermanagerpb "cloud.google.com/go/parametermanager/apiv1/parametermanagerpb"
22+
23+
"google.golang.org/api/option"
24+
"google.golang.org/grpc/codes"
25+
"google.golang.org/grpc/status"
26+
)
27+
28+
// Config is the configuration structure for the data source.
29+
type Config struct {
30+
// The Google Cloud project ID where the parameter is stored.
31+
ProjectId string `mapstructure:"project_id" required:"true"`
32+
33+
// The location in which parameter is stored. Defaults to "global" if not specified.
34+
Location string `mapstructure:"location"`
35+
36+
// The name of the parameter within the Parameter Manager.
37+
Name string `mapstructure:"name" required:"true"`
38+
39+
// The version of the parameter within the Parameter Manager.
40+
Version string `mapstructure:"version" required:"true"`
41+
42+
// A specific key to extract from the parameter payload if it's a JSON or YAML object.
43+
Key string `mapstructure:"key"`
44+
}
45+
46+
// Datasource is the data source implementation.
47+
type Datasource struct {
48+
config Config
49+
}
50+
51+
// DatasourceOutput contains the data returned by the data source.
52+
type DatasourceOutput struct {
53+
// The raw string payload of the parameter version.
54+
Payload string `mapstructure:"payload"`
55+
56+
// The value extracted using the 'key', if provided.
57+
Value string `mapstructure:"value"`
58+
}
59+
60+
// ConfigSpec returns the HCL object spec for the data source configuration.
61+
func (d *Datasource) ConfigSpec() hcldec.ObjectSpec {
62+
return d.config.FlatMapstructure().HCL2Spec()
63+
}
64+
65+
// OutputSpec returns the HCL object spec for the data source output.
66+
func (d *Datasource) OutputSpec() hcldec.ObjectSpec {
67+
return (&DatasourceOutput{}).FlatMapstructure().HCL2Spec()
68+
}
69+
70+
// Configure sets up the data source configuration.
71+
func (d *Datasource) Configure(raws ...interface{}) error {
72+
err := config.Decode(&d.config, nil, raws...)
73+
if err != nil {
74+
return err
75+
}
76+
77+
var errs *packersdk.MultiError
78+
79+
if d.config.ProjectId == "" {
80+
errs = packersdk.MultiErrorAppend(errs, errors.New("a 'project_id' must be specified"))
81+
}
82+
83+
if d.config.Location == "" {
84+
d.config.Location = "global"
85+
}
86+
87+
if d.config.Name == "" {
88+
errs = packersdk.MultiErrorAppend(errs, errors.New("a 'name' must be specified"))
89+
}
90+
91+
if d.config.Version == "" {
92+
errs = packersdk.MultiErrorAppend(errs, errors.New("a 'version' must be specified"))
93+
}
94+
95+
if errs != nil && len(errs.Errors) > 0 {
96+
return errs
97+
}
98+
99+
return nil
100+
}
101+
102+
// Execute fetches the parameter from Google Cloud Parameter Manager.
103+
func (d *Datasource) Execute() (cty.Value, error) {
104+
ctx := context.Background()
105+
106+
// Create a client
107+
var client *parametermanager.Client
108+
var err error
109+
110+
if d.config.Location == "global" {
111+
client, err = parametermanager.NewClient(ctx)
112+
} else {
113+
endpoint := fmt.Sprintf("parametermanager.%s.rep.googleapis.com:443", d.config.Location)
114+
client, err = parametermanager.NewClient(ctx, option.WithEndpoint(endpoint))
115+
}
116+
117+
if err != nil {
118+
return cty.NullVal(cty.EmptyObject), fmt.Errorf("failed to create parameter manager client: %w", err)
119+
}
120+
defer client.Close()
121+
122+
// Build the request to get parameter format
123+
parameterFormatURL := fmt.Sprintf("projects/%s/locations/%s/parameters/%s", d.config.ProjectId, d.config.Location, d.config.Name)
124+
125+
// Build the request to get parameter format
126+
parameterFormatReq := &parametermanagerpb.GetParameterRequest{
127+
Name: parameterFormatURL,
128+
}
129+
130+
// Call the API to get parameter.
131+
paramFormatResp, err := client.GetParameter(ctx, parameterFormatReq)
132+
if err != nil {
133+
return cty.NullVal(cty.EmptyObject), fmt.Errorf("failed to identify parameter format %w", err)
134+
}
135+
136+
paramFormat := paramFormatResp.Format
137+
138+
parameterPayloadURL := fmt.Sprintf("projects/%s/locations/%s/parameters/%s/versions/%s", d.config.ProjectId, d.config.Location, d.config.Name, d.config.Version)
139+
140+
// Build the request to get parameter payload
141+
parameterPayloadReq := &parametermanagerpb.RenderParameterVersionRequest{
142+
Name: parameterPayloadURL,
143+
}
144+
145+
// Call the API to render a parameter version.
146+
parameterPayloadResp, err := client.RenderParameterVersion(ctx, parameterPayloadReq)
147+
if err != nil {
148+
st := status.Convert(err)
149+
if st.Code() == codes.NotFound {
150+
return cty.NullVal(cty.EmptyObject), fmt.Errorf("value %q not found", parameterPayloadResp)
151+
}
152+
return cty.NullVal(cty.EmptyObject), fmt.Errorf("error rendering parameter: %w", err)
153+
}
154+
155+
payload := parameterPayloadResp.RenderedPayload
156+
157+
// Extract value from payload if key is provided
158+
var value string
159+
var payloadMap map[string]interface{}
160+
if d.config.Key != "" {
161+
switch paramFormat {
162+
case parametermanagerpb.ParameterFormat_JSON:
163+
jsonErr := json.Unmarshal(payload, &payloadMap)
164+
if jsonErr != nil {
165+
return cty.NullVal(cty.EmptyObject), fmt.Errorf("error unmarshaling JSON payload: %w", jsonErr)
166+
}
167+
168+
case parametermanagerpb.ParameterFormat_YAML:
169+
yamlErr := yaml.Unmarshal(payload, &payloadMap)
170+
if yamlErr != nil {
171+
return cty.NullVal(cty.EmptyObject), fmt.Errorf("error unmarshaling YAML payload: %w", yamlErr)
172+
}
173+
174+
default:
175+
return cty.NullVal(cty.EmptyObject), fmt.Errorf("key extraction is supported only for JSON and YAML payload")
176+
}
177+
178+
val, ok := payloadMap[d.config.Key]
179+
if !ok {
180+
return cty.NullVal(cty.EmptyObject), fmt.Errorf("key %q not found in payload", d.config.Key)
181+
}
182+
value = fmt.Sprintf("%v", val)
183+
}
184+
185+
output := DatasourceOutput{
186+
Payload: string(payload),
187+
Value: value,
188+
}
189+
190+
return hcl2helper.HCL2ValueFromConfig(output, d.OutputSpec()), nil
191+
}

datasource/parametermanager/data.hcl2spec.go

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)