diff --git a/Makefile b/Makefile index 319492ef1..277b3c273 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,12 @@ core-dev: generate # Shorthand for quickly testing the core of Terraform (i.e. "not providers") core-test: generate @echo "Testing core packages..." && \ - go test -tags 'core' $(TESTARGS) $(shell go list ./... | grep -v -E 'terraform/(builtin|vendor)') + go test -tags `core` $(TESTARGS) $(shell go list ./... | grep -v -E `terraform/(builtin|vendor)`) +get-deps: + @echo "==> Fetching dependencies" + @go get -v $(TEST) + # Shorthand for building and installing just one plugin for local testing. # Run as (for example): make plugin-dev PLUGIN=provider-aws plugin-dev: generate diff --git a/builtin/providers/vcd/provider.go b/builtin/providers/vcd/provider.go index a04d13904..5ee748f7c 100644 --- a/builtin/providers/vcd/provider.go +++ b/builtin/providers/vcd/provider.go @@ -60,11 +60,12 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "vcd_network": resourceVcdNetwork(), - "vcd_vapp": resourceVcdVApp(), - "vcd_firewall_rules": resourceVcdFirewallRules(), - "vcd_dnat": resourceVcdDNAT(), - "vcd_snat": resourceVcdSNAT(), + "vcd_network": resourceVcdNetwork(), + "vcd_vapp": resourceVcdVApp(), + "vcd_firewall_rules": resourceVcdFirewallRules(), + "vcd_dnat": resourceVcdDNAT(), + "vcd_snat": resourceVcdSNAT(), + "vcd_edgegateway_vpn": resourceVcdEdgeGatewayVpn(), }, ConfigureFunc: providerConfigure, diff --git a/builtin/providers/vcd/resource_vcd_edgegateway_vpn.go b/builtin/providers/vcd/resource_vcd_edgegateway_vpn.go new file mode 100644 index 000000000..18dc6d9fa --- /dev/null +++ b/builtin/providers/vcd/resource_vcd_edgegateway_vpn.go @@ -0,0 +1,281 @@ +package vcd + +import ( + "log" + + "fmt" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + types "github.com/ukcloud/govcloudair/types/v56" +) + +func resourceVcdEdgeGatewayVpn() *schema.Resource { + return &schema.Resource{ + Create: resourceVcdEdgeGatewayVpnCreate, + Read: resourceVcdEdgeGatewayVpnRead, + Delete: resourceVcdEdgeGatewayVpnDelete, + + Schema: map[string]*schema.Schema{ + + "edge_gateway": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "encryption_protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "local_ip_address": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "local_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "mtu": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + + "peer_ip_address": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "peer_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "shared_secret": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "local_subnets": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "local_subnet_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "local_subnet_gateway": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "local_subnet_mask": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + + "peer_subnets": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "peer_subnet_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "peer_subnet_gateway": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "peer_subnet_mask": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + } +} + +func resourceVcdEdgeGatewayVpnCreate(d *schema.ResourceData, meta interface{}) error { + vcdClient := meta.(*VCDClient) + log.Printf("[TRACE] CLIENT: %#v", vcdClient) + vcdClient.Mutex.Lock() + defer vcdClient.Mutex.Unlock() + + edgeGateway, err := vcdClient.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string)) + + localSubnetsList := d.Get("local_subnets").(*schema.Set).List() + peerSubnetsList := d.Get("peer_subnets").(*schema.Set).List() + + localSubnets := make([]*types.IpsecVpnSubnet, len(localSubnetsList)) + peerSubnets := make([]*types.IpsecVpnSubnet, len(peerSubnetsList)) + + for i, s := range localSubnetsList { + ls := s.(map[string]interface{}) + localSubnets[i] = &types.IpsecVpnSubnet{ + Name: ls["local_subnet_name"].(string), + Gateway: ls["local_subnet_gateway"].(string), + Netmask: ls["local_subnet_mask"].(string), + } + } + + for i, s := range peerSubnetsList { + ls := s.(map[string]interface{}) + peerSubnets[i] = &types.IpsecVpnSubnet{ + Name: ls["peer_subnet_name"].(string), + Gateway: ls["peer_subnet_gateway"].(string), + Netmask: ls["peer_subnet_mask"].(string), + } + } + + tunnel := &types.GatewayIpsecVpnTunnel{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + IpsecVpnLocalPeer: &types.IpsecVpnLocalPeer{ + ID: "", + Name: "", + }, + EncryptionProtocol: d.Get("encryption_protocol").(string), + LocalIPAddress: d.Get("local_ip_address").(string), + LocalID: d.Get("local_id").(string), + LocalSubnet: localSubnets, + Mtu: d.Get("mtu").(int), + PeerID: d.Get("peer_id").(string), + PeerIPAddress: d.Get("peer_ip_address").(string), + PeerSubnet: peerSubnets, + SharedSecret: d.Get("shared_secret").(string), + IsEnabled: true, + } + + tunnels := make([]*types.GatewayIpsecVpnTunnel, 1) + tunnels[0] = tunnel + + ipsecVPNConfig := &types.EdgeGatewayServiceConfiguration{ + Xmlns: "http://www.vmware.com/vcloud/v1.5", + GatewayIpsecVpnService: &types.GatewayIpsecVpnService{ + IsEnabled: true, + /* + Endpoint: &types.GatewayIpsecVpnEndpoint{ + Network: &types.Reference{ + HREF: "http://myvpn.com", + }, + PublicIP: "63.30.253.57", + }, + */ + Tunnel: tunnels, + }, + } + + log.Printf("[INFO] ipsecVPNConfig: %#v", ipsecVPNConfig) + + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { + edgeGateway.Refresh() + task, err := edgeGateway.AddIpsecVPN(ipsecVPNConfig) + if err != nil { + log.Printf("[INFO] Error setting ipsecVPNConfig rules: %s", err) + return resource.RetryableError( + fmt.Errorf("Error setting ipsecVPNConfig rules: %#v", err)) + } + + return resource.RetryableError(task.WaitTaskCompletion()) + }) + if err != nil { + return fmt.Errorf("Error completing tasks: %#v", err) + } + + d.SetId(d.Get("edge_gateway").(string)) + + return resourceVcdEdgeGatewayVpnRead(d, meta) +} + +func resourceVcdEdgeGatewayVpnDelete(d *schema.ResourceData, meta interface{}) error { + vcdClient := meta.(*VCDClient) + + log.Printf("[TRACE] CLIENT: %#v", vcdClient) + + vcdClient.Mutex.Lock() + defer vcdClient.Mutex.Unlock() + + edgeGateway, err := vcdClient.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string)) + + ipsecVPNConfig := &types.EdgeGatewayServiceConfiguration{ + Xmlns: "http://www.vmware.com/vcloud/v1.5", + GatewayIpsecVpnService: &types.GatewayIpsecVpnService{ + IsEnabled: false, + }, + } + + log.Printf("[INFO] ipsecVPNConfig: %#v", ipsecVPNConfig) + + err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError { + edgeGateway.Refresh() + task, err := edgeGateway.AddIpsecVPN(ipsecVPNConfig) + if err != nil { + log.Printf("[INFO] Error setting ipsecVPNConfig rules: %s", err) + return resource.RetryableError( + fmt.Errorf("Error setting ipsecVPNConfig rules: %#v", err)) + } + + return resource.RetryableError(task.WaitTaskCompletion()) + }) + if err != nil { + return fmt.Errorf("Error completing tasks: %#v", err) + } + + d.SetId(d.Get("edge_gateway").(string)) + + if err != nil { + return fmt.Errorf("Error finding edge gateway: %#v", err) + } + + return nil +} + +func resourceVcdEdgeGatewayVpnRead(d *schema.ResourceData, meta interface{}) error { + vcdClient := meta.(*VCDClient) + + edgeGateway, err := vcdClient.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string)) + if err != nil { + return fmt.Errorf("Error finding edge gateway: %#v", err) + } + + fmt.Println(edgeGateway) + + //d.Set("name", *edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.GatewayIpsecVpnService.Tunnel[0].Name) + // and all the others + + return nil +} diff --git a/vendor/github.com/ukcloud/govcloudair/Makefile b/vendor/github.com/ukcloud/govcloudair/Makefile new file mode 100644 index 000000000..9b7590262 --- /dev/null +++ b/vendor/github.com/ukcloud/govcloudair/Makefile @@ -0,0 +1,37 @@ +TEST?=./... +GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor) + +default: fmt test testrace vet + +# test runs the test suite and vets the code +test: get-deps fmtcheck + @golint ./... + @echo "==> Running Tests" + @go list $(TEST) | xargs -n1 go test -timeout=60s -parallel=10 $(TESTARGS) + +# testrace runs the race checker +testrace: + @go list $(TEST) | xargs -n1 go test -race $(TESTARGS) + +# vet runs the Go source code static analysis tool `vet` to find +# any common errors. +vet: + @echo "==> Running Go Vet" + @go vet $$(go list ./... | grep -v vendor/) ; if [ $$? -eq 1 ]; then \ + echo ""; \ + echo "Vet found suspicious constructs. Please check the reported constructs"; \ + echo "and fix them if necessary before submitting the code for review."; \ + exit 1; \ + fi + +get-deps: + @echo "==> Fetching dependencies" + @go get -v $(TEST) + @go get -u github.com/golang/lint/golint + + +fmt: + gofmt -w $(GOFMT_FILES) + +fmtcheck: + @sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'" \ No newline at end of file diff --git a/vendor/github.com/ukcloud/govcloudair/edgegateway.go b/vendor/github.com/ukcloud/govcloudair/edgegateway.go index e96712469..1bc174671 100644 --- a/vendor/github.com/ukcloud/govcloudair/edgegateway.go +++ b/vendor/github.com/ukcloud/govcloudair/edgegateway.go @@ -115,6 +115,10 @@ func (e *EdgeGateway) AddDhcpPool(network *types.OrgVDCNetwork, dhcppool []inter } func (e *EdgeGateway) RemoveNATMapping(nattype, externalIP, internalIP, port string) (Task, error) { + return e.RemoveNATPortMapping(nattype, externalIP, port, internalIP, port) +} + +func (e *EdgeGateway) RemoveNATPortMapping(nattype, externalIP, externalPort string, internalIP, internalPort string) (Task, error) { // Find uplink interface var uplink types.Reference for _, gi := range e.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface { @@ -140,7 +144,7 @@ func (e *EdgeGateway) RemoveNATMapping(nattype, externalIP, internalIP, port str // If matches, let's skip it and continue the loop if v.RuleType == nattype && v.GatewayNatRule.OriginalIP == externalIP && - v.GatewayNatRule.OriginalPort == port && + v.GatewayNatRule.OriginalPort == externalPort && v.GatewayNatRule.Interface.HREF == uplink.HREF { log.Printf("[DEBUG] REMOVING %s Rule: %#v", v.RuleType, v.GatewayNatRule) continue @@ -190,6 +194,10 @@ func (e *EdgeGateway) RemoveNATMapping(nattype, externalIP, internalIP, port str } func (e *EdgeGateway) AddNATMapping(nattype, externalIP, internalIP, port string) (Task, error) { + return e.AddNATPortMapping(nattype, externalIP, port, internalIP, port) +} + +func (e *EdgeGateway) AddNATPortMapping(nattype, externalIP, externalPort string, internalIP, internalPort string) (Task, error) { // Find uplink interface var uplink types.Reference for _, gi := range e.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface { @@ -218,8 +226,9 @@ func (e *EdgeGateway) AddNATMapping(nattype, externalIP, internalIP, port string // If matches, let's skip it and continue the loop if v.RuleType == nattype && v.GatewayNatRule.OriginalIP == externalIP && - v.GatewayNatRule.OriginalPort == port && + v.GatewayNatRule.OriginalPort == externalPort && v.GatewayNatRule.TranslatedIP == internalIP && + v.GatewayNatRule.TranslatedPort == internalPort && v.GatewayNatRule.Interface.HREF == uplink.HREF { continue } @@ -237,9 +246,9 @@ func (e *EdgeGateway) AddNATMapping(nattype, externalIP, internalIP, port string HREF: uplink.HREF, }, OriginalIP: externalIP, - OriginalPort: port, + OriginalPort: externalPort, TranslatedIP: internalIP, - TranslatedPort: port, + TranslatedPort: internalPort, Protocol: "tcp", }, } @@ -623,3 +632,49 @@ func (e *EdgeGateway) Create1to1Mapping(internal, external, description string) return *task, nil } + +func (e *EdgeGateway) AddIpsecVPN(ipsecVPNConfig *types.EdgeGatewayServiceConfiguration) (Task, error) { + + err := e.Refresh() + if err != nil { + fmt.Printf("error: %v\n", err) + } + + output, err := xml.MarshalIndent(ipsecVPNConfig, " ", " ") + if err != nil { + fmt.Errorf("error marshaling ipsecVPNConfig compose: %s", err) + } + + debug := os.Getenv("GOVCLOUDAIR_DEBUG") + + if debug == "true" { + fmt.Printf("\n\nXML DEBUG: %s\n\n", string(output)) + } + + b := bytes.NewBufferString(xml.Header + string(output)) + log.Printf("[DEBUG] ipsecVPN configuration: %s", b) + + s, _ := url.ParseRequestURI(e.EdgeGateway.HREF) + s.Path += "/action/configureServices" + + fmt.Println(s) + + req := e.c.NewRequest(map[string]string{}, "POST", *s, b) + + req.Header.Add("Content-Type", "application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml") + + resp, err := checkResp(e.c.Http.Do(req)) + if err != nil { + return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err) + } + + task := NewTask(e.c) + + if err = decodeBody(resp, task.Task); err != nil { + return Task{}, fmt.Errorf("error decoding Task response: %s", err) + } + + // The request was successful + return *task, nil + +} diff --git a/vendor/github.com/ukcloud/govcloudair/types/v56/types.go b/vendor/github.com/ukcloud/govcloudair/types/v56/types.go index b4932451d..53ce02174 100644 --- a/vendor/github.com/ukcloud/govcloudair/types/v56/types.go +++ b/vendor/github.com/ukcloud/govcloudair/types/v56/types.go @@ -62,10 +62,10 @@ type CustomizationSection struct { // FIXME: OVF Section needs to be laid down correctly Info string `xml:"ovf:Info"` // - GoldMaster bool `xml:"goldMaster,attr,omitempty"` - HREF string `xml:"href,attr,omitempty"` - Type string `xml:"type,attr,omitempty"` - CustomizeOnInstantiate bool `xml:"CustomizeOnInstantiate"` + GoldMaster bool `xml:"goldMaster,attr,omitempty"` + HREF string `xml:"href,attr,omitempty"` + Type string `xml:"type,attr,omitempty"` + CustomizeOnInstantiate bool `xml:"CustomizeOnInstantiate"` Link LinkList `xml:"Link,omitempty"` } @@ -172,7 +172,7 @@ type SubAllocations struct { HREF string `xml:"href,attr,omitempty"` // The URI of the entity. Type string `xml:"type,attr,omitempty"` // The MIME type of the entity. // Elements - Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. + Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. SubAllocation *SubAllocation `xml:"SubAllocation,omitempty"` // IP Range sub allocated to a edge gateway. } @@ -358,7 +358,7 @@ type Vdc struct { ComputeCapacity []*ComputeCapacity `xml:"ComputeCapacity"` Description string `xml:"Description,omitempty"` IsEnabled bool `xml:"IsEnabled"` - Link LinkList `xml:"Link,omitempty"` + Link LinkList `xml:"Link,omitempty"` NetworkQuota int `xml:"NetworkQuota"` NicQuota int `xml:"NicQuota"` ResourceEntities []*ResourceEntities `xml:"ResourceEntities,omitempty"` @@ -502,7 +502,7 @@ type Org struct { Description string `xml:"Description,omitempty"` FullName string `xml:"FullName"` IsEnabled bool `xml:"IsEnabled,omitempty"` - Link LinkList `xml:"Link,omitempty"` + Link LinkList `xml:"Link,omitempty"` Tasks *TasksInProgress `xml:"Tasks,omitempty"` } @@ -521,7 +521,7 @@ type CatalogItem struct { DateCreated string `xml:"DateCreated,omitempty"` Description string `xml:"Description,omitempty"` Entity *Entity `xml:"Entity"` - Link LinkList `xml:"Link,omitempty"` + Link LinkList `xml:"Link,omitempty"` Tasks *TasksInProgress `xml:"Tasks,omitempty"` VersionNumber int64 `xml:"VersionNumber,omitempty"` } @@ -538,7 +538,7 @@ type Entity struct { OperationKey string `xml:"operationKey,attr,omitempty"` Name string `xml:"name,attr"` Description string `xml:"Description,omitempty"` - Link LinkList `xml:"Link,omitempty"` + Link LinkList `xml:"Link,omitempty"` Tasks *TasksInProgress `xml:"Tasks,omitempty"` } @@ -566,7 +566,7 @@ type Catalog struct { DateCreated string `xml:"DateCreated"` Description string `xml:"Description"` IsPublished bool `xml:"IsPublished"` - Link LinkList `xml:"Link"` + Link LinkList `xml:"Link"` Owner *Owner `xml:"Owner,omitempty"` Tasks *TasksInProgress `xml:"Tasks,omitempty"` VersionNumber int64 `xml:"VersionNumber"` @@ -580,7 +580,7 @@ type Catalog struct { type Owner struct { HREF string `xml:"href,attr,omitempty"` Type string `xml:"type,attr,omitempty"` - Link LinkList `xml:"Link,omitempty"` + Link LinkList `xml:"Link,omitempty"` User *Reference `xml:"User"` } @@ -612,7 +612,7 @@ type File struct { BytesTransferred int64 `xml:"bytesTransferred,attr,omitempty"` Checksum string `xml:"checksum,attr,omitempty"` Description string `xml:"Description,omitempty"` - Link LinkList `xml:"Link,omitempty"` + Link LinkList `xml:"Link,omitempty"` Tasks *TasksInProgress `xml:"Tasks,omitempty"` } @@ -641,11 +641,11 @@ type UndeployVAppParams struct { // Description: Allows you to specify certain capabilities of this virtual machine. // Since: 5.1 type VMCapabilities struct { - HREF string `xml:"href,attr,omitempty"` - Type string `xml:"type,attr,omitempty"` - CPUHotAddEnabled bool `xml:"CpuHotAddEnabled,omitempty"` + HREF string `xml:"href,attr,omitempty"` + Type string `xml:"type,attr,omitempty"` + CPUHotAddEnabled bool `xml:"CpuHotAddEnabled,omitempty"` Link LinkList `xml:"Link,omitempty"` - MemoryHotAddEnabled bool `xml:"MemoryHotAddEnabled,omitempty"` + MemoryHotAddEnabled bool `xml:"MemoryHotAddEnabled,omitempty"` } // VMs represents a list of virtual machines. @@ -656,7 +656,7 @@ type VMCapabilities struct { type VMs struct { HREF string `xml:"href,attr,omitempty"` Type string `xml:"type,attr,omitempty"` - Link LinkList `xml:"Link,omitempty"` + Link LinkList `xml:"Link,omitempty"` VMReference []*Reference `xml:"VmReference,omitempty"` } @@ -687,6 +687,29 @@ type ComposeVAppParams struct { AllEULAsAccepted bool `xml:"AllEULAsAccepted,omitempty"` // True confirms acceptance of all EULAs in a vApp template. Instantiation fails if this element is missing, empty, or set to false and one or more EulaSection elements are present. } +type ReComposeVAppParams struct { + XMLName xml.Name `xml:"RecomposeVAppParams"` + Ovf string `xml:"xmlns:ovf,attr"` + Xsi string `xml:"xmlns:xsi,attr"` + Xmlns string `xml:"xmlns,attr"` + // Attributes + Name string `xml:"name,attr,omitempty"` // Typically used to name or identify the subject of the request. For example, the name of the object being created or modified. + Deploy bool `xml:"deploy,attr"` // True if the vApp should be deployed at instantiation. Defaults to true. + PowerOn bool `xml:"powerOn,attr"` // True if the vApp should be powered-on at instantiation. Defaults to true. + LinkedClone bool `xml:"linkedClone,attr,omitempty"` // Reserved. Unimplemented. + // Elements + Description string `xml:"Description,omitempty"` // Optional description. + VAppParent *Reference `xml:"VAppParent,omitempty"` // Reserved. Unimplemented. + InstantiationParams *InstantiationParams `xml:"InstantiationParams,omitempty"` // Instantiation parameters for the composed vApp. + SourcedItem *SourcedCompositionItemParam `xml:"SourcedItem,omitempty"` // Composition item. One of: vApp vAppTemplate Vm. + AllEULAsAccepted bool `xml:"AllEULAsAccepted,omitempty"` + DeleteItem *DeleteItem `xml:"DeleteItem,omitempty"` +} + +type DeleteItem struct { + HREF string `xml:"href,attr,omitempty"` +} + // SourcedCompositionItemParam represents a vApp, vApp template or Vm to include in a composed vApp. // Type: SourcedCompositionItemParamType // Namespace: http://www.vmware.com/vcloud/v1.5 @@ -754,7 +777,7 @@ type VApp struct { Deployed bool `xml:"deployed,attr,omitempty"` // True if the virtual machine is deployed. OvfDescriptorUploaded bool `xml:"ovfDescriptorUploaded,attr,omitempty"` // Read-only indicator that the OVF descriptor for this vApp has been uploaded. // Elements - Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. + Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. Description string `xml:"Description,omitempty"` // Optional description. Tasks *TasksInProgress `xml:"Tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. Files *FilesList `xml:"Files,omitempty"` // Represents a list of files to be transferred (uploaded or downloaded). Each File in the list is part of the ResourceEntity. @@ -851,7 +874,7 @@ type VAppTemplate struct { OvfDescriptorUploaded string `xml:"ovfDescriptorUploaded,attr,omitempty"` // True if the OVF descriptor for this template has been uploaded. GoldMaster bool `xml:"goldMaster,attr,omitempty"` // True if this template is a gold master. // Elements - Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. + Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. Description string `xml:"Description,omitempty"` // Optional description. Tasks *TasksInProgress `xml:"Tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. Files *FilesList `xml:"Files,omitempty"` // Represents a list of files to be transferred (uploaded or downloaded). Each File in the list is part of the ResourceEntity. @@ -894,7 +917,7 @@ type VM struct { NeedsCustomization bool `xml:"needsCustomization,attr,omitempty"` // True if this virtual machine needs customization. NestedHypervisorEnabled bool `xml:"nestedHypervisorEnabled,attr,omitempty"` // True if hardware-assisted CPU virtualization capabilities in the host should be exposed to the guest operating system. // Elements - Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. + Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. Description string `xml:"Description,omitempty"` // Optional description. Tasks *TasksInProgress `xml:"Tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. Files *FilesList `xml:"FilesList,omitempty"` // Represents a list of files to be transferred (uploaded or downloaded). Each File in the list is part of the ResourceEntity. @@ -1038,23 +1061,23 @@ type GuestCustomizationSection struct { // FIXME: Fix the OVF section Info string `xml:"ovf:Info"` // Elements - Enabled bool `xml:"Enabled,omitempty"` // True if guest customization is enabled. - ChangeSid bool `xml:"ChangeSid,omitempty"` // True if customization can change the Windows SID of this virtual machine. - VirtualMachineID string `xml:"VirtualMachineId,omitempty"` // Virtual machine ID to apply. - JoinDomainEnabled bool `xml:"JoinDomainEnabled,omitempty"` // True if this virtual machine can join a Windows Domain. - UseOrgSettings bool `xml:"UseOrgSettings,omitempty"` // True if customization should use organization settings (OrgGuestPersonalizationSettings) when joining a Windows Domain. - DomainName string `xml:"DomainName,omitempty"` // The name of the Windows Domain to join. - DomainUserName string `xml:"DomainUserName,omitempty"` // User name to specify when joining a Windows Domain. - DomainUserPassword string `xml:"DomainUserPassword,omitempty"` // Password to use with DomainUserName. - MachineObjectOU string `xml:"MachineObjectOU,omitempty"` // The name of the Windows Domain Organizational Unit (OU) in which the computer account for this virtual machine will be created. - AdminPasswordEnabled bool `xml:"AdminPasswordEnabled,omitempty"` // True if guest customization can modify administrator password settings for this virtual machine. - AdminPasswordAuto bool `xml:"AdminPasswordAuto,omitempty"` // True if the administrator password for this virtual machine should be automatically generated. - AdminPassword string `xml:"AdminPassword,omitempty"` // True if the administrator password for this virtual machine should be set to this string. (AdminPasswordAuto must be false.) - AdminAutoLogonEnabled bool `xml:"AdminAutoLogonEnabled,omitempty"` // True if guest administrator should automatically log into this virtual machine. - AdminAutoLogonCount int `xml:"AdminAutoLogonCount,omitempty"` // Number of times administrator can automatically log into this virtual machine. In case AdminAutoLogon is set to True, this value should be between 1 and 100. Otherwise, it should be 0. - ResetPasswordRequired bool `xml:"ResetPasswordRequired,omitempty"` // True if the administrator password for this virtual machine must be reset after first use. - CustomizationScript string `xml:"CustomizationScript,omitempty"` // Script to run on guest customization. The entire script must appear in this element. Use the XML entity to represent a newline. Unicode characters can be represented in the form &#xxxx; where xxxx is the character number. - ComputerName string `xml:"ComputerName,omitempty"` // Computer name to assign to this virtual machine. + Enabled bool `xml:"Enabled,omitempty"` // True if guest customization is enabled. + ChangeSid bool `xml:"ChangeSid,omitempty"` // True if customization can change the Windows SID of this virtual machine. + VirtualMachineID string `xml:"VirtualMachineId,omitempty"` // Virtual machine ID to apply. + JoinDomainEnabled bool `xml:"JoinDomainEnabled,omitempty"` // True if this virtual machine can join a Windows Domain. + UseOrgSettings bool `xml:"UseOrgSettings,omitempty"` // True if customization should use organization settings (OrgGuestPersonalizationSettings) when joining a Windows Domain. + DomainName string `xml:"DomainName,omitempty"` // The name of the Windows Domain to join. + DomainUserName string `xml:"DomainUserName,omitempty"` // User name to specify when joining a Windows Domain. + DomainUserPassword string `xml:"DomainUserPassword,omitempty"` // Password to use with DomainUserName. + MachineObjectOU string `xml:"MachineObjectOU,omitempty"` // The name of the Windows Domain Organizational Unit (OU) in which the computer account for this virtual machine will be created. + AdminPasswordEnabled bool `xml:"AdminPasswordEnabled,omitempty"` // True if guest customization can modify administrator password settings for this virtual machine. + AdminPasswordAuto bool `xml:"AdminPasswordAuto,omitempty"` // True if the administrator password for this virtual machine should be automatically generated. + AdminPassword string `xml:"AdminPassword,omitempty"` // True if the administrator password for this virtual machine should be set to this string. (AdminPasswordAuto must be false.) + AdminAutoLogonEnabled bool `xml:"AdminAutoLogonEnabled,omitempty"` // True if guest administrator should automatically log into this virtual machine. + AdminAutoLogonCount int `xml:"AdminAutoLogonCount,omitempty"` // Number of times administrator can automatically log into this virtual machine. In case AdminAutoLogon is set to True, this value should be between 1 and 100. Otherwise, it should be 0. + ResetPasswordRequired bool `xml:"ResetPasswordRequired,omitempty"` // True if the administrator password for this virtual machine must be reset after first use. + CustomizationScript string `xml:"CustomizationScript,omitempty"` // Script to run on guest customization. The entire script must appear in this element. Use the XML entity to represent a newline. Unicode characters can be represented in the form &#xxxx; where xxxx is the character number. + ComputerName string `xml:"ComputerName,omitempty"` // Computer name to assign to this virtual machine. Link LinkList `xml:"Link,omitempty"` // A link to an operation on this section. } @@ -1098,7 +1121,7 @@ type EdgeGateway struct { Name string `xml:"name,attr"` // The name of the entity. Status int `xml:"status,attr,omitempty"` // Creation status of the gateway. One of: 0 (The gateway is still being created) 1 (The gateway is ready) -1 (There was an error while creating the gateway). // Elements - Link LinkList `xml:"Link,omitempty"` // A link to an operation on this section. + Link LinkList `xml:"Link,omitempty"` // A link to an operation on this section. Description string `xml:"Description,omitempty"` // Optional description. Tasks *TasksInProgress `xml:"Tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. Configuration *GatewayConfiguration `xml:"Configuration"` // Gateway configuration. @@ -1159,11 +1182,12 @@ type SubnetParticipation struct { } type EdgeGatewayServiceConfiguration struct { - XMLName xml.Name `xml:"EdgeGatewayServiceConfiguration"` - Xmlns string `xml:"xmlns,attr,omitempty"` - GatewayDhcpService *GatewayDhcpService `xml:"GatewayDhcpService,omitempty"` - FirewallService *FirewallService `xml:"FirewallService,omitempty"` - NatService *NatService `xml:"NatService,omitempty"` + XMLName xml.Name `xml:"EdgeGatewayServiceConfiguration"` + Xmlns string `xml:"xmlns,attr,omitempty"` + GatewayDhcpService *GatewayDhcpService `xml:"GatewayDhcpService,omitempty"` + FirewallService *FirewallService `xml:"FirewallService,omitempty"` + NatService *NatService `xml:"NatService,omitempty"` + GatewayIpsecVpnService *GatewayIpsecVpnService `xml:"GatewayIpsecVpnService,omitempty"` // Substitute for NetworkService. Gateway Ipsec VPN service settings } // GatewayFeatures represents edge gateway services. @@ -1352,12 +1376,13 @@ type GatewayIpsecVpnTunnel struct { Description string `xml:"Description,omitempty"` // A description of the tunnel. // TODO: Fix this in a better way IpsecVpnThirdPartyPeer *IpsecVpnThirdPartyPeer `xml:"IpsecVpnThirdPartyPeer,omitempty"` // Details about the peer network. + IpsecVpnLocalPeer *IpsecVpnLocalPeer `xml:"IpsecVpnLocalPeer"` // Details about the local peer network. PeerIPAddress string `xml:"PeerIpAddress"` // IP address of the peer endpoint. PeerID string `xml:"PeerId"` // Id for the peer end point LocalIPAddress string `xml:"LocalIpAddress"` // Address of the local network. LocalID string `xml:"LocalId"` // Id for local end point - LocalSubnet *IpsecVpnSubnet `xml:"LocalSubnet"` // List of local subnets in the tunnel. - PeerSubnet *IpsecVpnSubnet `xml:"PeerSubnet"` // List of peer subnets in the tunnel. + LocalSubnet []*IpsecVpnSubnet `xml:"LocalSubnet"` // List of local subnets in the tunnel. + PeerSubnet []*IpsecVpnSubnet `xml:"PeerSubnet"` // List of peer subnets in the tunnel. SharedSecret string `xml:"SharedSecret"` // Shared secret used for authentication. SharedSecretEncrypted bool `xml:"SharedSecretEncrypted,omitempty"` // True if shared secret is encrypted. EncryptionProtocol string `xml:"EncryptionProtocol"` // Encryption protocol to be used. One of: AES, AES256, TRIPLEDES @@ -1372,6 +1397,12 @@ type IpsecVpnThirdPartyPeer struct { PeerID string `xml:"PeerId,omitempty"` // Id for the peer end point } +// IpsecVpnThirdPartyPeer represents details about a peer network +type IpsecVpnLocalPeer struct { + ID string `xml:"Id"` // Id for the peer end point + Name string `xml:"Name"` // Name for the peer +} + // IpsecVpnSubnet represents subnet details. // Type: IpsecVpnSubnetType // Namespace: http://www.vmware.com/vcloud/v1.5 @@ -1588,7 +1619,7 @@ type QueryResultEdgeGatewayRecordsType struct { PageSize int `xml:"pageSize,attr,omitempty"` // Page size, as a number of records or references. Total float64 `xml:"total,attr,omitempty"` // Total number of records or references in the container. // Elements - Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. + Link LinkList `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. EdgeGatewayRecord *QueryResultEdgeGatewayRecordType `xml:"EdgeGatewayRecord"` // A record representing a query result. } diff --git a/vendor/github.com/ukcloud/govcloudair/vapp.go b/vendor/github.com/ukcloud/govcloudair/vapp.go index bc3df5278..413c2ab29 100644 --- a/vendor/github.com/ukcloud/govcloudair/vapp.go +++ b/vendor/github.com/ukcloud/govcloudair/vapp.go @@ -55,6 +55,195 @@ func (v *VApp) Refresh() error { return nil } +func (v *VApp) ComposeRawVApp(name string) error { + vcomp := &types.ComposeVAppParams{ + Ovf: "http://schemas.dmtf.org/ovf/envelope/1", + Xsi: "http://www.w3.org/2001/XMLSchema-instance", + Xmlns: "http://www.vmware.com/vcloud/v1.5", + Deploy: false, + Name: name, + PowerOn: false, + } + + output, err := xml.MarshalIndent(vcomp, " ", " ") + if err != nil { + return fmt.Errorf("error marshaling vapp compose: %s", err) + } + + debug := os.Getenv("GOVCLOUDAIR_DEBUG") + + if debug == "true" { + fmt.Printf("\n\nXML DEBUG: %s\n\n", string(output)) + } + + b := bytes.NewBufferString(xml.Header + string(output)) + + s := v.c.VCDVDCHREF + s.Path += "/action/composeVApp" + + req := v.c.NewRequest(map[string]string{}, "POST", s, b) + + req.Header.Add("Content-Type", "application/vnd.vmware.vcloud.composeVAppParams+xml") + + resp, err := checkResp(v.c.Http.Do(req)) + if err != nil { + return fmt.Errorf("error instantiating a new vApp: %s", err) + } + + if err = decodeBody(resp, v.VApp); err != nil { + return fmt.Errorf("error decoding vApp response: %s", err) + } + + task := NewTask(v.c) + + for _, t := range v.VApp.Tasks.Task { + task.Task = t + err = task.WaitTaskCompletion() + if err != nil { + return fmt.Errorf("Error performing task: %#v", err) + } + } + + return nil +} + +func (v *VApp) AddVM(orgvdcnetwork OrgVDCNetwork, vapptemplate VAppTemplate, name string) error { + + vcomp := &types.ReComposeVAppParams{ + Ovf: "http://schemas.dmtf.org/ovf/envelope/1", + Xsi: "http://www.w3.org/2001/XMLSchema-instance", + Xmlns: "http://www.vmware.com/vcloud/v1.5", + Deploy: false, + Name: v.VApp.Name, + PowerOn: false, + Description: v.VApp.Description, + SourcedItem: &types.SourcedCompositionItemParam{ + Source: &types.Reference{ + HREF: vapptemplate.VAppTemplate.Children.VM[0].HREF, + Name: name, + }, + InstantiationParams: &types.InstantiationParams{ + NetworkConnectionSection: &types.NetworkConnectionSection{ + Type: vapptemplate.VAppTemplate.Children.VM[0].NetworkConnectionSection.Type, + HREF: vapptemplate.VAppTemplate.Children.VM[0].NetworkConnectionSection.HREF, + Info: "Network config for sourced item", + PrimaryNetworkConnectionIndex: vapptemplate.VAppTemplate.Children.VM[0].NetworkConnectionSection.PrimaryNetworkConnectionIndex, + NetworkConnection: &types.NetworkConnection{ + Network: orgvdcnetwork.OrgVDCNetwork.Name, + NetworkConnectionIndex: vapptemplate.VAppTemplate.Children.VM[0].NetworkConnectionSection.NetworkConnection.NetworkConnectionIndex, + IsConnected: true, + IPAddressAllocationMode: "POOL", + }, + }, + }, + NetworkAssignment: &types.NetworkAssignment{ + InnerNetwork: orgvdcnetwork.OrgVDCNetwork.Name, + ContainerNetwork: orgvdcnetwork.OrgVDCNetwork.Name, + }, + }, + } + + output, _ := xml.MarshalIndent(vcomp, " ", " ") + + s, _ := url.ParseRequestURI(v.VApp.HREF) + s.Path += "/action/recomposeVApp" + + fmt.Println(s) + fmt.Println(string(output)) + + b := bytes.NewBufferString(xml.Header + string(output)) + + req := v.c.NewRequest(map[string]string{}, "POST", *s, b) + + req.Header.Add("Content-Type", "application/vnd.vmware.vcloud.recomposeVAppParams+xml") + + task := NewTask(v.c) + v.Refresh() + if v.VApp.Tasks != nil { + fmt.Println("AYE") + for _, t := range v.VApp.Tasks.Task { + task.Task = t + err := task.WaitTaskCompletion() + if err != nil { + return fmt.Errorf("Error performing task: %#v", err) + } + } + } else { + fmt.Println("NO") + } + + resp, err := checkResp(v.c.Http.Do(req)) + if err != nil { + return fmt.Errorf("error instantiating a new vApp: %s", err) + } + + task = NewTask(v.c) + + if err = decodeBody(resp, task.Task); err != nil { + return fmt.Errorf("error decoding task response: %s", err) + } + + err = task.WaitTaskCompletion() + if err != nil { + return fmt.Errorf("Error performing task: %#v", err) + } + + return nil +} + +func (v *VApp) RemoveVM(vm VM) error { + + task := NewTask(v.c) + for _, t := range v.VApp.Tasks.Task { + task.Task = t + err := task.WaitTaskCompletion() + if err != nil { + return fmt.Errorf("Error performing task: %#v", err) + } + } + + vcomp := &types.ReComposeVAppParams{ + Ovf: "http://schemas.dmtf.org/ovf/envelope/1", + Xsi: "http://www.w3.org/2001/XMLSchema-instance", + Xmlns: "http://www.vmware.com/vcloud/v1.5", + DeleteItem: &types.DeleteItem{ + HREF: vm.VM.HREF, + }, + } + + output, _ := xml.MarshalIndent(vcomp, " ", " ") + + s, _ := url.ParseRequestURI(v.VApp.HREF) + s.Path += "/action/recomposeVApp" + + fmt.Println(s) + fmt.Println(string(output)) + + b := bytes.NewBufferString(xml.Header + string(output)) + + req := v.c.NewRequest(map[string]string{}, "POST", *s, b) + + req.Header.Add("Content-Type", "application/vnd.vmware.vcloud.recomposeVAppParams+xml") + + resp, err := checkResp(v.c.Http.Do(req)) + if err != nil { + return fmt.Errorf("error instantiating a new vApp: %s", err) + } + + task = NewTask(v.c) + + if err = decodeBody(resp, task.Task); err != nil { + return fmt.Errorf("error decoding task response: %s", err) + } + + err = task.WaitTaskCompletion() + if err != nil { + return fmt.Errorf("Error performing task: %#v", err) + } + + return nil +} + func (v *VApp) ComposeVApp(orgvdcnetwork OrgVDCNetwork, vapptemplate VAppTemplate, name string, description string) (Task, error) { if vapptemplate.VAppTemplate.Children == nil || orgvdcnetwork.OrgVDCNetwork == nil { @@ -396,7 +585,10 @@ func (v *VApp) Delete() (Task, error) { } func (v *VApp) RunCustomizationScript(computername, script string) (Task, error) { + return v.Customize(computername, script, false) +} +func (v *VApp) Customize(computername, script string, changeSid bool) (Task, error) { err := v.Refresh() if err != nil { return Task{}, fmt.Errorf("error refreshing vapp before running customization: %v", err) @@ -418,6 +610,7 @@ func (v *VApp) RunCustomizationScript(computername, script string) (Task, error) Enabled: true, ComputerName: computername, CustomizationScript: script, + ChangeSid: false, } output, err := xml.MarshalIndent(vu, " ", " ") diff --git a/vendor/github.com/ukcloud/govcloudair/vdc.go b/vendor/github.com/ukcloud/govcloudair/vdc.go index 046969540..d6d1d3079 100644 --- a/vendor/github.com/ukcloud/govcloudair/vdc.go +++ b/vendor/github.com/ukcloud/govcloudair/vdc.go @@ -67,7 +67,7 @@ func (v *Vdc) Refresh() error { } v.Vdc = unmarshalledVdc - + // The request was successful return nil } @@ -217,7 +217,7 @@ func (v *Vdc) FindVAppByName(vapp string) (VApp, error) { newvapp := NewVApp(v.c) if err = decodeBody(resp, newvapp.VApp); err != nil { - return VApp{}, fmt.Errorf("error decoding vApp response: %s", err) + return VApp{}, fmt.Errorf("error decoding vApp response: %s", err.Error()) } return *newvapp, nil @@ -228,6 +228,48 @@ func (v *Vdc) FindVAppByName(vapp string) (VApp, error) { return VApp{}, fmt.Errorf("can't find vApp: %s", vapp) } +func (v *Vdc) FindVMByName(vapp VApp, vm string) (VM, error) { + + err := v.Refresh() + if err != nil { + return VM{}, fmt.Errorf("error refreshing vdc: %s", err) + } + + for _, child := range vapp.VApp.Children.VM { + + if child.Name == vm { + + u, err := url.ParseRequestURI(child.HREF) + + if err != nil { + return VM{}, fmt.Errorf("error decoding vdc response: %s", err) + } + + // Querying the VApp + req := v.c.NewRequest(map[string]string{}, "GET", *u, nil) + + resp, err := checkResp(v.c.Http.Do(req)) + if err != nil { + return VM{}, fmt.Errorf("error retrieving vm: %s", err) + } + + newvm := NewVM(v.c) + + //body, err := ioutil.ReadAll(resp.Body) + //fmt.Println(string(body)) + + if err = decodeBody(resp, newvm.VM); err != nil { + return VM{}, fmt.Errorf("error decoding vm response: %s", err.Error()) + } + + return *newvm, nil + + } + + } + return VM{}, fmt.Errorf("can't find vm: %s", vm) +} + func (v *Vdc) FindVAppByID(vappid string) (VApp, error) { // Horrible hack to fetch a vapp with its id. diff --git a/vendor/vendor.json b/vendor/vendor.json index ee9f48dda..3097d4cbc 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -2906,16 +2906,16 @@ "revisionTime": "2016-09-28T01:52:44Z" }, { - "checksumSHA1": "y4ihcZrjJdyQDnsKLelo9/1MjqE=", + "checksumSHA1": "q+FWbxP3r4GRzEx+zZpmjhZ5b5Y=", "path": "github.com/ukcloud/govcloudair", - "revision": "9076b4221ebf430944c716c798e904e00cbaa89d", - "revisionTime": "2017-01-31T00:00:54Z" + "revision": "993d72d0f08369c36ef0d4220edff65bae450a05", + "revisionTime": "2017-03-28T11:27:18Z" }, { - "checksumSHA1": "CridJfrpcrjMdXnf7PbqA/+7wuY=", + "checksumSHA1": "8FHandxT6XIwsawRe0eNupivqho=", "path": "github.com/ukcloud/govcloudair/types/v56", - "revision": "9076b4221ebf430944c716c798e904e00cbaa89d", - "revisionTime": "2017-01-31T00:00:54Z" + "revision": "993d72d0f08369c36ef0d4220edff65bae450a05", + "revisionTime": "2017-03-28T11:27:18Z" }, { "checksumSHA1": "CdE9OUEGLn2pAv1UMuM5rSlaUpM=",