-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
VMWare vCloud Director Support #3785
Merged
Merged
Changes from 9 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
8780bd2
Added vCloud Director provider with tests and provider documentation
8376a5a
Merge branch 'terraform'
965882b
Added protection for api limiting
95ec9a9
Refresh firewall rules after each failure before trying to append new…
fc7dcb8
Minor change to documentation
cb90e6c
Merge branch 'master' into hmrc
7c09f96
Changed vmware-govcd dependency to pull from hmrc
bda4ef7
Merge branch 'terraform' into hmrc
b6abb91
Class a resource that is in tfstate but unable to be found on the pro…
a15c99e
Code cleanup to address PR comments
a05ff89
Changed documentation to better show what can be done with firewall r…
dc8924b
Changed vcd_vapp resource to make better use of Update function
5df9d22
Minor doc updates
nickithewatt ecc4ce3
Converted firewall_rules rule set to a list type. Code tidy
f8e1a64
Merge branch 'master' of github.com:hmrc/terraform into hmrc
cc54785
Merge branch 'terraform' into hmrc
f140c15
Fixed null pointer panic during firewall rules test
c8dfecc
Check where nested structs could possibly be nil before trying to acc…
29dfc43
Add retry calls to protect against api rate limiting
b0fdf8a
Fixed failing test
815ff7a
Merge branch 'terraform' into hmrc
f1c2be9
Make maxRetryTimeout (in seconds) configurable
nickithewatt 49195f8
Added docs for maxRetryTimeout
nickithewatt 3809315
Upped default maxRetryTimeout from 30s -> 60s
nickithewatt 5dde514
Merge pull request #1 from hmrc/timeout
devopsbrett a026673
Only undeploy a machine if it is switched on
aec94b1
Don't error if unable to undeploy
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/builtin/providers/vcd" | ||
"github.com/hashicorp/terraform/plugin" | ||
) | ||
|
||
func main() { | ||
plugin.Serve(&plugin.ServeOpts{ | ||
ProviderFunc: vcd.Provider, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package vcd | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
|
||
"github.com/hmrc/vmware-govcd" | ||
) | ||
|
||
type Config struct { | ||
User string | ||
Password string | ||
Org string | ||
Href string | ||
VDC string | ||
} | ||
|
||
func (c *Config) Client() (*govcd.VCDClient, error) { | ||
u, err := url.ParseRequestURI(c.Href) | ||
if err != nil { | ||
return nil, fmt.Errorf("Something went wrong: %s", err) | ||
} | ||
|
||
vcdclient := govcd.NewVCDClient(*u) | ||
org, vcd, err := vcdclient.Authenticate(c.User, c.Password, c.Org, c.VDC) | ||
if err != nil { | ||
return nil, fmt.Errorf("Something went wrong: %s", err) | ||
} | ||
vcdclient.Org = org | ||
vcdclient.OrgVdc = vcd | ||
return vcdclient, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package vcd | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
// Provider returns a terraform.ResourceProvider. | ||
func Provider() terraform.ResourceProvider { | ||
return &schema.Provider{ | ||
Schema: map[string]*schema.Schema{ | ||
"user": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
DefaultFunc: schema.EnvDefaultFunc("VCD_USER", nil), | ||
Description: "The user name for vcd API operations.", | ||
}, | ||
|
||
"password": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
DefaultFunc: schema.EnvDefaultFunc("VCD_PASSWORD", nil), | ||
Description: "The user password for vcd API operations.", | ||
}, | ||
|
||
"org": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
DefaultFunc: schema.EnvDefaultFunc("VCD_ORG", nil), | ||
Description: "The vcd org for API operations", | ||
}, | ||
|
||
"url": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
DefaultFunc: schema.EnvDefaultFunc("VCD_URL", nil), | ||
Description: "The vcd url for vcd API operations.", | ||
}, | ||
"vdc": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
DefaultFunc: schema.EnvDefaultFunc("VCD_VDC", ""), | ||
Description: "The name of the VDC to run operations on", | ||
}, | ||
}, | ||
|
||
ResourcesMap: map[string]*schema.Resource{ | ||
"vcd_network": resourceVcdNetwork(), | ||
"vcd_vapp": resourceVcdVApp(), | ||
"vcd_firewall_rules": resourceVcdFirewallRules(), | ||
"vcd_dnat": resourceVcdDNAT(), | ||
"vcd_snat": resourceVcdSNAT(), | ||
}, | ||
|
||
ConfigureFunc: providerConfigure, | ||
} | ||
} | ||
|
||
func providerConfigure(d *schema.ResourceData) (interface{}, error) { | ||
config := Config{ | ||
User: d.Get("user").(string), | ||
Password: d.Get("password").(string), | ||
Org: d.Get("org").(string), | ||
Href: d.Get("url").(string), | ||
VDC: d.Get("vdc").(string), | ||
} | ||
|
||
return config.Client() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package vcd | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
var testAccProviders map[string]terraform.ResourceProvider | ||
var testAccProvider *schema.Provider | ||
|
||
func init() { | ||
testAccProvider = Provider().(*schema.Provider) | ||
testAccProviders = map[string]terraform.ResourceProvider{ | ||
"vcd": testAccProvider, | ||
} | ||
} | ||
|
||
func TestProvider(t *testing.T) { | ||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil { | ||
t.Fatalf("err: %s", err) | ||
} | ||
} | ||
|
||
func TestProvider_impl(t *testing.T) { | ||
var _ terraform.ResourceProvider = Provider() | ||
} | ||
|
||
func testAccPreCheck(t *testing.T) { | ||
if v := os.Getenv("VCD_USER"); v == "" { | ||
t.Fatal("VCD_USER must be set for acceptance tests") | ||
} | ||
if v := os.Getenv("VCD_PASSWORD"); v == "" { | ||
t.Fatal("VCD_PASSWORD must be set for acceptance tests") | ||
} | ||
if v := os.Getenv("VCD_ORG"); v == "" { | ||
t.Fatal("VCD_ORG must be set for acceptance tests") | ||
} | ||
if v := os.Getenv("VCD_URL"); v == "" { | ||
t.Fatal("VCD_URL must be set for acceptance tests") | ||
} | ||
if v := os.Getenv("VCD_EDGE_GATEWAY"); v == "" { | ||
t.Fatal("VCD_EDGE_GATEWAY must be set for acceptance tests") | ||
} | ||
if v := os.Getenv("VCD_VDC"); v == "" { | ||
t.Fatal("VCD_VDC must be set for acceptance tests") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package vcd | ||
|
||
import ( | ||
"fmt" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hmrc/vmware-govcd" | ||
"strings" | ||
) | ||
|
||
func resourceVcdDNAT() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceVcdDNATCreate, | ||
Update: resourceVcdDNATUpdate, | ||
Delete: resourceVcdDNATDelete, | ||
Read: resourceVcdDNATRead, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"edge_gateway": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"external_ip": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
|
||
"port": &schema.Schema{ | ||
Type: schema.TypeInt, | ||
Required: true, | ||
}, | ||
|
||
"internal_ip": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceVcdDNATCreate(d *schema.ResourceData, meta interface{}) error { | ||
vcd_client := meta.(*govcd.VCDClient) | ||
// Multiple VCD components need to run operations on the Edge Gateway, as | ||
// the edge gatway will throw back an error if it is already performing an | ||
// operation we must wait until we can aquire a lock on the client | ||
vcd_client.Mutex.Lock() | ||
defer vcd_client.Mutex.Unlock() | ||
portString := getPortString(d.Get("port").(int)) | ||
|
||
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string)) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Unable to find edge gateway: %#v", err) | ||
} | ||
|
||
// Creating a loop to offer further protection from the edge gateway erroring | ||
// due to being busy eg another person is using another client so wouldn't be | ||
// constrained by out lock. If the edge gateway reurns with a busy error, wait | ||
// 3 seconds and then try again. Continue until a non-busy error or success | ||
|
||
err = retryCall(4, func() error { | ||
task, err := edgeGateway.AddNATMapping("DNAT", d.Get("external_ip").(string), | ||
d.Get("internal_ip").(string), | ||
portString) | ||
if err != nil { | ||
return fmt.Errorf("Error setting DNAT rules: %#v", err) | ||
} | ||
|
||
return task.WaitTaskCompletion() | ||
}) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error completing tasks: %#v", err) | ||
} | ||
|
||
d.SetId(d.Get("external_ip").(string) + "_" + portString) | ||
return nil | ||
} | ||
|
||
func resourceVcdDNATUpdate(d *schema.ResourceData, meta interface{}) error { | ||
return nil | ||
} | ||
|
||
func resourceVcdDNATRead(d *schema.ResourceData, meta interface{}) error { | ||
vcd_client := meta.(*govcd.VCDClient) | ||
e, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string)) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Unable to find edge gateway: %#v", err) | ||
} | ||
|
||
idSplit := strings.Split(d.Id(), "_") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than leaning on the semantics of data being stored inside the ID, it seems more straightforward to just call |
||
var found bool | ||
|
||
for _, r := range e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.NatService.NatRule { | ||
if r.RuleType == "DNAT" && | ||
r.GatewayNatRule.OriginalIP == idSplit[0] && | ||
r.GatewayNatRule.OriginalPort == idSplit[1] { | ||
found = true | ||
d.Set("internal_ip", r.GatewayNatRule.TranslatedIP) | ||
} | ||
} | ||
|
||
if !found { | ||
d.SetId("") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceVcdDNATDelete(d *schema.ResourceData, meta interface{}) error { | ||
vcd_client := meta.(*govcd.VCDClient) | ||
// Multiple VCD components need to run operations on the Edge Gateway, as | ||
// the edge gatway will throw back an error if it is already performing an | ||
// operation we must wait until we can aquire a lock on the client | ||
vcd_client.Mutex.Lock() | ||
defer vcd_client.Mutex.Unlock() | ||
portString := getPortString(d.Get("port").(int)) | ||
|
||
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string)) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Unable to find edge gateway: %#v", err) | ||
} | ||
err = retryCall(4, func() error { | ||
task, err := edgeGateway.RemoveNATMapping("DNAT", d.Get("external_ip").(string), | ||
d.Get("internal_ip").(string), | ||
portString) | ||
if err != nil { | ||
return fmt.Errorf("Error setting DNAT rules: %#v", err) | ||
} | ||
|
||
return task.WaitTaskCompletion() | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("Error completing tasks: %#v", err) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's no implementation for
Update
it's better to just omit this function from the Resource definition. That will also trigger a check to ensure that all the fields are set toForceNew
, which they should be when an Update is not available.