Skip to content

Commit c4c26c4

Browse files
committed
Add support for Public IPs
- Add support for Public IPs (resource, data source, tests, example & docs). - Add waiting for state to update operations (in helpers.go). - Stop setting the 'assign_public_ip' property on Instances & VNIC attachments. - Make 'hostname_label' on Private IP case insensitive.
1 parent 1d8d8ee commit c4c26c4

12 files changed

+1346
-33
lines changed

crud/helpers.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ package crud
44

55
import (
66
"context"
7-
"errors"
87
"fmt"
98
"log"
109
"reflect"
@@ -216,7 +215,7 @@ func CreateDBSystemResource(d *schema.ResourceData, sync ResourceCreator) (e err
216215
}
217216
}
218217
if stateful, ok := sync.(StatefullyCreatedResource); ok {
219-
e = waitForStateRefresh(stateful, timeout, stateful.CreatedPending(), stateful.CreatedTarget())
218+
e = waitForStateRefresh(stateful, timeout, "creation", stateful.CreatedPending(), stateful.CreatedTarget())
220219
}
221220

222221
d.SetId(sync.ID())
@@ -238,7 +237,7 @@ func CreateResource(d *schema.ResourceData, sync ResourceCreator) (e error) {
238237
d.SetId(sync.ID())
239238

240239
if stateful, ok := sync.(StatefullyCreatedResource); ok {
241-
e = waitForStateRefresh(stateful, d.Timeout(schema.TimeoutCreate), stateful.CreatedPending(), stateful.CreatedTarget())
240+
e = waitForStateRefresh(stateful, d.Timeout(schema.TimeoutCreate), "creation", stateful.CreatedPending(), stateful.CreatedTarget())
242241
if stateful.State() == string(oci_load_balancer.WorkRequestLifecycleStateFailed) {
243242
// Remove resource from state if asynchronous work request has failed so that it is recreated on next apply
244243
// TODO: automatic retry on WorkRequestFailed
@@ -285,6 +284,11 @@ func UpdateResource(d *schema.ResourceData, sync ResourceUpdater) (e error) {
285284
return
286285
}
287286
d.Partial(false)
287+
288+
if stateful, ok := sync.(StatefullyUpdatedResource); ok {
289+
e = waitForStateRefresh(stateful, d.Timeout(schema.TimeoutCreate), "update", stateful.UpdatedPending(), stateful.UpdatedTarget())
290+
}
291+
288292
sync.SetData()
289293

290294
return
@@ -304,7 +308,7 @@ func DeleteResource(d *schema.ResourceData, sync ResourceDeleter) (e error) {
304308

305309
//d.SetId(sync.ID())
306310
if stateful, ok := sync.(StatefullyDeletedResource); ok {
307-
e = waitForStateRefresh(stateful, d.Timeout(schema.TimeoutDelete), stateful.DeletedPending(), stateful.DeletedTarget())
311+
e = waitForStateRefresh(stateful, d.Timeout(schema.TimeoutDelete), "deletion", stateful.DeletedPending(), stateful.DeletedTarget())
308312
}
309313

310314
if ew, waitOK := sync.(ExtraWaitPostCreateDelete); waitOK {
@@ -338,7 +342,7 @@ func stateRefreshFunc(sync StatefulResource) resource.StateRefreshFunc {
338342
//
339343
// sync.D.Id must be set.
340344
// It does not set state from that refreshed state.
341-
func waitForStateRefresh(sync StatefulResource, timeout time.Duration, pending, target []string) (e error) {
345+
func waitForStateRefresh(sync StatefulResource, timeout time.Duration, operationName string, pending, target []string) (e error) {
342346
// TODO: try to move this onto sync
343347
stateConf := &resource.StateChangeConf{
344348
Pending: pending,
@@ -352,7 +356,7 @@ func waitForStateRefresh(sync StatefulResource, timeout time.Duration, pending,
352356
return
353357
}
354358
if sync.State() == FAILED {
355-
return errors.New("Resource creation failed, state FAILED")
359+
return fmt.Errorf("Resource %s failed, state FAILED", operationName)
356360
}
357361

358362
return
@@ -396,3 +400,15 @@ func StringsToSet(ss []string) *schema.Set {
396400
}
397401
return st
398402
}
403+
404+
// NormalizeBoolString parses a string value into a bool value, and if successful, formats it back
405+
// into a string & throws an error otherwise. This allows for normalizing the different formats of
406+
// valid bool strings (e.g. "1", "false", "TRUE", "F", etc.) to a uniform string representation of
407+
// a boolean value ("true" & "false").
408+
func NormalizeBoolString(v string) (string, error) {
409+
boolVal, err := strconv.ParseBool(v)
410+
if err != nil {
411+
return "", err
412+
}
413+
return strconv.FormatBool(boolVal), nil
414+
}

docs/core/public_ips.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# oci_core_public_ip
2+
3+
## PublicIp Resource
4+
5+
### PublicIp Reference
6+
7+
The following attributes are exported:
8+
9+
* `availability_domain` - The public IP's Availability Domain. This property is set only for ephemeral public IPs (that is, when the `scope` of the public IP is set to AVAILABILITY_DOMAIN). The value is the Availability Domain of the assigned private IP. Example: `Uocm:PHX-AD-1`
10+
* `compartment_id` - The OCID of the compartment containing the public IP. For an ephemeral public IP, this is the same compartment as the private IP's. For a reserved public IP that is currently assigned, this can be a different compartment than the assigned private IP's.
11+
* `display_name` - A user-friendly name. Does not have to be unique, and it's changeable. Avoid entering confidential information.
12+
* `id` - The public IP's Oracle ID (OCID).
13+
* `ip_address` - The public IP address of the `publicIp` object. Example: `129.146.2.1`
14+
* `lifetime` - Defines when the public IP is deleted and released back to Oracle's public IP pool.
15+
* `EPHEMERAL`: The lifetime is tied to the lifetime of its assigned private IP. The ephemeral public IP is automatically deleted when its private IP is deleted, when the VNIC is terminated, or when the instance is terminated. An ephemeral public IP must always be assigned to a private IP.
16+
* `RESERVED`: You control the public IP's lifetime. You can delete a reserved public IP whenever you like. It does not need to be assigned to a private IP at all times.
17+
For more information and comparison of the two types, see [Public IP Addresses](https://docs.us-phoenix-1.oraclecloud.com/Content/Network/Tasks/managingpublicIPs.htm).
18+
* `private_ip_id` - The OCID of the private IP that the public IP is currently assigned to, or in the process of being assigned to.
19+
* `scope` - Whether the public IP is regional or specific to a particular Availability Domain.
20+
* `REGION`: The public IP exists within a region and can be assigned to a private IP in any Availability Domain in the region. Reserved public IPs have `scope` = `REGION`.
21+
* `AVAILABILITY_DOMAIN`: The public IP exists within the Availability Domain of the private IP it's assigned to, which is specified by the `availabilityDomain` property of the public IP object. Ephemeral public IPs have `scope` = `AVAILABILITY_DOMAIN`.
22+
* `state` - The public IP's current state.
23+
* `time_created` - The date and time the public IP was created, in the format defined by RFC3339. Example: `2016-08-25T21:10:29.600Z`
24+
25+
26+
27+
### Create Operation
28+
Creates a public IP. Use the `lifetime` property to specify whether it's an ephemeral or
29+
reserved public IP. For information about limits on how many you can create, see
30+
[Public IP Addresses](https://docs.us-phoenix-1.oraclecloud.com/Content/Network/Tasks/managingpublicIPs.htm).
31+
32+
* **For an ephemeral public IP:** You must also specify a `privateIpId` with the OCID of
33+
the primary private IP you want to assign the public IP to. The public IP is created in
34+
the same Availability Domain as the private IP. An ephemeral public IP must always be
35+
assigned to a private IP, and only to the *primary* private IP on a VNIC, not a secondary
36+
private IP.
37+
38+
* **For a reserved public IP:** You may also optionally assign the public IP to a private
39+
IP by specifying `privateIpId`. Or you can later assign the public IP with
40+
[UpdatePublicIp](https://docs.us-phoenix-1.oraclecloud.com/api/#/en/iaas/20160918/PublicIp/UpdatePublicIp).
41+
42+
**Note:** When assigning a public IP to a private IP, the private IP must not already have
43+
a public IP with `lifecycleState` = ASSIGNING or ASSIGNED. If it does, an error is returned.
44+
45+
Also, for reserved public IPs, the optional assignment part of this operation is
46+
asynchronous. Poll the public IP's `lifecycleState` to determine if the assignment
47+
succeeded.
48+
49+
50+
The following arguments are supported:
51+
52+
* `compartment_id` - (Required) The OCID of the compartment to contain the public IP. For ephemeral public IPs, you must set this to the private IP's compartment OCID.
53+
* `display_name` - (Optional) A user-friendly name. Does not have to be unique, and it's changeable. Avoid entering confidential information.
54+
* `lifetime` - (Required) Defines when the public IP is deleted and released back to the Oracle Cloud Infrastructure public IP pool. For more information, see [Public IP Addresses](https://docs.us-phoenix-1.oraclecloud.com/Content/Network/Tasks/managingpublicIPs.htm).
55+
* `private_ip_id` - (Optional) The OCID of the private IP to assign the public IP to. Required for an ephemeral public IP because it must always be assigned to a private IP (specifically a *primary* private IP). Optional for a reserved public IP. If you don't provide it, the public IP is created but not assigned to a private IP. You can later assign the public IP with [UpdatePublicIp](https://docs.us-phoenix-1.oraclecloud.com/api/#/en/iaas/20160918/PublicIp/UpdatePublicIp).
56+
57+
58+
### Update Operation
59+
Updates the specified public IP. You must specify the object's OCID. Use this operation if you want to:
60+
61+
* Assign a reserved public IP in your pool to a private IP.
62+
* Move a reserved public IP to a different private IP.
63+
* Unassign a reserved public IP from a private IP (which returns it to your pool
64+
of reserved public IPs).
65+
* Change the display name for a public IP (either ephemeral or reserved).
66+
67+
Assigning, moving, and unassigning a reserved public IP are asynchronous
68+
operations. Poll the public IP's `lifecycleState` to determine if the operation
69+
succeeded.
70+
71+
**Note:** When moving a reserved public IP, the target private IP
72+
must not already have a public IP with `lifecycleState` = ASSIGNING or ASSIGNED. If it
73+
does, an error is returned. Also, the initial unassignment from the original
74+
private IP always succeeds, but the assignment to the target private IP is asynchronous and
75+
could fail silently (for example, if the target private IP is deleted or has a different public IP
76+
assigned to it in the interim). If that occurs, the public IP remains unassigned and its
77+
`lifecycleState` switches to AVAILABLE (it is not reassigned to its original private IP).
78+
You must poll the public IP's `lifecycleState` to determine if the move succeeded.
79+
80+
Regarding ephemeral public IPs:
81+
82+
* If you want to assign an ephemeral public IP to a primary private IP, use
83+
[CreatePublicIp](https://docs.us-phoenix-1.oraclecloud.com/api/#/en/iaas/20160918/PublicIp/CreatePublicIp).
84+
* You can't move an ephemeral public IP to a different private IP.
85+
* If you want to unassign an ephemeral public IP from its private IP, use
86+
[DeletePublicIp](https://docs.us-phoenix-1.oraclecloud.com/api/#/en/iaas/20160918/PublicIp/DeletePublicIp), which
87+
unassigns and deletes the ephemeral public IP.
88+
89+
**Note:** If a public IP (either ephemeral or reserved) is assigned to a secondary private
90+
IP (see [PrivateIp](https://docs.us-phoenix-1.oraclecloud.com/api/#/en/iaas/20160918/PrivateIp)), and you move that secondary
91+
private IP to another VNIC, the public IP moves with it.
92+
93+
**Note:** There's a limit to the number of [public IPs](https://docs.us-phoenix-1.oraclecloud.com/api/#/en/iaas/20160918/PublicIp/)
94+
a VNIC or instance can have. If you try to move a reserved public IP
95+
to a VNIC or instance that has already reached its public IP limit, an error is
96+
returned. For information about the public IP limits, see
97+
[Public IP Addresses](https://docs.us-phoenix-1.oraclecloud.com/Content/Network/Tasks/managingpublicIPs.htm).
98+
99+
100+
The following arguments support updates:
101+
* `display_name` - A user-friendly name. Does not have to be unique, and it's changeable. Avoid entering confidential information.
102+
* `private_ip_id` - The OCID of the private IP to assign the public IP to. Required for an ephemeral public IP because it must always be assigned to a private IP (specifically a *primary* private IP). Optional for a reserved public IP. If you don't provide it, the public IP is created but not assigned to a private IP. You can later assign the public IP with [UpdatePublicIp](https://docs.us-phoenix-1.oraclecloud.com/api/#/en/iaas/20160918/PublicIp/UpdatePublicIp).
103+
104+
105+
** IMPORTANT **
106+
Any change to a property that does not support update will force the destruction and recreation of the resource with the new property values
107+
108+
### Example Usage
109+
110+
```
111+
resource "oci_core_public_ip" "test_public_ip" {
112+
#Required
113+
compartment_id = "${var.compartment_id}"
114+
lifetime = "${var.public_ip_lifetime}"
115+
116+
#Optional
117+
display_name = "${var.public_ip_display_name}"
118+
private_ip_id = "${oci_core_private_ip.test_private_ip.id}"
119+
}
120+
```
121+
122+
# oci_core_public_ips
123+
124+
## PublicIp DataSource
125+
126+
Gets a list of public_ips.
127+
128+
### List Operation
129+
Lists either the ephemeral or reserved [PublicIp](https://docs.us-phoenix-1.oraclecloud.com/api/#/en/iaas/20160918/PublicIp/) objects
130+
in the specified compartment.
131+
132+
To list your reserved public IPs, set `scope` = `REGION`, and leave the
133+
`availabilityDomain` parameter empty.
134+
135+
To list your ephemeral public IPs, set `scope` = `AVAILABILITY_DOMAIN`, and set the
136+
`availabilityDomain` parameter to the desired Availability Domain. An ephemeral public IP
137+
is always in the same Availability Domain and compartment as the private IP it's assigned to.
138+
139+
The following arguments are supported:
140+
141+
* `availability_domain` - (Optional) The name of the Availability Domain. Example: `Uocm:PHX-AD-1`
142+
* `compartment_id` - (Required) The OCID of the compartment.
143+
* `scope` - (Required) Whether the public IP is regional or specific to a particular Availability Domain.
144+
* `REGION`: The public IP exists within a region and can be assigned to a private IP in any Availability Domain in the region. Reserved public IPs have `scope` = `REGION`.
145+
* `AVAILABILITY_DOMAIN`: The public IP exists within the Availability Domain of the private IP it's assigned to, which is specified by the `availabilityDomain` property of the public IP object. Ephemeral public IPs have `scope` = `AVAILABILITY_DOMAIN`.
146+
147+
148+
The following attributes are exported:
149+
150+
* `public_ips` - The list of public_ips.
151+
152+
### Example Usage
153+
154+
```
155+
data "oci_core_public_ips" "test_public_ips" {
156+
#Required
157+
compartment_id = "${var.compartment_id}"
158+
scope = "${var.public_ip_scope}"
159+
160+
#Optional
161+
availability_domain = "${var.public_ip_availability_domain}"
162+
}
163+
```

0 commit comments

Comments
 (0)