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

Add vkcs_networking_anycastip resource #544

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description: |-
---

# VKCS Provider's changelog
#### v0.10.0
- Add vkcs_networking_anycastip resource

#### v0.9.2
- Reduce the minimum number of DHCP ports to wait for a subnet to be ready from 2 to 1
Expand Down
2 changes: 1 addition & 1 deletion automation
72 changes: 72 additions & 0 deletions docs/resources/networking_anycastip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
subcategory: "Network"
layout: "vkcs"
page_title: "vkcs: vkcs_networking_anycastip"
description: |-
Manages a anycast IP resource within VKCS.
---

# vkcs_networking_anycastip



## Example Usage
### Anycast IP association with two octavia loadbalancers
```terraform
resource "vkcs_networking_anycastip" "anycastip" {
name = "app-tf-example"
description = "app-tf-example"

network_id = data.vkcs_networking_network.extnet.id
associations = [
{
id = vkcs_lb_loadbalancer.app1.vip_port_id
type = "octavia"
},
{
id = vkcs_lb_loadbalancer.app2.vip_port_id
type = "octavia"
}
]
}
```

## Argument Reference
- `network_id` **required** *string* → ID of the external network to choose ip for anycast IP from.

- `associations` *set* → List of port associations with anycast IP.
- `id` **required** *string* → ID of port / dc interface / octavia loadbalancer vip port.

- `type` **required** *string* → Type of association. Can be one of: port, dc_interface, octavia.


- `description` optional *string* → Description of the anycast IP.

- `health_check` optional → Health check settings.
- `port` optional *number* → Port for check to connect to.

- `type` optional *string* → Check type. Can be one of: TCP, ICMP.


- `name` optional *string* → Name of the anycast IP.

- `region` optional *string* → The region in which to obtain the Networking client. If omitted, the `region` argument of the provider is used. Changing this creates a new resource.


## Attributes Reference
In addition to all arguments above, the following attributes are exported:
- `id` *string* → ID of the anycast IP.

- `ip_address` *string* → Anycast IP address.

- `subnet_id` *string* → Anycast IP subnet id.



## Import

Anycast IPs can be imported using the `id`, e.g.

```shell
terraform import vkcs_networking_anycastip.anycastip_1 bfbed405-dd89-41d9-aa97-6e335161146d
```
15 changes: 15 additions & 0 deletions examples/networking/anycastip/base-loadbalancer.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
resource "vkcs_lb_loadbalancer" "app1" {
name = "app-tf-example-1"
description = "Loadbalancer for resources/datasources testing"
vip_subnet_id = vkcs_networking_subnet.app.id
tags = ["app-front-tf-example"]
}

resource "vkcs_lb_loadbalancer" "app2" {
name = "app-tf-example-2"
description = "Loadbalancer for resources/datasources testing"
vip_subnet_id = vkcs_networking_subnet.app.id
tags = ["app-front-tf-example"]
}


33 changes: 33 additions & 0 deletions examples/networking/anycastip/base-networking.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Create networks
resource "vkcs_networking_network" "app" {
name = "app-tf-example"
description = "Application network"

sdn = "sprut"
}

resource "vkcs_networking_subnet" "app" {
name = "app-tf-example"
network_id = vkcs_networking_network.app.id
cidr = "192.168.199.0/24"

sdn = "sprut"
}

# Get external network with Internet access
data "vkcs_networking_network" "extnet" {
name = "internet"
}

# Create a router to connect networks
resource "vkcs_networking_router" "router" {
name = "router-tf-example"
# Connect router to Internet
external_network_id = data.vkcs_networking_network.extnet.id
}

# Connect networks to the router
resource "vkcs_networking_router_interface" "app" {
router_id = vkcs_networking_router.router.id
subnet_id = vkcs_networking_subnet.app.id
}
16 changes: 16 additions & 0 deletions examples/networking/anycastip/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
resource "vkcs_networking_anycastip" "anycastip" {
name = "app-tf-example"
description = "app-tf-example"

network_id = data.vkcs_networking_network.extnet.id
associations = [
{
id = vkcs_lb_loadbalancer.app1.vip_port_id
type = "octavia"
},
{
id = vkcs_lb_loadbalancer.app2.vip_port_id
type = "octavia"
}
]
}
23 changes: 23 additions & 0 deletions templates/networking/resources/vkcs_networking_anycastip.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
subcategory: "{{.SubCategory}}"
layout: "vkcs"
page_title: "vkcs: {{.Name}}"
description: |-
Manages a anycast IP resource within VKCS.
---

