cloudstack/resource_cloudstack_ipaddress.go (156 lines of code) (raw):

// // 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-plugin-sdk/v2/helper/schema" ) func resourceCloudStackIPAddress() *schema.Resource { return &schema.Resource{ Create: resourceCloudStackIPAddressCreate, Read: resourceCloudStackIPAddressRead, Delete: resourceCloudStackIPAddressDelete, Schema: map[string]*schema.Schema{ "is_portable": { Type: schema.TypeBool, Optional: true, Default: false, ForceNew: true, }, "network_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "vpc_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "zone": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, "ip_address": { Type: schema.TypeString, Computed: true, }, "is_source_nat": { Type: schema.TypeBool, Computed: true, }, "tags": tagsSchema(), }, } } func resourceCloudStackIPAddressCreate(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) if err := verifyIPAddressParams(d); err != nil { return err } // Create a new parameter struct p := cs.Address.NewAssociateIpAddressParams() if d.Get("is_portable").(bool) { p.SetIsportable(true) } if networkid, ok := d.GetOk("network_id"); ok { // Set the networkid p.SetNetworkid(networkid.(string)) if vpcid, ok := d.GetOk("vpc_id"); ok && vpcid.(string) != "" { return fmt.Errorf("set only network_id or vpc_id") } } if vpcid, ok := d.GetOk("vpc_id"); ok { // Set the vpcid p.SetVpcid(vpcid.(string)) } if zone, ok := d.GetOk("zone"); ok { // Retrieve the zone ID zoneid, e := retrieveID(cs, "zone", zone.(string)) if e != nil { return e.Error() } // Set the zoneid p.SetZoneid(zoneid) } // If there is a project supplied, we retrieve and set the project id if err := setProjectid(p, cs, d); err != nil { return err } // Associate a new IP address r, err := cs.Address.AssociateIpAddress(p) if err != nil { return fmt.Errorf("Error associating a new IP address: %s", err) } d.SetId(r.Id) // Set tags if necessary err = setTags(cs, d, "PublicIpAddress") if err != nil { return fmt.Errorf("Error setting tags on the IP address: %s", err) } return resourceCloudStackIPAddressRead(d, meta) } func resourceCloudStackIPAddressRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the IP address details ip, count, err := cs.Address.GetPublicIpAddressByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf( "[DEBUG] IP address with ID %s is no longer associated", d.Id()) d.SetId("") return nil } return err } d.Set("is_portable", ip.Isportable) d.Set("is_source_nat", ip.Issourcenat) // Updated the IP address d.Set("ip_address", ip.Ipaddress) if _, ok := d.GetOk("network_id"); ok { d.Set("network_id", ip.Associatednetworkid) } if _, ok := d.GetOk("vpc_id"); ok { d.Set("vpc_id", ip.Vpcid) } if _, ok := d.GetOk("zone"); ok { setValueOrID(d, "zone", ip.Zonename, ip.Zoneid) } tags := make(map[string]interface{}) for _, tag := range ip.Tags { tags[tag.Key] = tag.Value } d.Set("tags", tags) setValueOrID(d, "project", ip.Project, ip.Projectid) return nil } func resourceCloudStackIPAddressDelete(d *schema.ResourceData, meta interface{}) error { if !d.Get("is_source_nat").(bool) { cs := meta.(*cloudstack.CloudStackClient) // Create a new parameter struct p := cs.Address.NewDisassociateIpAddressParams(d.Id()) // Disassociate the IP address if _, err := cs.Address.DisassociateIpAddress(p); 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 disassociating IP address %s: %s", d.Id(), err) } } return nil } func verifyIPAddressParams(d *schema.ResourceData) error { _, portable := d.GetOk("is_portable") _, network := d.GetOk("network_id") _, vpc := d.GetOk("vpc_id") _, zone := d.GetOk("zone") if portable && ((network && vpc) || (!network && !vpc)) { return fmt.Errorf( "You must supply a value for either (so not both) the 'network_id' or 'vpc_id' parameter for a portable IP") } if !portable && !zone && !network { return fmt.Errorf("You must supply a value for the 'network_id' and/or 'zone' parameters for a non portable IP") } return nil }