Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[submodule "vendor/compute-api"]
path = vendor/github.com/DimensionDataResearch/go-dd-cloud-compute
url = https://github.com/DimensionDataResearch/go-dd-cloud-compute.git
branch = development/v2.0
36 changes: 16 additions & 20 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
dist: trusty
language: go

go:
- "1.12.1"

branches:
only:
- /^development\/v.*$/
- /^release\/v.*$/
- /^v.*$/

- 1.12.x
env:
- GOMAXPROCS=4 GO111MODULE=on
install:
- go get golang.org/x/crypto/pkcs12
- go get github.com/pkg/errors
- go get github.com/hashicorp/terraform
- pushd $GOPATH/src/github.com/hashicorp/terraform
- git checkout v0.11.13
- popd

- go get github.com/hashicorp/[email protected]
- go mod tidy
- go mod vendor
- go get github.com/DimensionDataResearch/go-dd-cloud-compute@development/v2.0
script:
- make dist

before_deploy:
- export TRAVIS_TAG="v2.3.6"
- git tag $TRAVIS_TAG
deploy:
provider: releases
file: _bin/terraform-provider-ddcloud.*.zip
api_key:
secure: e8YOmjwTS+Dqp7JtyC0yCGonHmpN0ZmhZUPb5miZKtzlHUqqsiMglOrfkqad4r2olyjLWtyNwWwXvqEPSPKO81FOs7HQ1PkoluvAOdesvaBZ2bm5LbXhpzSzbFZNN4mdx5RNYMmIB6pBz48bC5AtcWD6yWtVWG1v7ZhIlXYlo7TQvV2VxZKN/j45OdfDmkGM+es+MlBTzmJUanoReXdvXjvwb373yHDDNVi5mfWE+AwMK/G8+gUdDb6UTBO59GnbT3VisB1tL31aytWwaubdiuWmnpFxeZ/i+cJvGoywbwSGUv80ZyE97JpO81wLG2f+dlkUCRMzLd9GhPxWVmP+JxXPXYvlewXPijoK3SEfH6+Ojj5CjyoycHEcB0/QIZpQOUyWRMsqkeA4TCluCZe5luq4Xjn3AJo9LAfCYCymHmrVAL0/t1Qyv/cXIwPu9lSEFjHXYKojMLdtYVYS9jUCcWI0a01mQUb1MKPixbxeDe/7iZ1PgSng7hbomnjlX+ETO6y3BB4yzJMDEFmoHgBxNQo8ArvfJ4EijiA4q+NMgU7FosKjLBYcO/GV+0AK/wG0jPaPd8u3kLNJRGctBSMz1HmX0YBtE+d0w74ps9lOPArzfOltN98X3sqRp0zvtVuRM68pIbBIQ0l15PU4r2IDXQT1yNR0QQqI9Mp5OGZlJwE=
file_glob: true
skip_cleanup: true
file: _bin/terraform-provider-ddcloud.*.zip
on:
repo: DimensionDataResearch/dd-cloud-compute-terraform
tags: true
api_key:
secure: LTJjqC/G2arlaXfH+BGaU4dWUdBk9f6nKQwM0B3MtRZm76Lhi/wZFWOqzU3qSXbSGEHuSgfH4MsSM3AqQrLwsYRxkDo2QmwC05WrCa8ErdHPl0MWxEr1ZnRSysZsh2/BoVka1NsH93quPxCi6VjlSXPEjMAOtpMytsax3ac/gSZNOHrByEyxmNPFYlsS8eY+7B8D5c8EbBYZ6uuyN5vBqs46HwiAiXqIKEoUnjUjTrr/oyyH9Dd9RW98Ak6QF8ZnyrW1W6g4jyGPlRKfP6mhNI18jhn26w45sx6B84zKNY6YgmGwtrGJHfWC8qS0WBEDIKlmkRL8/j9mEzvsHMQ8wVYItgSPHl+kRnQjEuqI6vkiyEeFdmUrs1ZFKWbfkfO9Doz6pohQBxrATM480nEumnyRyeo50wxiXwe0BAlG5do/duqPT/p03sb2Zh8JolXqfbHcCXFdFiX9cEUBhaO+ofiWfpq0T2ezxr5fH8m+1TMZLOPhJc1yDXirnoEFtrm4QBYAfMJOeJhKHB12MZjMIirYahNoFT1+wDeTx/GGwfIkm4AG+OnYic2muRqIU+dG3DPpbn2YbkNTnS+nvdE73g8wcQQnjbsPaD7obuKnMrK7EDIgBl8CJwzdRan9kRc6BUuGzdGEJ1ern7yZKzIrmTz76hbPTRB6tTWTQh1uBb0=
branch: development\/v2.0
skip_cleanup: 'true'
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
PROVIDER_NAME = ddcloud

