|  | // | 
|  | // Licensed to the Apache Software Foundation (ASF) under one | 
|  | // or more contributor license agreements.  See the NOTICE file | 
|  | // distributed with this work for additional information | 
|  | // regarding copyright ownership.  The ASF licenses this file | 
|  | // to you under the Apache License, Version 2.0 (the | 
|  | // "License"); you may not use this file except in compliance | 
|  | // with the License.  You may obtain a copy of the License at | 
|  | // | 
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, | 
|  | // software distributed under the License is distributed on an | 
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | // KIND, either express or implied.  See the License for the | 
|  | // specific language governing permissions and limitations | 
|  | // under the License. | 
|  | // | 
|  |  | 
|  | package cloudstack | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "log" | 
|  | "strings" | 
|  |  | 
|  | "github.com/apache/cloudstack-go/v2/cloudstack" | 
|  | "github.com/hashicorp/terraform/helper/schema" | 
|  | ) | 
|  |  | 
|  | func resourceCloudStackVPC() *schema.Resource { | 
|  | return &schema.Resource{ | 
|  | Create: resourceCloudStackVPCCreate, | 
|  | Read:   resourceCloudStackVPCRead, | 
|  | Update: resourceCloudStackVPCUpdate, | 
|  | Delete: resourceCloudStackVPCDelete, | 
|  | Importer: &schema.ResourceImporter{ | 
|  | State: importStatePassthrough, | 
|  | }, | 
|  |  | 
|  | Schema: map[string]*schema.Schema{ | 
|  | "name": { | 
|  | Type:     schema.TypeString, | 
|  | Required: true, | 
|  | }, | 
|  |  | 
|  | "display_text": { | 
|  | Type:     schema.TypeString, | 
|  | Optional: true, | 
|  | Computed: true, | 
|  | }, | 
|  |  | 
|  | "cidr": { | 
|  | Type:     schema.TypeString, | 
|  | Required: true, | 
|  | ForceNew: true, | 
|  | }, | 
|  |  | 
|  | "vpc_offering": { | 
|  | Type:     schema.TypeString, | 
|  | Required: true, | 
|  | ForceNew: true, | 
|  | }, | 
|  |  | 
|  | "network_domain": { | 
|  | Type:     schema.TypeString, | 
|  | Optional: true, | 
|  | Computed: true, | 
|  | ForceNew: true, | 
|  | }, | 
|  |  | 
|  | "project": { | 
|  | Type:     schema.TypeString, | 
|  | Optional: true, | 
|  | Computed: true, | 
|  | ForceNew: true, | 
|  | }, | 
|  |  | 
|  | "source_nat_ip": { | 
|  | Type:     schema.TypeString, | 
|  | Computed: true, | 
|  | }, | 
|  |  | 
|  | "zone": { | 
|  | Type:     schema.TypeString, | 
|  | Required: true, | 
|  | ForceNew: true, | 
|  | }, | 
|  |  | 
|  | "tags": tagsSchema(), | 
|  | }, | 
|  | } | 
|  | } | 
|  |  | 
|  | func resourceCloudStackVPCCreate(d *schema.ResourceData, meta interface{}) error { | 
|  | cs := meta.(*cloudstack.CloudStackClient) | 
|  |  | 
|  | name := d.Get("name").(string) | 
|  |  | 
|  | // Retrieve the vpc_offering ID | 
|  | vpcofferingid, e := retrieveID(cs, "vpc_offering", d.Get("vpc_offering").(string)) | 
|  | if e != nil { | 
|  | return e.Error() | 
|  | } | 
|  |  | 
|  | // Retrieve the zone ID | 
|  | zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string)) | 
|  | if e != nil { | 
|  | return e.Error() | 
|  | } | 
|  |  | 
|  | // Set the display text | 
|  | displaytext, ok := d.GetOk("display_text") | 
|  | if !ok { | 
|  | displaytext = name | 
|  | } | 
|  |  | 
|  | // Create a new parameter struct | 
|  | p := cs.VPC.NewCreateVPCParams( | 
|  | d.Get("cidr").(string), | 
|  | displaytext.(string), | 
|  | name, | 
|  | vpcofferingid, | 
|  | zoneid, | 
|  | ) | 
|  |  | 
|  | // If there is a network domain supplied, make sure to add it to the request | 
|  | if networkDomain, ok := d.GetOk("network_domain"); ok { | 
|  | // Set the network domain | 
|  | p.SetNetworkdomain(networkDomain.(string)) | 
|  | } | 
|  |  | 
|  | // If there is a project supplied, we retrieve and set the project id | 
|  | if err := setProjectid(p, cs, d); err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Create the new VPC | 
|  | r, err := cs.VPC.CreateVPC(p) | 
|  | if err != nil { | 
|  | return fmt.Errorf("Error creating VPC %s: %s", name, err) | 
|  | } | 
|  |  | 
|  | d.SetId(r.Id) | 
|  |  | 
|  | // Set tags if necessary | 
|  | err = setTags(cs, d, "Vpc") | 
|  | if err != nil { | 
|  | return fmt.Errorf("Error setting tags on the VPC: %s", err) | 
|  | } | 
|  |  | 
|  | return resourceCloudStackVPCRead(d, meta) | 
|  | } | 
|  |  | 
|  | func resourceCloudStackVPCRead(d *schema.ResourceData, meta interface{}) error { | 
|  | cs := meta.(*cloudstack.CloudStackClient) | 
|  |  | 
|  | // Get the VPC details | 
|  | v, count, err := cs.VPC.GetVPCByID( | 
|  | d.Id(), | 
|  | cloudstack.WithProject(d.Get("project").(string)), | 
|  | ) | 
|  | if err != nil { | 
|  | if count == 0 { | 
|  | log.Printf( | 
|  | "[DEBUG] VPC %s does no longer exist", d.Get("name").(string)) | 
|  | d.SetId("") | 
|  | return nil | 
|  | } | 
|  |  | 
|  | return err | 
|  | } | 
|  |  | 
|  | d.Set("name", v.Name) | 
|  | d.Set("display_text", v.Displaytext) | 
|  | d.Set("cidr", v.Cidr) | 
|  | d.Set("network_domain", v.Networkdomain) | 
|  |  | 
|  | tags := make(map[string]interface{}) | 
|  | for _, tag := range v.Tags { | 
|  | tags[tag.Key] = tag.Value | 
|  | } | 
|  | d.Set("tags", tags) | 
|  |  | 
|  | // Get the VPC offering details | 
|  | o, _, err := cs.VPC.GetVPCOfferingByID(v.Vpcofferingid) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | setValueOrID(d, "vpc_offering", o.Name, v.Vpcofferingid) | 
|  | setValueOrID(d, "project", v.Project, v.Projectid) | 
|  | setValueOrID(d, "zone", v.Zonename, v.Zoneid) | 
|  |  | 
|  | // Create a new parameter struct | 
|  | p := cs.Address.NewListPublicIpAddressesParams() | 
|  | p.SetVpcid(d.Id()) | 
|  | p.SetIssourcenat(true) | 
|  |  | 
|  | // If there is a project supplied, we retrieve and set the project id | 
|  | if err := setProjectid(p, cs, d); err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Get the source NAT IP assigned to the VPC | 
|  | l, err := cs.Address.ListPublicIpAddresses(p) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | if l.Count == 1 { | 
|  | d.Set("source_nat_ip", l.PublicIpAddresses[0].Ipaddress) | 
|  | } | 
|  |  | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func resourceCloudStackVPCUpdate(d *schema.ResourceData, meta interface{}) error { | 
|  | cs := meta.(*cloudstack.CloudStackClient) | 
|  |  | 
|  | name := d.Get("name").(string) | 
|  |  | 
|  | // Check if the name is changed | 
|  | if d.HasChange("name") { | 
|  | // Create a new parameter struct | 
|  | p := cs.VPC.NewUpdateVPCParams(d.Id()) | 
|  |  | 
|  | // Set the new name | 
|  | p.SetName(name) | 
|  |  | 
|  | // Update the VPC | 
|  | _, err := cs.VPC.UpdateVPC(p) | 
|  | if err != nil { | 
|  | return fmt.Errorf( | 
|  | "Error updating name of VPC %s: %s", name, err) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Check if the display text is changed | 
|  | if d.HasChange("display_text") { | 
|  | // Create a new parameter struct | 
|  | p := cs.VPC.NewUpdateVPCParams(d.Id()) | 
|  |  | 
|  | // Set the display text | 
|  | displaytext, ok := d.GetOk("display_text") | 
|  | if !ok { | 
|  | displaytext = d.Get("name") | 
|  | } | 
|  |  | 
|  | // Set the new display text | 
|  | p.SetDisplaytext(displaytext.(string)) | 
|  |  | 
|  | // Update the VPC | 
|  | _, err := cs.VPC.UpdateVPC(p) | 
|  | if err != nil { | 
|  | return fmt.Errorf( | 
|  | "Error updating display test of VPC %s: %s", name, err) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Check is the tags have changed | 
|  | if d.HasChange("tags") { | 
|  | err := updateTags(cs, d, "Vpc") | 
|  | if err != nil { | 
|  | return fmt.Errorf("Error updating tags on VPC %s: %s", name, err) | 
|  | } | 
|  | d.SetPartial("tags") | 
|  | } | 
|  |  | 
|  | return resourceCloudStackVPCRead(d, meta) | 
|  | } | 
|  |  | 
|  | func resourceCloudStackVPCDelete(d *schema.ResourceData, meta interface{}) error { | 
|  | cs := meta.(*cloudstack.CloudStackClient) | 
|  |  | 
|  | // Create a new parameter struct | 
|  | p := cs.VPC.NewDeleteVPCParams(d.Id()) | 
|  |  | 
|  | // Delete the VPC | 
|  | _, err := cs.VPC.DeleteVPC(p) | 
|  | if err != nil { | 
|  | // This is a very poor way to be told the ID does no longer exist :( | 
|  | if strings.Contains(err.Error(), fmt.Sprintf( | 
|  | "Invalid parameter id value=%s due to incorrect long value format, "+ | 
|  | "or entity does not exist", d.Id())) { | 
|  | return nil | 
|  | } | 
|  |  | 
|  | return fmt.Errorf("Error deleting VPC %s: %s", d.Get("name").(string), err) | 
|  | } | 
|  |  | 
|  | return nil | 
|  | } |