1// Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
2//
3// Example code for Core Services API
4//
5
6package example
7
8import (
9	"context"
10	"fmt"
11	"log"
12
13	"github.com/oracle/oci-go-sdk/common"
14	"github.com/oracle/oci-go-sdk/core"
15	"github.com/oracle/oci-go-sdk/example/helpers"
16)
17
18const (
19	vcnDisplayName     = "OCI-GOSDK-Sample-VCN"
20	subnetDisplayName1 = "OCI-GOSDK-Sample-Subnet1"
21	subnetDisplayName2 = "OCI-GOSDK-Sample-Subnet2"
22	subnetDisplayName3 = "OCI-GOSDK-Sample-Subnet3"
23
24	// replace following variables with your instance info
25	// this is used by ExampleCreateImageDetails_Polymorphic
26	objectStorageURIWtihImage = "[The Object Storage URL for the image which will be used to create an image.]"
27)
28
29// ExampleLaunchInstance does create an instance
30// NOTE: launch instance will create a new instance and VCN. please make sure delete the instance
31// after execute this sample code, otherwise, you will be charged for the running instance
32func ExampleLaunchInstance() {
33	c, err := core.NewComputeClientWithConfigurationProvider(common.DefaultConfigProvider())
34	helpers.FatalIfError(err)
35	ctx := context.Background()
36
37	// create the launch instance request
38	request := core.LaunchInstanceRequest{}
39	request.CompartmentId = helpers.CompartmentID()
40	request.DisplayName = common.String("OCI-Sample-Instance")
41	request.AvailabilityDomain = helpers.AvailabilityDomain()
42
43	// create a subnet or get the one already created
44	subnet := CreateOrGetSubnet()
45	fmt.Println("subnet created")
46	request.SubnetId = subnet.Id
47
48	// get a image
49	image := listImages(ctx, c)[30]
50	fmt.Println("list images")
51	request.ImageId = image.Id
52
53	// get all the shapes and filter the list by compatibility with the image
54	shapes := listShapes(ctx, c, request.ImageId)
55	fmt.Println("list shapes")
56	request.Shape = shapes[1].Shape
57
58	// default retry policy will retry on non-200 response
59	request.RequestMetadata = helpers.GetRequestMetadataWithDefaultRetryPolicy()
60
61	createResp, err := c.LaunchInstance(ctx, request)
62	helpers.FatalIfError(err)
63
64	fmt.Println("launching instance")
65
66	// should retry condition check which returns a bool value indicating whether to do retry or not
67	// it checks the lifecycle status equals to Running or not for this case
68	shouldRetryFunc := func(r common.OCIOperationResponse) bool {
69		if converted, ok := r.Response.(core.GetInstanceResponse); ok {
70			return converted.LifecycleState != core.InstanceLifecycleStateRunning
71		}
72		return true
73	}
74
75	// create get instance request with a retry policy which takes a function
76	// to determine shouldRetry or not
77	pollingGetRequest := core.GetInstanceRequest{
78		InstanceId:      createResp.Instance.Id,
79		RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
80	}
81
82	instance, pollError := c.GetInstance(ctx, pollingGetRequest)
83	helpers.FatalIfError(pollError)
84
85	fmt.Println("instance launched")
86
87	attachVnicResponse, err := c.AttachVnic(context.Background(), core.AttachVnicRequest{
88		AttachVnicDetails: core.AttachVnicDetails{
89			CreateVnicDetails: &core.CreateVnicDetails{
90				SubnetId:       subnet.Id,
91				AssignPublicIp: common.Bool(true),
92			},
93			InstanceId: instance.Id,
94		},
95	})
96
97	helpers.FatalIfError(err)
98	fmt.Println("vnic attached")
99
100	_, err = c.DetachVnic(context.Background(), core.DetachVnicRequest{
101		VnicAttachmentId: attachVnicResponse.Id,
102	})
103
104	helpers.FatalIfError(err)
105	fmt.Println("vnic dettached")
106
107	defer func() {
108		terminateInstance(ctx, c, createResp.Id)
109
110		client, clerr := core.NewVirtualNetworkClientWithConfigurationProvider(common.DefaultConfigProvider())
111		helpers.FatalIfError(clerr)
112
113		vcnID := subnet.VcnId
114		deleteSubnet(ctx, client, subnet.Id)
115		deleteVcn(ctx, client, vcnID)
116	}()
117
118	// Output:
119	// subnet created
120	// list images
121	// list shapes
122	// launching instance
123	// instance launched
124	// vnic attached
125	// vnic dettached
126	// terminating instance
127	// instance terminated
128	// deleteing subnet
129	// subnet deleted
130	// deleteing VCN
131	// VCN deleted
132}
133
134// ExampleCreateImageDetails_Polymorphic creates a boot disk image for the specified instance or
135// imports an exported image from the Oracle Cloud Infrastructure Object Storage service.
136func ExampleCreateImageDetails_Polymorphic() {
137	request := core.CreateImageRequest{}
138	request.CompartmentId = helpers.CompartmentID()
139
140	// you can import an image based on the Object Storage URL 'core.ImageSourceViaObjectStorageUriDetails'
141	// or based on the namespace, bucket name and object name 'core.ImageSourceViaObjectStorageTupleDetails'
142	// following example shows how to import image from object storage uri, you can use another one:
143	// request.ImageSourceDetails = core.ImageSourceViaObjectStorageTupleDetails
144	sourceDetails := core.ImageSourceViaObjectStorageUriDetails{}
145	sourceDetails.SourceUri = common.String(objectStorageURIWtihImage)
146
147	request.ImageSourceDetails = sourceDetails
148
149	c, err := core.NewComputeClientWithConfigurationProvider(common.DefaultConfigProvider())
150	helpers.FatalIfError(err)
151
152	_, err = c.CreateImage(context.Background(), request)
153	helpers.FatalIfError(err)
154	fmt.Println("image created")
155}
156
157// CreateOrGetVcn either creates a new Virtual Cloud Network (VCN) or get the one already exist
158func CreateOrGetVcn() core.Vcn {
159	c, clerr := core.NewVirtualNetworkClientWithConfigurationProvider(common.DefaultConfigProvider())
160	helpers.FatalIfError(clerr)
161	ctx := context.Background()
162
163	vcnItems := listVcns(ctx, c)
164
165	for _, element := range vcnItems {
166		if *element.DisplayName == vcnDisplayName {
167			// VCN already created, return it
168			return element
169		}
170	}
171
172	// create a new VCN
173	request := core.CreateVcnRequest{}
174	request.CidrBlock = common.String("10.0.0.0/16")
175	request.CompartmentId = helpers.CompartmentID()
176	request.DisplayName = common.String(vcnDisplayName)
177	request.DnsLabel = common.String("vcndns")
178
179	r, err := c.CreateVcn(ctx, request)
180	helpers.FatalIfError(err)
181	return r.Vcn
182}
183
184// CreateSubnet creates a new subnet or get the one already exist
185func CreateOrGetSubnet() core.Subnet {
186	return CreateOrGetSubnetWithDetails(
187		common.String(subnetDisplayName1),
188		common.String("10.0.0.0/24"),
189		common.String("subnetdns1"),
190		helpers.AvailabilityDomain())
191}
192
193// CreateOrGetSubnetWithDetails either creates a new Virtual Cloud Network (VCN) or get the one already exist
194// with detail info
195func CreateOrGetSubnetWithDetails(displayName *string, cidrBlock *string, dnsLabel *string, availableDomain *string) core.Subnet {
196	c, clerr := core.NewVirtualNetworkClientWithConfigurationProvider(common.DefaultConfigProvider())
197	helpers.FatalIfError(clerr)
198	ctx := context.Background()
199
200	subnets := listSubnets(ctx, c)
201
202	if displayName == nil {
203		displayName = common.String(subnetDisplayName1)
204	}
205
206	// check if the subnet has already been created
207	for _, element := range subnets {
208		if *element.DisplayName == *displayName {
209			// find the subnet, return it
210			return element
211		}
212	}
213
214	// create a new subnet
215	request := core.CreateSubnetRequest{}
216	request.AvailabilityDomain = availableDomain
217	request.CompartmentId = helpers.CompartmentID()
218	request.CidrBlock = cidrBlock
219	request.DisplayName = displayName
220	request.DnsLabel = dnsLabel
221	request.RequestMetadata = helpers.GetRequestMetadataWithDefaultRetryPolicy()
222
223	vcn := CreateOrGetVcn()
224	request.VcnId = vcn.Id
225
226	r, err := c.CreateSubnet(ctx, request)
227	helpers.FatalIfError(err)
228
229	// retry condition check, stop unitl return true
230	pollUntilAvailable := func(r common.OCIOperationResponse) bool {
231		if converted, ok := r.Response.(core.GetSubnetResponse); ok {
232			return converted.LifecycleState != core.SubnetLifecycleStateAvailable
233		}
234		return true
235	}
236
237	pollGetRequest := core.GetSubnetRequest{
238		SubnetId:        r.Id,
239		RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(pollUntilAvailable),
240	}
241
242	// wait for lifecyle become running
243	_, pollErr := c.GetSubnet(ctx, pollGetRequest)
244	helpers.FatalIfError(pollErr)
245
246	// update the security rules
247	getReq := core.GetSecurityListRequest{
248		SecurityListId: common.String(r.SecurityListIds[0]),
249	}
250
251	getResp, err := c.GetSecurityList(ctx, getReq)
252	helpers.FatalIfError(err)
253
254	// this security rule allows remote control the instance
255	portRange := core.PortRange{
256		Max: common.Int(1521),
257		Min: common.Int(1521),
258	}
259
260	newRules := append(getResp.IngressSecurityRules, core.IngressSecurityRule{
261		Protocol: common.String("6"), // TCP
262		Source:   common.String("0.0.0.0/0"),
263		TcpOptions: &core.TcpOptions{
264			DestinationPortRange: &portRange,
265		},
266	})
267
268	updateReq := core.UpdateSecurityListRequest{
269		SecurityListId: common.String(r.SecurityListIds[0]),
270	}
271
272	updateReq.IngressSecurityRules = newRules
273
274	_, err = c.UpdateSecurityList(ctx, updateReq)
275	helpers.FatalIfError(err)
276
277	return r.Subnet
278}
279
280func listVcns(ctx context.Context, c core.VirtualNetworkClient) []core.Vcn {
281	request := core.ListVcnsRequest{
282		CompartmentId: helpers.CompartmentID(),
283	}
284
285	r, err := c.ListVcns(ctx, request)
286	helpers.FatalIfError(err)
287	return r.Items
288}
289
290func listSubnets(ctx context.Context, c core.VirtualNetworkClient) []core.Subnet {
291	vcn := CreateOrGetVcn()
292
293	request := core.ListSubnetsRequest{
294		CompartmentId: helpers.CompartmentID(),
295		VcnId:         vcn.Id,
296	}
297
298	r, err := c.ListSubnets(ctx, request)
299	helpers.FatalIfError(err)
300	return r.Items
301}
302
303// ListImages lists the available images in the specified compartment.
304func listImages(ctx context.Context, c core.ComputeClient) []core.Image {
305	request := core.ListImagesRequest{
306		CompartmentId: helpers.CompartmentID(),
307	}
308
309	r, err := c.ListImages(ctx, request)
310	helpers.FatalIfError(err)
311
312	return r.Items
313}
314
315// ListShapes Lists the shapes that can be used to launch an instance within the specified compartment.
316func listShapes(ctx context.Context, c core.ComputeClient, imageID *string) []core.Shape {
317	request := core.ListShapesRequest{
318		CompartmentId: helpers.CompartmentID(),
319		ImageId:       imageID,
320	}
321
322	r, err := c.ListShapes(ctx, request)
323	helpers.FatalIfError(err)
324
325	if r.Items == nil || len(r.Items) == 0 {
326		log.Fatalln("Invalid response from ListShapes")
327	}
328
329	return r.Items
330}
331
332func terminateInstance(ctx context.Context, c core.ComputeClient, id *string) {
333	request := core.TerminateInstanceRequest{
334		InstanceId:      id,
335		RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
336	}
337
338	_, err := c.TerminateInstance(ctx, request)
339	helpers.FatalIfError(err)
340
341	fmt.Println("terminating instance")
342
343	// should retry condition check which returns a bool value indicating whether to do retry or not
344	// it checks the lifecycle status equals to Terminated or not for this case
345	shouldRetryFunc := func(r common.OCIOperationResponse) bool {
346		if converted, ok := r.Response.(core.GetInstanceResponse); ok {
347			return converted.LifecycleState != core.InstanceLifecycleStateTerminated
348		}
349		return true
350	}
351
352	pollGetRequest := core.GetInstanceRequest{
353		InstanceId:      id,
354		RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
355	}
356
357	_, pollErr := c.GetInstance(ctx, pollGetRequest)
358	helpers.FatalIfError(pollErr)
359	fmt.Println("instance terminated")
360}
361
362func deleteVcn(ctx context.Context, c core.VirtualNetworkClient, id *string) {
363	request := core.DeleteVcnRequest{
364		VcnId:           id,
365		RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
366	}
367
368	fmt.Println("deleteing VCN")
369	_, err := c.DeleteVcn(ctx, request)
370	helpers.FatalIfError(err)
371
372	// should retry condition check which returns a bool value indicating whether to do retry or not
373	// it checks the lifecycle status equals to Terminated or not for this case
374	shouldRetryFunc := func(r common.OCIOperationResponse) bool {
375		if serviceError, ok := common.IsServiceError(r.Error); ok && serviceError.GetHTTPStatusCode() == 404 {
376			// resource been deleted, stop retry
377			return false
378		}
379
380		if converted, ok := r.Response.(core.GetVcnResponse); ok {
381			return converted.LifecycleState != core.VcnLifecycleStateTerminated
382		}
383		return true
384	}
385
386	pollGetRequest := core.GetVcnRequest{
387		VcnId:           id,
388		RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
389	}
390
391	_, pollErr := c.GetVcn(ctx, pollGetRequest)
392	if serviceError, ok := common.IsServiceError(pollErr); !ok ||
393		(ok && serviceError.GetHTTPStatusCode() != 404) {
394		// fail if the error is not service error or
395		// if the error is service error and status code not equals to 404
396		helpers.FatalIfError(pollErr)
397	}
398	fmt.Println("VCN deleted")
399}
400
401func deleteSubnet(ctx context.Context, c core.VirtualNetworkClient, id *string) {
402	request := core.DeleteSubnetRequest{
403		SubnetId:        id,
404		RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
405	}
406
407	_, err := c.DeleteSubnet(context.Background(), request)
408	helpers.FatalIfError(err)
409
410	fmt.Println("deleteing subnet")
411
412	// should retry condition check which returns a bool value indicating whether to do retry or not
413	// it checks the lifecycle status equals to Terminated or not for this case
414	shouldRetryFunc := func(r common.OCIOperationResponse) bool {
415		if serviceError, ok := common.IsServiceError(r.Error); ok && serviceError.GetHTTPStatusCode() == 404 {
416			// resource been deleted
417			return false
418		}
419
420		if converted, ok := r.Response.(core.GetSubnetResponse); ok {
421			return converted.LifecycleState != core.SubnetLifecycleStateTerminated
422		}
423		return true
424	}
425
426	pollGetRequest := core.GetSubnetRequest{
427		SubnetId:        id,
428		RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
429	}
430
431	_, pollErr := c.GetSubnet(ctx, pollGetRequest)
432	if serviceError, ok := common.IsServiceError(pollErr); !ok ||
433		(ok && serviceError.GetHTTPStatusCode() != 404) {
434		// fail if the error is not service error or
435		// if the error is service error and status code not equals to 404
436		helpers.FatalIfError(pollErr)
437	}
438
439	fmt.Println("subnet deleted")
440}
441