VERSION = 2.3.3
VERSION = 2.3.6
VERSION_INFO_FILE = ./$(PROVIDER_NAME)/version-info.go

BIN_DIRECTORY = _bin
DEV_BIN_DIRECTORY = /usr/local/bin/
DEV_BIN_DIRECTORY = _bin
LOCAL_BIN_DIRECTORY = /usr/local/bin
EXECUTABLE_NAME = terraform-provider-$(PROVIDER_NAME)
DIST_ZIP_PREFIX = $(EXECUTABLE_NAME).v$(VERSION)

Expand All @@ -20,9 +21,12 @@ fmt:

clean:
rm -rf $(BIN_DIRECTORY) $(VERSION_INFO_FILE)
rm -rf $(DEV_BIN_DIRECTORY) $(VERSION_INFO_FILE)
go clean $(REPO_ROOT)/...

# Peform a LOCAL development (current-platform-only) build.
local: version fmt
go build -o $(LOCAL_BIN_DIRECTORY)/$(EXECUTABLE_NAME)

# Peform a development (current-platform-only) build.
dev: version fmt
go build -o $(DEV_BIN_DIRECTORY)/$(EXECUTABLE_NAME)
Expand Down
7 changes: 4 additions & 3 deletions ddcloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,12 @@ func Provider() terraform.ResourceProvider {
"region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
Description: "The region code that identifies the target end-point for the Dimension Data CloudControl API.",
ConflictsWith: []string{"cloudcontrol_endpoint"},
},
"cloudcontrol_endpoint": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
Description: "The base URL of a custom target end-point for the Dimension Data CloudControl API.",
ConflictsWith: []string{"region"},
},
Expand Down Expand Up @@ -129,8 +127,11 @@ func Provider() terraform.ResourceProvider {
// A reserved IPv6 or private IPv4 address on a VLAN.
"ddcloud_ip_address_reservation": resourceIPAddressReservation(),

// Enterprise network domain static route
// Enterprise network domain static route.
"ddcloud_static_route": resourceStaticRoute(),

// A IP address block in network domain.
"ddcloud_ip_address_block": resourceIPAddressBlock(),
},

DataSourcesMap: map[string]*schema.Resource{
Expand Down
199 changes: 199 additions & 0 deletions ddcloud/resource_ip_address_block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package ddcloud

import (
"fmt"
"github.com/DimensionDataResearch/dd-cloud-compute-terraform/retry"
"github.com/DimensionDataResearch/go-dd-cloud-compute/compute"
"github.com/hashicorp/terraform/helper/schema"
"log"
)

const (
resourceKeyIPAddressBlockID = "ipblock_id"
resourceKeyIPAddressBlockDomainID = "domain_id"
resourceKeyIPAddressBlockBaseIp = "base_ip"
resourceKeyIPAddressBlockDescription = "description"
)

func resourceIPAddressBlock() *schema.Resource {
return &schema.Resource{
Create: resourceIPAddressBlockCreate,
Read: resourceIPAddressBlockRead,
Update: resourceIPAddressBlockUpdate,
Delete: resourceIPAddressBlockDelete,
Importer: &schema.ResourceImporter{
State: resourceIPAddressBlockImport,
},

Schema: map[string]*schema.Schema{
resourceKeyIPAddressBlockID: &schema.Schema{
Type: schema.TypeString,
Computed: true,
Description: "The Id of the IP Address block.",
},
resourceKeyIPAddressBlockDomainID: &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The network domain where IP address block resides.",
},
resourceKeyIPAddressBlockBaseIp: &schema.Schema{
Type: schema.TypeString,
Computed: true,
ForceNew: false,
Description: "An IPv4 address in dot notation, corresponding to the lowest IPv address in the block.",
},
resourceKeyIPAddressBlockDescription: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
Description: "A description for the IP Address Block",
},
resourceKeyTag: schemaTag(),
},
}
}