# {{.Name}}

{{ .Description }}

## Example Usage
### Anycast IP association with two octavia loadbalancers
{{tffile .ExampleFile}}

{{ .SchemaMarkdown }}

## Import

Anycast IPs can be imported using the `id`, e.g.

{{codefile "shell" "templates/networking/resources/vkcs_networking_anycastip/import.sh"}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import vkcs_networking_anycastip.anycastip_1 bfbed405-dd89-41d9-aa97-6e335161146d
49 changes: 30 additions & 19 deletions vkcs/internal/acctest/acctest.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,25 @@ var (
OsRegionName = os.Getenv("OS_REGION_NAME")
OsProjectID = os.Getenv("OS_PROJECT_ID")
OsExtNetName = os.Getenv("OS_EXT_NET_NAME")
OsExtNetSprutName = os.Getenv("OS_EXT_NET_SPRUT_NAME")
OsAvailabilityZone = os.Getenv("OS_AVAILABILITY_ZONE")
OsVolumeType = os.Getenv("OS_VOLUME_TYPE")
)

var AccTestValues map[string]string = map[string]string{
"BaseNetwork": AccTestBaseNetwork,
"BaseExtNetwork": AccTestBaseExtNetwork(),
"BaseImage": AccTestBaseImage(),
"BaseFlavor": AccTestBaseFlavor(),
"BaseNewFlavor": AccTestBaseNewFlavor(),
"AvailabilityZone": OsAvailabilityZone,
"VolumeType": OsVolumeType,
"FlavorName": OsFlavorName,
"NewFlavorName": OsNewFlavorName,
"ImageName": OsImageName,
"ExtNetName": OsExtNetName,
"ProjectID": OsProjectID,
"BaseNetwork": AccTestBaseNetwork,
"BaseExtNetwork": AccTestBaseExtNetwork(),
"BaseExtSprutNetwork": AccTestBaseExtNetworkSprut(),
"BaseImage": AccTestBaseImage(),
"BaseFlavor": AccTestBaseFlavor(),
"BaseNewFlavor": AccTestBaseNewFlavor(),
"AvailabilityZone": OsAvailabilityZone,
"VolumeType": OsVolumeType,
"FlavorName": OsFlavorName,
"NewFlavorName": OsNewFlavorName,
"ImageName": OsImageName,
"ExtNetName": OsExtNetName,
"ProjectID": OsProjectID,
}

var AccTestProviders map[string]func() (*schema.Provider, error)
Expand Down Expand Up @@ -82,13 +84,14 @@ func init() {

func AccTestPreCheck(t *testing.T) {
vars := map[string]interface{}{
"OS_VOLUME_TYPE": OsVolumeType,
"OS_AVAILABILITY_ZONE": OsAvailabilityZone,
"OS_FLAVOR_NAME": OsFlavorName,
"OS_NEW_FLAVOR_NAME": OsNewFlavorName,
"OS_IMAGE_NAME": OsImageName,
"OS_EXT_NET_NAME": OsExtNetName,
"OS_PROJECT_ID": OsProjectID,
"OS_VOLUME_TYPE": OsVolumeType,
"OS_AVAILABILITY_ZONE": OsAvailabilityZone,
"OS_FLAVOR_NAME": OsFlavorName,
"OS_NEW_FLAVOR_NAME": OsNewFlavorName,
"OS_IMAGE_NAME": OsImageName,
"OS_EXT_NET_NAME": OsExtNetName,
"OS_EXT_NET_SPRUT_NAME": OsExtNetSprutName,
"OS_PROJECT_ID": OsProjectID,
}
for k, v := range vars {
if v == "" {
Expand All @@ -105,6 +108,14 @@ func AccTestBaseExtNetwork() string {
`, OsExtNetName)
}

func AccTestBaseExtNetworkSprut() string {
return fmt.Sprintf(`
data "vkcs_networking_network" "extnet" {
name = "%s"
}
`, OsExtNetSprutName)
}

func AccTestBaseFlavor() string {
return fmt.Sprintf(`
data "vkcs_compute_flavor" "base" {
Expand Down
87 changes: 87 additions & 0 deletions vkcs/internal/services/networking/v2/anycastips/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package anycastips

import "github.com/gophercloud/gophercloud"

type CreateOptsBuilder interface {
Map() (map[string]interface{}, error)
}

// CreateOpts specifies attributes used to create a new anycast IP.
type CreateOpts struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
NetworkID string `json:"network_id" required:"true"`
Associations []AnycastIPAssociation `json:"associations,omitempty"`
HealthCheck *AnycastIPHealthCheck `json:"healthcheck,omitempty"`
}

// Map builds a request body from a CreateOpts structure.
func (opts CreateOpts) Map() (map[string]interface{}, error) {
b, err := gophercloud.BuildRequestBody(opts, "anycastip")
return b, err
}

// Create implements an anycast IP create request.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.Map()
if err != nil {
r.Err = err
return
}
resp, err := client.Post(anycastIPsURL(client), &b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{201},
})
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return
}

// Get returns information about an anycast IP, given its ID.
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
resp, err := client.Get(anycastIPURL(client, id), &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return
}

type UpdateOptsBuilder interface {
Map() (map[string]interface{}, error)
}

// UpdateOpts specifies attributes used to update an anycast IP.
type UpdateOpts struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Associations []AnycastIPAssociation `json:"associations,omitempty"`
HealthCheck *AnycastIPHealthCheck `json:"healthcheck,omitempty"`
}

// Map builds a request body from a UpdateOpts structure.
func (opts UpdateOpts) Map() (map[string]interface{}, error) {
b, err := gophercloud.BuildRequestBody(opts, "anycastip")
return b, err
}

// Update implements an anycast IP update request.
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
b, err := opts.Map()
if err != nil {
r.Err = err
return
}
resp, err := client.Put(anycastIPURL(client, id), &b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return
}

// Delete implements an anycast IP delete request.
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
resp, err := client.Delete(anycastIPURL(client, id), &gophercloud.RequestOpts{
OkCodes: []int{204},
JSONResponse: &r.Body,
})
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return
}
56 changes: 56 additions & 0 deletions vkcs/internal/services/networking/v2/anycastips/results.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package anycastips

import "github.com/gophercloud/gophercloud"

type commonResult struct {
gophercloud.Result
}

// Extract interprets any anycast IP result as an AnycastIP, if possible.
func (r commonResult) Extract() (*AnycastIP, error) {
var res AnycastIPResp
if err := r.ExtractInto(&res); err != nil {
return nil, err
}
return &res.AnycastIP, nil
}

// CreateResult is the result of a create request. Call its Extract method
// to interpret a result as an AnycastIP.
type CreateResult struct {
commonResult
}

// GetResult is the result of a get request. Call its Extract method
// to interpret a result as an AnycastIP.
type GetResult struct {
commonResult
}

// UpdateResult is the result of an update request. Call its Extract method
// to interpret a result as an AnycastIP.
type UpdateResult struct {
commonResult
}

// DeleteResult is the result of a delete request. Call its ExtractErr method
// to determine if a request succeeded or failed.
type DeleteResult struct {
gophercloud.ErrResult
}

type AnycastIPResp struct {
AnycastIP AnycastIP `json:"anycastip"`
}

// AnycastIP represents an anycast IP.
type AnycastIP struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
NetworkID string `json:"network_id"`
SubnetID string `json:"subnet_id"`
IPAddress string `json:"ip_address"`
Associations []AnycastIPAssociation `json:"associations,omitempty"`
HealthCheck *AnycastIPHealthCheck `json:"healthcheck,omitempty"`
}
Loading
Loading