Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature subnet #156

Closed
wants to merge 12 commits into from
109 changes: 109 additions & 0 deletions docs/resources/softlayer_subnet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#### `softlayer_subnet`

`softlayer_subnet` provides portable and static subnets that consist of either IPv4 and IPv6 addresses. Users are able to create
public portable subnets, private portable subnets, and public static subnets with an IPv4 option and public portable subnets and public static
subnets with an IPv6 option.

The portable IPv4 subnet is created as a seconday subnet on a VLAN. IP addresses in the portable subnet can be assigned as secondary IP
addresses for SoftLayer resources in the VLAN. Each portable subnet has a default gateway IP address, network IP address, and broadcast
IP address. For example, if a portable subnet is `10.0.0.0/30`, `10.0.0.0` is a network IP address, `10.0.0.1` is a default gateway IP address,
and `10.0.0.3` is a broadcast IP address. Therefore, only `10.0.0.2` can be assigned to SoftLayer resources as a secondary IP address.
Number of usuable IP addresses is `capacity` - 3. If `capacity` is 4, the number of usuable IP addresses is 4 - 3 = 1. If `capacity` is 8, the
number of usuable IP addresses is 8 - 3 = 5. For additional details, refer to [Static and Portable IP blocks](https://knowledgelayer.softlayer.com/articles/static-and-portable-ip-blocks).

The static IPv4 subnet provides secondary IP addresses for primary IP addresses. It provides secondary IP addresses for SoftLayer resources such as
virtual servers, bare metal servers, and netscaler VPXs. Suppose that a virtual server requires secondary IP addresses. Then, users can create
a static subnet on the public IP address of the virtual server. Unlike the portable subnet, `capacity` is same with a number of usuable IP address.
For example, if a static subnet is `10.0.0.0/30`, `capacity` is 4 and four IP addresses(10.0.0.0 ~ 10.0.0.3) can be used as secondary IP addresses.
For additional details, refer to [Subnet](https://knowledgelayer.softlayer.com/topic/subnets).

Both the public portable IPv6 subnet and the public static IP only accept `64` as a value of `capacity` attribute. They provide 2^64 IP addresses. For additional detail, refer to [IPv6 address](http://blog.softlayer.com/tag/ipv6)

The following example will create a private portable subnet which has one available IPv4 address.
##### Example Usage of portable subnet

```hcl
# Create a new portable subnet
resource "softlayer_subnet" "portable_subnet" {
type = "Portable"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if there can only be two types, portable or static, make it a boolean then portable = true or static = true to avoid possible spelling errors. If it is not portable, then it is static and vice-versa.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SoftLayer internally uses some subnet types: PRIMARY, ADDITIONAL_PRIMARY, SECONDARY, ROUTED_TO_VLAN, SECONDARY_ON_VLAN, STORAGE_NETWORK, and STATIC_IP_ROUTED. From an end user perspective, the types can be simplified to: Primary, Static, Portable, and Global. We can ignore Global type because softlayer_global_ip is already provided. As of now, softlayer_subnet only supports Static and Portable because Primary subnet cannot be ordered manually. However, I think that Primary subnet ordering will be supported in the future. Then, we can extend this resource without schema update.

softlayer_subnet data source also can be added later. Unlike softlayer_subnet resource, the data source may supports Primary, Portable, Static. In this case, we can use the same attribute name type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@minsikl ok, in that case, why not use the same type strings as the SL API? What would static map to? STATIC_IP_ROUTED? What about portable?

The point is, if we can't make it fool-proof with booleans because there could be more than two types, then let's go with the raw API type names and then we can point there for the list of allowed types and spelling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@renier The initial code used ROUTED_TO_VLAN for portable subnets and STATIC_IP_ROUTED for static subnets. The subnet type can be retrieved using SoftLayer_Network_Subnet ::subnetType. However, I realized that SL API returns additional types such as SECONDARY_ON_VLAN, SUBNET_ON_VLAN, and STATIC_IP_ROUTED. After IPv6 feature is added, I got additional types such as STATIC_IP6_ROUTED. The raw subnet type is not an input parameter of a create function and I'm not able to guess which type will be returned from SL API. In end-user perspective, these raw types are meaningless and SL Portal uses terminology Portable, Static.

Copy link
Contributor

@renier renier Jun 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we go with the portal or with the API? is the question.

If we go with the portal names, it would be good to at least document what that means in API types.

The raw subnet type is not an input parameter of a create function and I'm not able to guess which type will be returned from SL API.

What kinds of subnets can you create then? and how do you specify the kind upon creation? (over the API)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, the user could just provide the required resource attribute without specifying the type,

I explained that primary subnet and portable subnet has the same attributes. How will you distinguish the primary subnet if you don't have type attribute?

primary = true/false

primary = true is okay. But, what is primary = false? Is that mean that the subnet will be global, secondary, third, or portable? Will you add an attribute per types such as static = true and secondary = true? primary is one of subnet types. If you use type attribute, you don't have to add additional true/false attributes to support different types. Why do you use true/false for type names?

Copy link
Contributor

@renier renier Jun 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, the user could just provide the required resource attribute without specifying the type,

I explained that primary subnet and portable subnet has the same attributes. How will you distinguish the primary subnet if you don't have type attribute?

Can a user order a primary subnet today? If not, then I stand by that we should not add a required pseudo-attribute based on something that has not happened in the API yet. We don't have enough information on how to handle until it actually does. Does this make sense?

Is it that we know that orderable primary subnets is in the works and we expect that to be available any moment now? If so, do we know exactly how the ordering of a primary subnet will look like?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@renier softlayer_vlan already provides a function to create the first primary subnet. When you create a new VLAN using terraform, you should define the size of the first primary subnet. Then, placeOrder in softlayer_vlan resource sends priceId of VLAN and priceId of the primary subnet and creates a new VLAN with a primary subnet. So, primary subnets ordering requires same information with portable subnets ordering.

Subnet types are not pseudo-attributes. price item key names contain them, SL portal, automatic tickets, and knowledgelayer use them. Only SL API provides it's internal subnet types.

Boolean attributes should be only used when SL API provides boolean properties or the attributes are optional values such as advanced monitering or redundant power supply. Or they will be pseudo-attributes, and it's hard to understand the meaning.

I defined a general softlayer_subnet resource and it is a pseudo resource. That's why the type attribute is important in softlayer_subnet resource. type is added to define a real resource type of subnets. In the later, if a new attribute is added to describe a new subnet type such as primary=true/false, primary and type will provide duplicated information, and I don't think that it is a good design. Current softlayer_subnet only supports parts of SL subnet types. At least, we need to provide extensible schema if we want to use softlayer_subnet.

If you don't want to use type attribute, let's just define separate resources softlayer_portable_subnet and softlayer_static_subnet. There is no advantage to using softlayer_subnet and if softlayer_subnet is provided without type, it will just make confusion.

Copy link
Contributor

@renier renier Jun 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

softlayer_vlan already provides a function to create the first primary subnet.

That's good to know and understand. I had not made the link between the vlan and the primary subnet. Why were you thinking that primary could be an additional type to softlayer_subnet, when it is already being provided by softlayer_vlan?

Subnet types are not pseudo-attributes. price item key names contain them, SL portal, automatic tickets, and knowledgelayer use them. Only SL API provides it's internal subnet types.
Boolean attributes should be only used when SL API provides boolean properties or the attributes are optional values such as advanced monitering or redundant power supply. Or they will be pseudo-attributes, and it's hard to understand the meaning.

In this case, the type is an attribute that is not synced with the API and is only managed locally. Thus, it is a pseudo-attribute of the resource by definition. Just as any boolean flags in other resources that are also only managed locally. The most common pseudo-attributes are booleans, because you usually don't need to make those kinds of attributes more complex and should not if possible.

I defined a general softlayer_subnet resource and it is a pseudo resource.

Based on my definition above, a pseudo-resource would be something that is not sync-ed with the cloud and it would be managed completely locally. For example, the random provider in terraform only has pseudo-resources. It follows that softlayer_subnet is not a pseudo-resource.

If you don't want to use type attribute, let's just define separate resources softlayer_portable_subnet and softlayer_static_subnet. There is no advantage to using softlayer_subnet and if softlayer_subnet is provided without type, it will just make confusion.

It doesn't have to be confusing if we document that portable subnets are created when you fill out the vlan_id, otherwise if you provide the endpoint_ip, it is static. Even less if you provide a documented computed attribute to the resource computing this fact for them as a word (portable or static).

Creating multiple resources, one per subnet type, is also an option, as long as 99% of the code is shared among them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's good to know and understand.

I gave you the primary subnet provisioning example as an answer to your question: Can a user order a primary subnet today? If not, then I stand by that we should not add a required pseudo-attribute based on something that has not happened in the API yet. We don't have enough information on how to handle until it actually does.. You can see that primary subnet requires same attributes with portable subnet when you create a new primary subnet.

Why were you thinking that primary could be an additional type to softlayer_subnet, when it is already being provided by softlayer_vlan?

If you get a chance to deploy middle/large size systems or some cluster solutions on SoftLayer, you will find several primary subnet requirements which are not provided in SoftLayer. You can only create the first primary subnet as I explained above. You are not able to create 2nd/3rd primary subnets with a specific CIDR. Some cluster solutions require specific CIDR and some users want to reserve primary subnets in their VLAN for their firewall rules or applications.

Based on my definition above, a pseudo-resource would be something that is not sync-ed with the cloud and it would be managed completely locally. For example, the random provider in terraform only has pseudo-resources. It follows that softlayer_subnet is not a pseudo-resource.

primary subnet, portable subnet, static subnet, and global subnet are combinations of interface and routing commands on physical routers and switches. subnet is a general network terminology which provides IP range and CIDR information. But, primary subnet, portable subnet, static subnet, and global subnet are not general terminologies and only used in SoftLayer. They are offering names and you can create and manage them on SoftLayer. subnet is used to refer to these soft layer offerings, not the actual resource name.

It doesn't have to be confusing if we document that portable subnets are created when you fill out the vlan_id, otherwise if you provide the endpoint_ip, it is static. Even less if you provide a documented computed attribute to the resource computing this fact for them as a word (portable or static).

Documents must, of course, be provided. Nevertheless, if there is a better way to define a resource, that method should be used.
Indirect resource definition methods also affect tf file readability. In a tf file where dozens of subnets are defined, people have to extract the subnet type by identifying the manual, deducing the subnet type, or creating a separate script.

Creating multiple resources, one per subnet type, is also an option, as long as 99% of the code is shared among them.

I'll create create two different subnets softlayer_subnet_portable and softlayer_subnet_static.

network = "PRIVATE"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same with the type of network. if there can only be two types, public and private, then make it a boolean private = true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

ip_version = 4
capacity = 4
vlan_id = 1234567
notes = "portable_subnet"
}
```

The following example will create a public static subnet which has four available IPv4 address.
##### Example Usage of static subnet

```hcl
# Create a new static subnet
resource "softlayer_subnet" "static_subnet" {
type = "Static"
network = "PUBLIC"
ip_version = 4
capacity = 4
endpoint_ip="151.1.1.1"
notes = "static_subnet_updated"
}
```

Sometimes, users need to get IP addresses on a subnet. Terraform built-in functions can be used to get IP addresses from `subnet`.
The following example returns first IP address in the subnet `test`:
```hcl
resource "softlayer_subnet" "test" {
type = "Static"
network = "PUBLIC"
ip_version = 4
capacity = 4
endpoint_ip="159.8.181.82"
}

# Use a built-in function cidrhost with index 0.
output "first_ip_address" {
value = "${cidrhost(softlayer_subnet.test.subnet,0)}"
}
```

##### Argument Reference

The following arguments are supported:

* `network` | *string*
* Set the network property of the subnet if it is public or private. Accepted values are PRIVATE and PUBLIC.
* **Required**
* `type` | *string*
* Set the type of the subnet. Accepted values are Portable and Static.
* **Required**
* `ip_version` | *int*
* Set the IP version of the subnet. Accepted values are 4 and 6.
* **Required**
* `capacity` | *int*
* Set the size of the subnet.
* Accepted values for a public portable IPv4 subnet are 4, 8, 16, and 32.
* Accepted values for a private portable IPv4 subnet are 4, 8, 16, 32, and 64.
* Accepted values for a public static IPv4 subnet are 1, 2, 4, 8, 16, and 32.
* Accepted value for a public portable IPv6 subnet is 64. /64 block is created and 2^64 IP addresses are provided.
* Accepted value for a public static IPv6 subnet is 64. /64 block is created and 2^64 IP addresses are provided.
* **Required**
* `vlan_id` | *int*
* VLAN id for portable subnet. It should be configured when the subnet is a portable subnet. Both public VLAN ID and private VLAN ID can
be configured. Accepted values can be found [here](https://control.softlayer.com/network/vlans). Click on the desired VLAN and note the
ID on the resulting URL. Or, you can also [refer to a VLAN by name using a data source](https://github.com/softlayer/terraform-provider-softlayer/blob/master/docs/datasources/softlayer_vlan.md).
* **Optional**
* `endpoint_ip` | *string*
* Target primary IP address for static subnet. It should be configured when the subnet is a static subnet. Only public IP address can be
configured as a `endpoint_ip`. It can be public IP address of virtual servers, bare metal servers, and netscaler VPXs. `static subnet` will
be created on VLAN where `endpoint_ip` is located in.
* **Optional**
* `notes` | *string*
* Set comments for the subnet.
* **Optional**

##### Attributes Reference

The following attributes are exported:

* `id` - id of the subnet.
* `subnet` - It rovides IP address/netmask format (ex. 10.10.10.10/28). It can be used to get an available IP address in `subnet`.
1 change: 1 addition & 0 deletions softlayer/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func Provider() terraform.ResourceProvider {
"softlayer_file_storage": resourceSoftLayerFileStorage(),
"softlayer_block_storage": resourceSoftLayerBlockStorage(),
"softlayer_dns_secondary": resourceSoftLayerDnsSecondary(),
"softlayer_subnet": resourceSoftLayerSubnet(),
},

ConfigureFunc: providerConfigure,
Expand Down
Loading