func resourceIPAddressBlockCreate(data *schema.ResourceData, provider interface{}) (err error) {
domainID := data.Get(resourceKeyIPAddressBlockDomainID).(string)
providerState := provider.(*providerState)
apiClient := providerState.Client()

log.Printf("Creating new IP address block in network domain '%s'",
domainID,
)

ipBlockID, err := apiClient.AddPublicIPBlock(domainID)
data.SetId(ipBlockID)

if err != nil {
return err
}

// Tags
err = applyTags(data, apiClient, compute.AssetTypePublicIPBlock, providerState.Settings())
if err != nil {
return err
}
data.SetPartial(resourceKeyTag)
data.Partial(false)

return nil
}

func resourceIPAddressBlockRead(data *schema.ResourceData, provider interface{}) (err error) {

id := data.Id()
domainID := data.Get(resourceKeyIPAddressBlockDomainID).(string)
ipBlockID := data.Get(resourceKeyIPAddressBlockID).(string)
baseIp := data.Get(resourceKeyIPAddressBlockBaseIp).(string)

log.Printf("Read IP Address Block Id = '%s' in network domain '%s', IP Base Address '%s').", ipBlockID, domainID, baseIp)

apiClient := provider.(*providerState).Client()

ipBlock, err := apiClient.GetPublicIPBlock(id)
if err != nil {
return err
}

if ipBlock != nil {
data.Set(resourceKeyIPAddressBlockDomainID, ipBlock.ID)
data.Set(resourceKeyIPAddressBlockDomainID, ipBlock.NetworkDomainID)
data.Set(resourceKeyIPAddressBlockBaseIp, ipBlock.BaseIP)

err = readTags(data, apiClient, compute.AssetTypePublicIPBlock)
if err != nil {
return err
}

} else {
data.SetId("") // Mark resource as deleted.
}

return nil
}

func resourceIPAddressBlockUpdate(data *schema.ResourceData, provider interface{}) (err error) {

providerState := provider.(*providerState)
apiClient := providerState.Client()

if data.HasChange(resourceKeyTag) {
err := applyTags(data, apiClient, compute.AssetTypePublicIPBlock, providerState.Settings())
if err != nil {
return err
}

data.SetPartial(resourceKeyTag)
}

return
}

func resourceIPAddressBlockDelete(data *schema.ResourceData, provider interface{}) (err error) {

id := data.Id()
networkDomainID := data.Get(resourceKeyIPAddressBlockDomainID).(string)

log.Printf("Delete IP Address Block '%s' in network domain '%s'.", id, networkDomainID)

providerState := provider.(*providerState)
apiClient := providerState.Client()

operationDescription := fmt.Sprintf("Delete IP address block '%s'", id)
err = providerState.Retry().Action(operationDescription, deleteTimeoutVLAN, func(context retry.Context) {
// CloudControl has issues if more than one asynchronous operation is initated at a time (returns UNEXPECTED_ERROR).
asyncLock := providerState.AcquireAsyncOperationLock(operationDescription)
defer asyncLock.Release() // Released once the current attempt is complete.

deleteError := apiClient.RemovePublicIPBlock(id)
if deleteError != nil {
if compute.IsResourceBusyError(deleteError) {
context.Retry()
} else {
context.Fail(deleteError)
}
}

asyncLock.Release()
})
if err != nil {
return err
}

log.Printf("IP Address Block '%s' is being deleted...", id)

return apiClient.WaitForDelete(compute.ResourceTypePublicIPBlock, id, 2)
}

