Skip to content

Commit 8a752f4

Browse files
Create the MachineImage resource (#3556) (#2109)
* Create the MachineImage resource This does not yet support the creation of instances from MachineImages. Signed-off-by: Modular Magician <[email protected]>
1 parent 342dae3 commit 8a752f4

File tree

7 files changed

+635
-2
lines changed

7 files changed

+635
-2
lines changed

.changelog/3556.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-resource
2+
`google_compute_machine_image`
3+
```

google-beta/provider.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,9 +638,9 @@ func Provider() terraform.ResourceProvider {
638638
return provider
639639
}
640640

641-
// Generated resources: 156
641+
// Generated resources: 157
642642
// Generated IAM resources: 66
643-
// Total generated resources: 222
643+
// Total generated resources: 223
644644
func ResourceMap() map[string]*schema.Resource {
645645
resourceMap, _ := ResourceMapWithErrors()
646646
return resourceMap
@@ -711,6 +711,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) {
711711
"google_compute_instance_iam_policy": ResourceIamPolicy(ComputeInstanceIamSchema, ComputeInstanceIamUpdaterProducer, ComputeInstanceIdParseFunc),
712712
"google_compute_instance_group_named_port": resourceComputeInstanceGroupNamedPort(),
713713
"google_compute_interconnect_attachment": resourceComputeInterconnectAttachment(),
714+
"google_compute_machine_image": resourceComputeMachineImage(),
714715
"google_compute_network": resourceComputeNetwork(),
715716
"google_compute_network_endpoint": resourceComputeNetworkEndpoint(),
716717
"google_compute_network_endpoint_group": resourceComputeNetworkEndpointGroup(),
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
// ----------------------------------------------------------------------------
2+
//
3+
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
4+
//
5+
// ----------------------------------------------------------------------------
6+
//
7+
// This file is automatically generated by Magic Modules and manual
8+
// changes will be clobbered when the file is regenerated.
9+
//
10+
// Please read more about how to change this file in
11+
// .github/CONTRIBUTING.md.
12+
//
13+
// ----------------------------------------------------------------------------
14+
15+
package google
16+
17+
import (
18+
"fmt"
19+
"log"
20+
"reflect"
21+
"time"
22+
23+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
24+
)
25+
26+
func resourceComputeMachineImage() *schema.Resource {
27+
return &schema.Resource{
28+
Create: resourceComputeMachineImageCreate,
29+
Read: resourceComputeMachineImageRead,
30+
Update: resourceComputeMachineImageUpdate,
31+
Delete: resourceComputeMachineImageDelete,
32+
33+
Importer: &schema.ResourceImporter{
34+
State: resourceComputeMachineImageImport,
35+
},
36+
37+
Timeouts: &schema.ResourceTimeout{
38+
Create: schema.DefaultTimeout(4 * time.Minute),
39+
Update: schema.DefaultTimeout(4 * time.Minute),
40+
Delete: schema.DefaultTimeout(4 * time.Minute),
41+
},
42+
43+
Schema: map[string]*schema.Schema{
44+
"name": {
45+
Type: schema.TypeString,
46+
Required: true,
47+
Description: `Name of the resource.`,
48+
},
49+
"source_instance": {
50+
Type: schema.TypeString,
51+
Required: true,
52+
DiffSuppressFunc: compareSelfLinkOrResourceName,
53+
Description: `The source instance used to create the machine image. You can provide this as a partial or full URL to the resource.`,
54+
},
55+
"description": {
56+
Type: schema.TypeString,
57+
Optional: true,
58+
Description: `A text description of the resource.`,
59+
},
60+
"project": {
61+
Type: schema.TypeString,
62+
Optional: true,
63+
Computed: true,
64+
ForceNew: true,
65+
},
66+
"self_link": {
67+
Type: schema.TypeString,
68+
Computed: true,
69+
},
70+
},
71+
}
72+
}
73+
74+
func resourceComputeMachineImageCreate(d *schema.ResourceData, meta interface{}) error {
75+
config := meta.(*Config)
76+
77+
obj := make(map[string]interface{})
78+
nameProp, err := expandComputeMachineImageName(d.Get("name"), d, config)
79+
if err != nil {
80+
return err
81+
} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
82+
obj["name"] = nameProp
83+
}
84+
descriptionProp, err := expandComputeMachineImageDescription(d.Get("description"), d, config)
85+
if err != nil {
86+
return err
87+
} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
88+
obj["description"] = descriptionProp
89+
}
90+
sourceInstanceProp, err := expandComputeMachineImageSourceInstance(d.Get("source_instance"), d, config)
91+
if err != nil {
92+
return err
93+
} else if v, ok := d.GetOkExists("source_instance"); !isEmptyValue(reflect.ValueOf(sourceInstanceProp)) && (ok || !reflect.DeepEqual(v, sourceInstanceProp)) {
94+
obj["sourceInstance"] = sourceInstanceProp
95+
}
96+
97+
url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/machineImages")
98+
if err != nil {
99+
return err
100+
}
101+
102+
log.Printf("[DEBUG] Creating new MachineImage: %#v", obj)
103+
project, err := getProject(d, config)
104+
if err != nil {
105+
return err
106+
}
107+
res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutCreate))
108+
if err != nil {
109+
return fmt.Errorf("Error creating MachineImage: %s", err)
110+
}
111+
112+
// Store the ID now
113+
id, err := replaceVars(d, config, "projects/{{project}}/global/machineImages/{{name}}")
114+
if err != nil {
115+
return fmt.Errorf("Error constructing id: %s", err)
116+
}
117+
d.SetId(id)
118+
119+
log.Printf("[DEBUG] Finished creating MachineImage %q: %#v", d.Id(), res)
120+
121+
return resourceComputeMachineImageRead(d, meta)
122+
}
123+
124+
func resourceComputeMachineImageRead(d *schema.ResourceData, meta interface{}) error {
125+
config := meta.(*Config)
126+
127+
url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/machineImages/{{name}}")
128+
if err != nil {
129+
return err
130+
}
131+
132+
project, err := getProject(d, config)
133+
if err != nil {
134+
return err
135+
}
136+
res, err := sendRequest(config, "GET", project, url, nil)
137+
if err != nil {
138+
return handleNotFoundError(err, d, fmt.Sprintf("ComputeMachineImage %q", d.Id()))
139+
}
140+
141+
if err := d.Set("project", project); err != nil {
142+
return fmt.Errorf("Error reading MachineImage: %s", err)
143+
}
144+
145+
if err := d.Set("name", flattenComputeMachineImageName(res["name"], d, config)); err != nil {
146+
return fmt.Errorf("Error reading MachineImage: %s", err)
147+
}
148+
if err := d.Set("description", flattenComputeMachineImageDescription(res["description"], d, config)); err != nil {
149+
return fmt.Errorf("Error reading MachineImage: %s", err)
150+
}
151+
if err := d.Set("source_instance", flattenComputeMachineImageSourceInstance(res["sourceInstance"], d, config)); err != nil {
152+
return fmt.Errorf("Error reading MachineImage: %s", err)
153+
}
154+
if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil {
155+
return fmt.Errorf("Error reading MachineImage: %s", err)
156+
}
157+
158+
return nil
159+
}
160+
161+
func resourceComputeMachineImageUpdate(d *schema.ResourceData, meta interface{}) error {
162+
config := meta.(*Config)
163+
164+
project, err := getProject(d, config)
165+
if err != nil {
166+
return err
167+
}
168+
169+
obj := make(map[string]interface{})
170+
nameProp, err := expandComputeMachineImageName(d.Get("name"), d, config)
171+
if err != nil {
172+
return err
173+
} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) {
174+
obj["name"] = nameProp
175+
}
176+
descriptionProp, err := expandComputeMachineImageDescription(d.Get("description"), d, config)
177+
if err != nil {
178+
return err
179+
} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
180+
obj["description"] = descriptionProp
181+
}
182+
sourceInstanceProp, err := expandComputeMachineImageSourceInstance(d.Get("source_instance"), d, config)
183+
if err != nil {
184+
return err
185+
} else if v, ok := d.GetOkExists("source_instance"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sourceInstanceProp)) {
186+
obj["sourceInstance"] = sourceInstanceProp
187+
}
188+
189+
url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/machineImages/{{name}}")
190+
if err != nil {
191+
return err
192+
}
193+
194+
log.Printf("[DEBUG] Updating MachineImage %q: %#v", d.Id(), obj)
195+
_, err = sendRequestWithTimeout(config, "PUT", project, url, obj, d.Timeout(schema.TimeoutUpdate))
196+
197+
if err != nil {
198+
return fmt.Errorf("Error updating MachineImage %q: %s", d.Id(), err)
199+
}
200+
201+
return resourceComputeMachineImageRead(d, meta)
202+
}
203+
204+
func resourceComputeMachineImageDelete(d *schema.ResourceData, meta interface{}) error {
205+
config := meta.(*Config)
206+
207+
project, err := getProject(d, config)
208+
if err != nil {
209+
return err
210+
}
211+
212+
url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/machineImages/{{name}}")
213+
if err != nil {
214+
return err
215+
}
216+
217+
var obj map[string]interface{}
218+
log.Printf("[DEBUG] Deleting MachineImage %q", d.Id())
219+
220+
res, err := sendRequestWithTimeout(config, "DELETE", project, url, obj, d.Timeout(schema.TimeoutDelete))
221+
if err != nil {
222+
return handleNotFoundError(err, d, "MachineImage")
223+
}
224+
225+
log.Printf("[DEBUG] Finished deleting MachineImage %q: %#v", d.Id(), res)
226+
return nil
227+
}
228+
229+
func resourceComputeMachineImageImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
230+
config := meta.(*Config)
231+
if err := parseImportId([]string{
232+
"projects/(?P<project>[^/]+)/global/machineImages/(?P<name>[^/]+)",
233+
"(?P<project>[^/]+)/(?P<name>[^/]+)",
234+
"(?P<name>[^/]+)",
235+
}, d, config); err != nil {
236+
return nil, err
237+
}
238+
239+
// Replace import id for the resource id
240+
id, err := replaceVars(d, config, "projects/{{project}}/global/machineImages/{{name}}")
241+
if err != nil {
242+
return nil, fmt.Errorf("Error constructing id: %s", err)
243+
}
244+
d.SetId(id)
245+
246+
return []*schema.ResourceData{d}, nil
247+
}
248+
249+
func flattenComputeMachineImageName(v interface{}, d *schema.ResourceData, config *Config) interface{} {
250+
return v
251+
}
252+
253+
func flattenComputeMachineImageDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} {
254+
return v
255+
}
256+
257+
func flattenComputeMachineImageSourceInstance(v interface{}, d *schema.ResourceData, config *Config) interface{} {
258+
if v == nil {
259+
return v
260+
}
261+
return ConvertSelfLinkToV1(v.(string))
262+
}
263+
264+
func expandComputeMachineImageName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
265+
return v, nil
266+
}
267+
268+
func expandComputeMachineImageDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
269+
return v, nil
270+
}
271+
272+
func expandComputeMachineImageSourceInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
273+
f, err := parseZonalFieldValue("instances", v.(string), "project", "zone", d, config, true)
274+
if err != nil {
275+
return nil, fmt.Errorf("Invalid value for source_instance: %s", err)
276+
}
277+
return f.RelativeLink(), nil
278+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// ----------------------------------------------------------------------------
2+
//
3+
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
4+
//
5+
// ----------------------------------------------------------------------------
6+
//
7+
// This file is automatically generated by Magic Modules and manual
8+
// changes will be clobbered when the file is regenerated.
9+
//
10+
// Please read more about how to change this file in
11+
// .github/CONTRIBUTING.md.
12+
//
13+
// ----------------------------------------------------------------------------
14+
15+
package google
16+
17+
import (
18+
"fmt"
19+
"strings"
20+
"testing"
21+
22+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
23+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
24+
)
25+
26+
func TestAccComputeMachineImage_machineImageBasicExample(t *testing.T) {
27+
t.Parallel()
28+
29+
context := map[string]interface{}{
30+
"random_suffix": randString(t, 10),
31+
}
32+
33+
vcrTest(t, resource.TestCase{
34+
PreCheck: func() { testAccPreCheck(t) },
35+
Providers: testAccProvidersOiCS,
36+
CheckDestroy: testAccCheckComputeMachineImageDestroyProducer(t),
37+
Steps: []resource.TestStep{
38+
{
39+
Config: testAccComputeMachineImage_machineImageBasicExample(context),
40+
},
41+
},
42+
})
43+
}
44+
45+
func testAccComputeMachineImage_machineImageBasicExample(context map[string]interface{}) string {
46+
return Nprintf(`
47+
resource "google_compute_instance" "vm" {
48+
provider = google-beta
49+
name = "vm%{random_suffix}"
50+
machine_type = "n1-standard-1"
51+
52+
boot_disk {
53+
initialize_params {
54+
image = "debian-cloud/debian-9"
55+
}
56+
}
57+
58+
network_interface {
59+
network = "default"
60+
}
61+
}
62+
63+
resource "google_compute_machine_image" "image" {
64+
provider = google-beta
65+
name = "image%{random_suffix}"
66+
source_instance = google_compute_instance.vm.self_link
67+
}
68+
`, context)
69+
}
70+
71+
func testAccCheckComputeMachineImageDestroyProducer(t *testing.T) func(s *terraform.State) error {
72+
return func(s *terraform.State) error {
73+
for name, rs := range s.RootModule().Resources {
74+
if rs.Type != "google_compute_machine_image" {
75+
continue
76+
}
77+
if strings.HasPrefix(name, "data.") {
78+
continue
79+
}
80+
81+
config := googleProviderConfig(t)
82+
83+
url, err := replaceVarsForTest(config, rs, "{{ComputeBasePath}}projects/{{project}}/global/machineImages/{{name}}")
84+
if err != nil {
85+
return err
86+
}
87+
88+
_, err = sendRequest(config, "GET", "", url, nil)
89+
if err == nil {
90+
return fmt.Errorf("ComputeMachineImage still exists at %s", url)
91+
}
92+
}
93+
94+
return nil
95+
}
96+
}

0 commit comments

Comments
 (0)