Skip to content

Commit 1a6f416

Browse files
committed
Singular datasource support for Instances
1 parent e0e44d2 commit 1a6f416

File tree

5 files changed

+532
-1
lines changed

5 files changed

+532
-1
lines changed

oci/core_instance_data_source.go

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
2+
3+
package provider
4+
5+
import (
6+
"context"
7+
8+
"log"
9+
10+
"github.com/hashicorp/terraform/helper/schema"
11+
"github.com/hashicorp/terraform/helper/validation"
12+
oci_core "github.com/oracle/oci-go-sdk/core"
13+
)
14+
15+
func InstanceDataSource() *schema.Resource {
16+
return &schema.Resource{
17+
Read: readSingularInstance,
18+
Schema: map[string]*schema.Schema{
19+
"instance_id": {
20+
Type: schema.TypeString,
21+
Required: true,
22+
},
23+
// Computed
24+
"availability_domain": {
25+
Type: schema.TypeString,
26+
Computed: true,
27+
},
28+
"compartment_id": {
29+
Type: schema.TypeString,
30+
Computed: true,
31+
},
32+
"defined_tags": {
33+
Type: schema.TypeMap,
34+
Computed: true,
35+
Elem: schema.TypeString,
36+
},
37+
"display_name": {
38+
Type: schema.TypeString,
39+
Computed: true,
40+
},
41+
"extended_metadata": {
42+
Type: schema.TypeMap,
43+
Computed: true,
44+
Elem: schema.TypeString,
45+
},
46+
"fault_domain": {
47+
Type: schema.TypeString,
48+
Computed: true,
49+
},
50+
"freeform_tags": {
51+
Type: schema.TypeMap,
52+
Computed: true,
53+
Elem: schema.TypeString,
54+
},
55+
"image": {
56+
Type: schema.TypeString,
57+
Computed: true,
58+
},
59+
"ipxe_script": {
60+
Type: schema.TypeString,
61+
Computed: true,
62+
},
63+
"launch_mode": {
64+
Type: schema.TypeString,
65+
Computed: true,
66+
},
67+
"launch_options": {
68+
Type: schema.TypeList,
69+
Computed: true,
70+
Elem: &schema.Resource{
71+
Schema: map[string]*schema.Schema{
72+
// Required
73+
74+
// Optional
75+
76+
// Computed
77+
"boot_volume_type": {
78+
Type: schema.TypeString,
79+
Computed: true,
80+
},
81+
"firmware": {
82+
Type: schema.TypeString,
83+
Computed: true,
84+
},
85+
"network_type": {
86+
Type: schema.TypeString,
87+
Computed: true,
88+
},
89+
"remote_data_volume_type": {
90+
Type: schema.TypeString,
91+
Computed: true,
92+
},
93+
},
94+
},
95+
},
96+
"metadata": {
97+
Type: schema.TypeMap,
98+
Computed: true,
99+
Elem: schema.TypeString,
100+
},
101+
"region": {
102+
Type: schema.TypeString,
103+
Computed: true,
104+
},
105+
"shape": {
106+
Type: schema.TypeString,
107+
Computed: true,
108+
},
109+
"source_details": {
110+
Type: schema.TypeList,
111+
Computed: true,
112+
Elem: &schema.Resource{
113+
Schema: map[string]*schema.Schema{
114+
// Required
115+
"source_id": {
116+
Type: schema.TypeString,
117+
Required: true,
118+
ForceNew: true,
119+
},
120+
"source_type": {
121+
Type: schema.TypeString,
122+
Required: true,
123+
ForceNew: true,
124+
DiffSuppressFunc: EqualIgnoreCaseSuppressDiff,
125+
ValidateFunc: validation.StringInSlice([]string{
126+
"bootVolume",
127+
"image",
128+
}, true),
129+
},
130+
131+
// Optional
132+
"boot_volume_size_in_gbs": {
133+
Type: schema.TypeString,
134+
Optional: true,
135+
Computed: true,
136+
ForceNew: true,
137+
ValidateFunc: validateInt64TypeString,
138+
DiffSuppressFunc: int64StringDiffSuppressFunction,
139+
},
140+
141+
// Computed
142+
},
143+
},
144+
},
145+
"state": {
146+
Type: schema.TypeString,
147+
Computed: true,
148+
},
149+
"time_created": {
150+
Type: schema.TypeString,
151+
Computed: true,
152+
},
153+
// Legacy custom computed convenience values
154+
"public_ip": {
155+
Type: schema.TypeString,
156+
Computed: true,
157+
},
158+
"private_ip": {
159+
Type: schema.TypeString,
160+
Computed: true,
161+
},
162+
"hostname_label": {
163+
Type: schema.TypeString,
164+
Computed: true,
165+
},
166+
"subnet_id": {
167+
Type: schema.TypeString,
168+
Computed: true,
169+
},
170+
// Add this computed boot_volume_id field even though it's not part of the API specs. This will make it easier to
171+
// discover the attached boot volume's ID; to preserve it for reattachment.
172+
"boot_volume_id": {
173+
Type: schema.TypeString,
174+
Computed: true,
175+
},
176+
},
177+
}
178+
}
179+
180+
func readSingularInstance(d *schema.ResourceData, m interface{}) error {
181+
sync := &InstanceDataSourceCrud{}
182+
sync.D = d
183+
sync.Client = m.(*OracleClients).computeClient
184+
sync.VirtualNetworkClient = m.(*OracleClients).virtualNetworkClient
185+
sync.BlockStorageClient = m.(*OracleClients).blockstorageClient
186+
187+
return ReadResource(sync)
188+
}
189+
190+
type InstanceDataSourceCrud struct {
191+
InstanceResourceCrud
192+
}
193+
194+
func (s *InstanceDataSourceCrud) VoidState() {
195+
s.D.SetId("")
196+
}
197+
198+
func (s *InstanceDataSourceCrud) Get() error {
199+
request := oci_core.GetInstanceRequest{}
200+
201+
if instanceId, ok := s.D.GetOkExists("instance_id"); ok {
202+
tmp := instanceId.(string)
203+
request.InstanceId = &tmp
204+
}
205+
206+
request.RequestMetadata.RetryPolicy = getRetryPolicy(false, "core")
207+
208+
response, err := s.Client.GetInstance(context.Background(), request)
209+
if err != nil {
210+
return err
211+
}
212+
213+
s.Res = &response.Instance
214+
return nil
215+
}
216+
217+
func (s *InstanceDataSourceCrud) SetData() error {
218+
if s.Res == nil {
219+
return nil
220+
}
221+
222+
s.D.SetId(*s.Res.Id)
223+
224+
if s.Res.AvailabilityDomain != nil {
225+
s.D.Set("availability_domain", *s.Res.AvailabilityDomain)
226+
}
227+
228+
if s.Res.CompartmentId != nil {
229+
s.D.Set("compartment_id", *s.Res.CompartmentId)
230+
}
231+
232+
if s.Res.DefinedTags != nil {
233+
s.D.Set("defined_tags", definedTagsToMap(s.Res.DefinedTags))
234+
}
235+
236+
if s.Res.DisplayName != nil {
237+
s.D.Set("display_name", *s.Res.DisplayName)
238+
}
239+
240+
// Extended metadata (a json blob) may not return with the same node order in which it
241+
// was originally created, the solution is to not set it here after subsequent GETS to
242+
// prevent inadvertent diffs or destroy/creates
243+
// if s.Res.ExtendedMetadata != nil {
244+
// // extended_metadata is an arbitrarily structured json object, `objectToMap` would not work
245+
// s.D.Set("extended_metadata", []interface{}{objectToMap(s.Res.ExtendedMetadata)})
246+
// }
247+
248+
if s.Res.FaultDomain != nil {
249+
s.D.Set("fault_domain", *s.Res.FaultDomain)
250+
}
251+
252+
s.D.Set("freeform_tags", s.Res.FreeformTags)
253+
254+
if s.Res.ImageId != nil {
255+
// @CODEGEN 1/2018: support legacy name "image"
256+
s.D.Set("image", *s.Res.ImageId)
257+
}
258+
259+
if s.Res.IpxeScript != nil {
260+
s.D.Set("ipxe_script", *s.Res.IpxeScript)
261+
}
262+
263+
s.D.Set("launch_mode", s.Res.LaunchMode)
264+
265+
if s.Res.LaunchOptions != nil {
266+
s.D.Set("launch_options", []interface{}{LaunchOptionsToMap(s.Res.LaunchOptions)})
267+
} else {
268+
s.D.Set("launch_options", nil)
269+
}
270+
271+
if s.Res.Metadata != nil {
272+
err := s.D.Set("metadata", s.Res.Metadata)
273+
if err != nil {
274+
log.Printf("error setting metadata %q", err)
275+
}
276+
}
277+
278+
if s.Res.Region != nil {
279+
s.D.Set("region", *s.Res.Region)
280+
}
281+
282+
if s.Res.Shape != nil {
283+
s.D.Set("shape", *s.Res.Shape)
284+
}
285+
286+
bootVolume, bootVolumeErr := s.getBootVolume()
287+
if bootVolumeErr != nil {
288+
log.Printf("[WARN] Could not get the boot volume: %q", bootVolumeErr)
289+
}
290+
291+
if s.Res.SourceDetails != nil {
292+
var sourceDetailsFromConfig map[string]interface{}
293+
if details, ok := s.D.GetOkExists("source_details"); ok {
294+
if tmpList := details.([]interface{}); len(tmpList) > 0 {
295+
sourceDetailsFromConfig = tmpList[0].(map[string]interface{})
296+
}
297+
}
298+
sourceDetailsArray := []interface{}{}
299+
if sourceDetailsMap := InstanceSourceDetailsToMap(&s.Res.SourceDetails, bootVolume, sourceDetailsFromConfig); sourceDetailsMap != nil {
300+
sourceDetailsArray = append(sourceDetailsArray, sourceDetailsMap)
301+
}
302+
err := s.D.Set("source_details", sourceDetailsArray)
303+
if err != nil {
304+
return err
305+
}
306+
} else {
307+
s.D.Set("source_details", nil)
308+
}
309+
310+
if bootVolume != nil && bootVolume.Id != nil {
311+
s.D.Set("boot_volume_id", *bootVolume.Id)
312+
}
313+
314+
s.D.Set("state", s.Res.LifecycleState)
315+
316+
if s.Res.TimeCreated != nil {
317+
s.D.Set("time_created", s.Res.TimeCreated.String())
318+
}
319+
320+
if s.Res.LifecycleState == oci_core.InstanceLifecycleStateRunning {
321+
vnic, vnicError := s.getPrimaryVnic()
322+
if vnicError != nil || vnic == nil {
323+
log.Printf("[WARN] Primary VNIC could not be found during instance refresh: %q", vnicError)
324+
} else {
325+
s.D.Set("hostname_label", vnic.HostnameLabel)
326+
s.D.Set("public_ip", vnic.PublicIp)
327+
s.D.Set("private_ip", vnic.PrivateIp)
328+
s.D.Set("subnet_id", vnic.SubnetId)
329+
}
330+
}
331+
332+
return nil
333+
}

0 commit comments

Comments
 (0)