func resourceIPAddressBlockImport(data *schema.ResourceData, provider interface{}) (importedData []*schema.ResourceData, err error) {
providerState := provider.(*providerState)
apiClient := providerState.Client()

ipAddressBlockID := data.Id()
log.Printf("Import IP Address Block by ID '%s'.", ipAddressBlockID)
ipAddressBlock, err := apiClient.GetPublicIPBlock(ipAddressBlockID)

if err != nil {
return
}

if ipAddressBlock == nil {
err = fmt.Errorf("IP Address block '%s' not found", ipAddressBlockID)

return
}

data.SetId(ipAddressBlock.ID)

data.Set(resourceKeyIPAddressBlockID, ipAddressBlock.ID)
data.Set(resourceKeyIPAddressBlockDomainID, ipAddressBlock.NetworkDomainID)
data.Set(resourceKeyIPAddressBlockBaseIp, ipAddressBlock.BaseIP)

err = readTags(data, apiClient, compute.AssetTypePublicIPBlock)

importedData = []*schema.ResourceData{data}

return
}
2 changes: 1 addition & 1 deletion ddcloud/resource_nat.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func resourceNATCreate(data *schema.ResourceData, provider interface{}) error {
}

data.Set(resourceKeyNATPublicAddress, natRule.ExternalIPAddress)

data.Set(resourceKeyNATPrivateAddress, natRule.InternalIPAddress)
return nil
}

Expand Down
24 changes: 24 additions & 0 deletions ddcloud/resource_networkdomain.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func resourceNetworkDomain() *schema.Resource {
Description: "The IPv4 subnet for transit outside of the network domain",
},
resourceKeyNetworkDomainFirewallRule: schemaNetworkDomainFirewallRule(),
resourceKeyTag: schemaTag(),
},
}
}
Expand Down Expand Up @@ -140,6 +141,12 @@ func resourceNetworkDomainCreate(data *schema.ResourceData, provider interface{}
return err
}

// Tags
err = applyTags(data, apiClient, compute.AssetTypeNetworkDomain, providerState.Settings())
if err != nil {
return err
}
data.SetPartial(resourceKeyTag)
data.Partial(false)

return nil
Expand Down Expand Up @@ -183,6 +190,11 @@ func resourceNetworkDomainRead(data *schema.ResourceData, provider interface{})
networkDomain.OutsideTransitVLANIPv4Subnet.PrefixSize,
))
data.SetPartial(resourceKeyNetworkDomainOutsideTransitIPv4Subnet)

err = readTags(data, apiClient, compute.AssetTypeNetworkDomain)
if err != nil {
return err
}
} else {
data.SetId("") // Mark resource as deleted.
}
Expand Down Expand Up @@ -227,6 +239,16 @@ func resourceNetworkDomainUpdate(data *schema.ResourceData, provider interface{}
apiClient := providerState.Client()

var err error

if data.HasChange(resourceKeyTag) {
err := applyTags(data, apiClient, compute.AssetTypeNetworkDomain, providerState.Settings())
if err != nil {
return err
}

data.SetPartial(resourceKeyTag)
}

if newName != nil || newPlan != nil || newDescription != nil {
err = apiClient.EditNetworkDomain(id, newName, newDescription, newPlan)
if err != nil {
Expand Down Expand Up @@ -339,6 +361,8 @@ func resourceNetworkDomainImport(data *schema.ResourceData, provider interface{}
data.Set(resourceKeyNetworkDomainPlan, networkDomain.Type)
data.Set(resourceKeyNetworkDomainDataCenter, networkDomain.DatacenterID)

err = readTags(data, apiClient, compute.AssetTypeNetworkDomain)

importedData = []*schema.ResourceData{data}

return
Expand Down
Loading