func createPortForward( d *schema.ResourceData, meta interface{}, forward map[string]interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Make sure all required parameters are there if err := verifyPortForwardParams(d, forward); err != nil { return err } virtualmachine, ok := forward["virtual_machine_id"] if !ok { virtualmachine, ok = forward["virtual_machine"] } if !ok { return errors.New( "Either `virtual_machine_id` or [deprecated] `virtual_machine` must be provided.") } // Retrieve the virtual_machine ID virtualmachineid, e := retrieveID( cs, "virtual_machine", virtualmachine.(string), cloudstack.WithProject(d.Get("project").(string)), ) if e != nil { return e.Error() } vm, _, err := cs.VirtualMachine.GetVirtualMachineByID( virtualmachineid, cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { return err } // Create a new parameter struct p := cs.Firewall.NewCreatePortForwardingRuleParams(d.Id(), forward["private_port"].(int), forward["protocol"].(string), forward["public_port"].(int), vm.Id) // Set the network ID of the default network, needed when public IP address // is not associated with any Guest network yet (VPC case) p.SetNetworkid(vm.Nic[0].Networkid) // Do not open the firewall automatically in any case p.SetOpenfirewall(false) r, err := cs.Firewall.CreatePortForwardingRule(p) if err != nil { return err } forward["uuid"] = r.Id return nil }
func resourceCloudStackDiskRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the volume details v, count, err := cs.Volume.GetVolumeByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { d.SetId("") return nil } return err } d.Set("name", v.Name) d.Set("attach", v.Attached != "") // If attached this contains a timestamp when attached d.Set("size", int(v.Size/(1024*1024*1024))) // Needed to get GB's again setValueOrID(d, "disk_offering", v.Diskofferingname, v.Diskofferingid) setValueOrID(d, "project", v.Project, v.Projectid) setValueOrID(d, "zone", v.Zonename, v.Zoneid) if v.Attached != "" { // Get the virtual machine details vm, _, err := cs.VirtualMachine.GetVirtualMachineByID( v.Virtualmachineid, cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { return err } // Get the guest OS type details os, _, err := cs.GuestOS.GetOsTypeByID(vm.Guestosid) if err != nil { return err } // Get the guest OS category details c, _, err := cs.GuestOS.GetOsCategoryByID(os.Oscategoryid) if err != nil { return err } d.Set("device", retrieveDeviceName(v.Deviceid, c.Name)) setValueOrID(d, "virtual_machine", v.Vmname, v.Virtualmachineid) } return nil }
func resourceCloudStackInstanceRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the virtual machine details vm, count, err := cs.VirtualMachine.GetVirtualMachineByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf("[DEBUG] Instance %s does no longer exist", d.Get("name").(string)) d.SetId("") return nil } return err } // Update the config d.Set("name", vm.Name) d.Set("display_name", vm.Displayname) d.Set("network_id", vm.Nic[0].Networkid) d.Set("ip_address", vm.Nic[0].Ipaddress) d.Set("group", vm.Group) setValueOrID(d, "service_offering", vm.Serviceofferingname, vm.Serviceofferingid) setValueOrID(d, "template", vm.Templatename, vm.Templateid) setValueOrID(d, "project", vm.Project, vm.Projectid) setValueOrID(d, "zone", vm.Zonename, vm.Zoneid) return nil }
// associatePublicIPAddress associates a new IP and sets the address and it's ID. func (lb *loadBalancer) associatePublicIPAddress() error { glog.V(4).Infof("Allocate new IP for load balancer: %v", lb.name) // If a network belongs to a VPC, the IP address needs to be associated with // the VPC instead of with the network. network, count, err := lb.Network.GetNetworkByID(lb.networkID, cloudstack.WithProject(lb.projectID)) if err != nil { if count == 0 { return fmt.Errorf("could not find network %v", lb.networkID) } return fmt.Errorf("error retrieving network: %v", err) } p := lb.Address.NewAssociateIpAddressParams() if network.Vpcid != "" { p.SetVpcid(network.Vpcid) } else { p.SetNetworkid(lb.networkID) } if lb.projectID != "" { p.SetProjectid(lb.projectID) } // Associate a new IP address r, err := lb.Address.AssociateIpAddress(p) if err != nil { return fmt.Errorf("error associating new IP address: %v", err) } lb.ipAddr = r.Ipaddress lb.ipAddrID = r.Id return nil }
func resourceCloudStackNetworkACLRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the network ACL list details f, count, err := cs.NetworkACL.GetNetworkACLListByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf( "[DEBUG] Network ACL list %s does no longer exist", d.Get("name").(string)) d.SetId("") return nil } return err } d.Set("name", f.Name) d.Set("description", f.Description) d.Set("vpc_id", f.Vpcid) return nil }
func resourceCloudStackStaticNATRead(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 no longer exists", d.Id()) d.SetId("") return nil } return err } if !ip.Isstaticnat { log.Printf("[DEBUG] Static NAT is no longer enabled for IP address with ID %s", d.Id()) d.SetId("") return nil } d.Set("virtual_machine_id", ip.Virtualmachineid) d.Set("vm_guest_ip", ip.Vmipaddress) setValueOrID(d, "project", ip.Project, ip.Projectid) return nil }
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 } // 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) } setValueOrID(d, "project", ip.Project, ip.Projectid) return nil }
func resourceCloudStackAffinityGroupRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) log.Printf("[DEBUG] Rerieving affinity group %s", d.Get("name").(string)) // Get the affinity group details ag, count, err := cs.AffinityGroup.GetAffinityGroupByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf("[DEBUG] Affinity group %s does not longer exist", d.Get("name").(string)) d.SetId("") return nil } return err } // Update the config d.Set("name", ag.Name) d.Set("description", ag.Description) d.Set("type", ag.Type) return nil }
func resourceCloudStackLoadBalancerRuleRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the load balancer details lb, count, err := cs.LoadBalancer.GetLoadBalancerRuleByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf("[DEBUG] Load balancer rule %s does no longer exist", d.Get("name").(string)) d.SetId("") return nil } return err } d.Set("algorithm", lb.Algorithm) d.Set("public_port", lb.Publicport) d.Set("private_port", lb.Privateport) d.Set("ip_address_id", lb.Publicipid) // Only set network if user specified it to avoid spurious diffs if _, ok := d.GetOk("network_id"); ok { d.Set("network_id", lb.Networkid) } setValueOrID(d, "project", lb.Project, lb.Projectid) return nil }
func resourceCloudStackDiskRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the volume details v, count, err := cs.Volume.GetVolumeByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { d.SetId("") return nil } return err } d.Set("name", v.Name) d.Set("attach", v.Attached != "") // If attached this contains a timestamp when attached d.Set("size", int(v.Size/(1024*1024*1024))) // Needed to get GB's again setValueOrID(d, "disk_offering", v.Diskofferingname, v.Diskofferingid) setValueOrID(d, "project", v.Project, v.Projectid) setValueOrID(d, "zone", v.Zonename, v.Zoneid) if v.Attached != "" { d.Set("device_id", int(v.Deviceid)) d.Set("virtual_machine_id", v.Virtualmachineid) } return nil }
func resourceCloudStackSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the security group details sg, count, err := cs.SecurityGroup.GetSecurityGroupByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf("[DEBUG] Security group %s does not longer exist", d.Get("name").(string)) d.SetId("") return nil } return err } // Make a map of all the rule indexes so we can easily find a rule sgRules := append(sg.Ingressrule, sg.Egressrule...) ruleIndex := make(map[string]int, len(sgRules)) for idx, r := range sgRules { ruleIndex[r.Ruleid] = idx } // Create an empty schema.Set to hold all rules rules := resourceCloudStackSecurityGroupRule().Schema["rule"].ZeroValue().(*schema.Set) // Read all rules that are configured if rs := d.Get("rule").(*schema.Set); rs.Len() > 0 { for _, rule := range rs.List() { rule := rule.(map[string]interface{}) // First get any existing values cidrList, cidrListOK := rule["cidr_list"].(*schema.Set) usgList, usgListOk := rule["user_security_group_list"].(*schema.Set) // Then reset the values to a new empty set rule["cidr_list"] = &schema.Set{F: schema.HashString} rule["user_security_group_list"] = &schema.Set{F: schema.HashString} if cidrListOK && cidrList.Len() > 0 { for _, cidr := range cidrList.List() { readSecurityGroupRule(sg, ruleIndex, rule, cidr.(string)) } } if usgListOk && usgList.Len() > 0 { for _, usg := range usgList.List() { readSecurityGroupRule(sg, ruleIndex, rule, usg.(string)) } } rules.Add(rule) } } return nil }
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) // 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 { return fmt.Errorf("Unexpected number (%d) of source NAT IPs returned", l.Count) } d.Set("source_nat_ip", l.PublicIpAddresses[0].Ipaddress) return nil }
func createPortForward(d *schema.ResourceData, meta interface{}, forward map[string]interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Make sure all required parameters are there if err := verifyPortForwardParams(d, forward); err != nil { return err } vm, _, err := cs.VirtualMachine.GetVirtualMachineByID( forward["virtual_machine_id"].(string), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { return err } // Create a new parameter struct p := cs.Firewall.NewCreatePortForwardingRuleParams(d.Id(), forward["private_port"].(int), forward["protocol"].(string), forward["public_port"].(int), vm.Id) if vmGuestIP, ok := forward["vm_guest_ip"]; ok { p.SetVmguestip(vmGuestIP.(string)) // Set the network ID based on the guest IP, needed when the public IP address // is not associated with any network yet NICS: for _, nic := range vm.Nic { if vmGuestIP.(string) == nic.Ipaddress { p.SetNetworkid(nic.Networkid) break NICS } for _, ip := range nic.Secondaryip { if vmGuestIP.(string) == ip.Ipaddress { p.SetNetworkid(nic.Networkid) break NICS } } } } else { // If no guest IP is configured, use the primary NIC p.SetNetworkid(vm.Nic[0].Networkid) } // Do not open the firewall automatically in any case p.SetOpenfirewall(false) r, err := cs.Firewall.CreatePortForwardingRule(p) if err != nil { return err } forward["uuid"] = r.Id return nil }
func resourceCloudStackDiskDetach(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Check if the volume is actually attached, before detaching if attached, err := isAttached(d, meta); err != nil || !attached { return err } // Create a new parameter struct p := cs.Volume.NewDetachVolumeParams() // Set the volume ID p.SetId(d.Id()) // Detach the currently attached volume if _, err := cs.Volume.DetachVolume(p); err != nil { // Retrieve the virtual_machine ID virtualmachineid, e := retrieveID( cs, "virtual_machine", d.Get("virtual_machine").(string), cloudstack.WithProject(d.Get("project").(string)), ) if e != nil { return e.Error() } // Create a new parameter struct pd := cs.VirtualMachine.NewStopVirtualMachineParams(virtualmachineid) // Stop the virtual machine in order to be able to detach the disk if _, err := cs.VirtualMachine.StopVirtualMachine(pd); err != nil { return err } // Try again to detach the currently attached volume if _, err := cs.Volume.DetachVolume(p); err != nil { return err } // Create a new parameter struct pu := cs.VirtualMachine.NewStartVirtualMachineParams(virtualmachineid) // Start the virtual machine again if _, err := cs.VirtualMachine.StartVirtualMachine(pu); err != nil { return err } } return nil }
func isAttached(d *schema.ResourceData, meta interface{}) (bool, error) { cs := meta.(*cloudstack.CloudStackClient) // Get the volume details v, _, err := cs.Volume.GetVolumeByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { return false, err } return v.Attached != "", nil }
func resourceCloudStackNetworkRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the virtual machine details n, count, err := cs.Network.GetNetworkByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf( "[DEBUG] Network %s does no longer exist", d.Get("name").(string)) d.SetId("") return nil } return err } d.Set("name", n.Name) d.Set("display_text", n.Displaytext) d.Set("cidr", n.Cidr) d.Set("gateway", n.Gateway) _, vpcID := d.GetOk("vpc_id") _, vpc := d.GetOk("vpc") if vpcID || vpc { d.Set("vpc_id", n.Vpcid) // Since we're in a VPC, also update the ACL ID. If we don't // have an ACL ID make sure we set the default value instead. if n.Aclid == "" { n.Aclid = none } d.Set("acl_id", n.Aclid) } // Read the tags and store them in a map tags := make(map[string]interface{}) for item := range n.Tags { tags[n.Tags[item].Key] = n.Tags[item].Value } d.Set("tags", tags) setValueOrID(d, "network_offering", n.Networkofferingname, n.Networkofferingid) setValueOrID(d, "project", n.Project, n.Projectid) setValueOrID(d, "zone", n.Zonename, n.Zoneid) return nil }
func resourceCloudStackStaticNATCreate(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) ipaddressid := d.Get("ip_address_id").(string) vm, _, err := cs.VirtualMachine.GetVirtualMachineByID( d.Get("virtual_machine_id").(string), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { return err } // Create a new parameter struct p := cs.NAT.NewEnableStaticNatParams(ipaddressid, vm.Id) if vmGuestIP, ok := d.GetOk("vm_guest_ip"); ok { p.SetVmguestip(vmGuestIP.(string)) // Set the network ID based on the guest IP, needed when the public IP address // is not associated with any network yet NICS: for _, nic := range vm.Nic { if vmGuestIP.(string) == nic.Ipaddress { p.SetNetworkid(nic.Networkid) break NICS } for _, ip := range nic.Secondaryip { if vmGuestIP.(string) == ip.Ipaddress { p.SetNetworkid(nic.Networkid) break NICS } } } } else { // If no guest IP is configured, use the primary NIC p.SetNetworkid(vm.Nic[0].Networkid) } _, err = cs.NAT.EnableStaticNat(p) if err != nil { return fmt.Errorf("Error enabling static NAT: %s", err) } d.SetId(ipaddressid) return resourceCloudStackStaticNATRead(d, meta) }
func resourceCloudStackDiskAttach(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // First check if the disk isn't already attached if attached, err := isAttached(d, meta); err != nil || attached { return err } // Retrieve the virtual_machine ID virtualmachineid, e := retrieveID( cs, "virtual_machine", d.Get("virtual_machine").(string), cloudstack.WithProject(d.Get("project").(string)), ) if e != nil { return e.Error() } // Create a new parameter struct p := cs.Volume.NewAttachVolumeParams(d.Id(), virtualmachineid) if device, ok := d.GetOk("device"); ok { // Retrieve the device ID deviceid := retrieveDeviceID(device.(string)) if deviceid == -1 { return fmt.Errorf("Device %s is not a valid device", device.(string)) } // Set the device ID p.SetDeviceid(deviceid) } // Attach the new volume r, err := Retry(4, retryableAttachVolumeFunc(cs, p)) if err != nil { return err } d.SetId(r.(*cloudstack.AttachVolumeResponse).Id) return nil }
func resourceCloudStackStaticNATExists(d *schema.ResourceData, meta interface{}) (bool, 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 no longer exists", d.Id()) return false, nil } return false, err } return ip.Isstaticnat, nil }
func resourceCloudStackPortForwardCreate(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) ipaddress, ok := d.GetOk("ip_address_id") if !ok { ipaddress, ok = d.GetOk("ipaddress") } if !ok { return errors.New("Either `ip_address_id` or [deprecated] `ipaddress` must be provided.") } // Retrieve the ipaddress ID ipaddressid, e := retrieveID( cs, "ip_address", ipaddress.(string), cloudstack.WithProject(d.Get("project").(string)), ) if e != nil { return e.Error() } // We need to set this upfront in order to be able to save a partial state d.SetId(ipaddressid) // Create all forwards that are configured if nrs := d.Get("forward").(*schema.Set); nrs.Len() > 0 { // Create an empty schema.Set to hold all forwards forwards := resourceCloudStackPortForward().Schema["forward"].ZeroValue().(*schema.Set) err := createPortForwards(d, meta, forwards, nrs) // We need to update this first to preserve the correct state d.Set("forward", forwards) if err != nil { return err } } return resourceCloudStackPortForwardRead(d, meta) }
func resourceCloudStackTemplateRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Get the template details t, count, err := cs.Template.GetTemplateByID( d.Id(), "executable", cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf( "[DEBUG] Template %s no longer exists", d.Get("name").(string)) d.SetId("") return nil } return err } d.Set("name", t.Name) d.Set("display_text", t.Displaytext) d.Set("format", t.Format) d.Set("hypervisor", t.Hypervisor) d.Set("is_dynamically_scalable", t.Isdynamicallyscalable) d.Set("is_extractable", t.Isextractable) d.Set("is_featured", t.Isfeatured) d.Set("is_public", t.Ispublic) d.Set("password_enabled", t.Passwordenabled) d.Set("is_ready", t.Isready) setValueOrID(d, "os_type", t.Ostypename, t.Ostypeid) setValueOrID(d, "project", t.Project, t.Projectid) setValueOrID(d, "zone", t.Zonename, t.Zoneid) return nil }
func resourceCloudStackInstanceCreate(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // Retrieve the service_offering ID serviceofferingid, e := retrieveID(cs, "service_offering", d.Get("service_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() } // Retrieve the zone object zone, _, err := cs.Zone.GetZoneByID(zoneid) if err != nil { return err } // Retrieve the template ID templateid, e := retrieveTemplateID(cs, zone.Id, d.Get("template").(string)) if e != nil { return e.Error() } // Create a new parameter struct p := cs.VirtualMachine.NewDeployVirtualMachineParams(serviceofferingid, templateid, zone.Id) // Set the name name, hasName := d.GetOk("name") if hasName { p.SetName(name.(string)) } // Set the display name if displayname, ok := d.GetOk("display_name"); ok { p.SetDisplayname(displayname.(string)) } else if hasName { p.SetDisplayname(name.(string)) } if zone.Networktype == "Advanced" { network, ok := d.GetOk("network_id") if !ok { network, ok = d.GetOk("network") } if !ok { return errors.New( "Either `network_id` or [deprecated] `network` must be provided when using a zone with network type `advanced`.") } // Retrieve the network ID networkid, e := retrieveID( cs, "network", network.(string), cloudstack.WithProject(d.Get("project").(string)), ) if e != nil { return e.Error() } // Set the default network ID p.SetNetworkids([]string{networkid}) } // If there is a ipaddres supplied, add it to the parameter struct ipaddress, ok := d.GetOk("ip_address") if !ok { ipaddress, ok = d.GetOk("ipaddress") } if ok { p.SetIpaddress(ipaddress.(string)) } if ags := d.Get("affinity_group_ids").(*schema.Set); ags.Len() > 0 { var groups []string for _, group := range ags.List() { groups = append(groups, group.(string)) } p.SetAffinitygroupids(groups) } // If there is a project supplied, we retrieve and set the project id if err := setProjectid(p, cs, d); err != nil { return err } // If a keypair is supplied, add it to the parameter struct if keypair, ok := d.GetOk("keypair"); ok { p.SetKeypair(keypair.(string)) } // If the user data contains any info, it needs to be base64 encoded and // added to the parameter struct if userData, ok := d.GetOk("user_data"); ok { ud := base64.StdEncoding.EncodeToString([]byte(userData.(string))) // deployVirtualMachine uses POST by default, so max userdata is 32K maxUD := 32768 if cs.HTTPGETOnly { // deployVirtualMachine using GET instead, so max userdata is 2K maxUD = 2048 } if len(ud) > maxUD { return fmt.Errorf( "The supplied user_data contains %d bytes after encoding, "+ "this exeeds the limit of %d bytes", len(ud), maxUD) } p.SetUserdata(ud) } // If there is a group supplied, add it to the parameter struct if group, ok := d.GetOk("group"); ok { p.SetGroup(group.(string)) } // If there is a root_disk_size supplied, add it to the parameter struct if rootdisksize, ok := d.GetOk("root_disk_size"); ok { p.SetRootdisksize(int64(rootdisksize.(int))) } // Create the new instance r, err := cs.VirtualMachine.DeployVirtualMachine(p) if err != nil { return fmt.Errorf("Error creating the new instance %s: %s", name, err) } d.SetId(r.Id) // Set the connection info for any configured provisioners d.SetConnInfo(map[string]string{ "host": r.Nic[0].Ipaddress, "password": r.Password, }) return resourceCloudStackInstanceRead(d, meta) }
func (s *stepPrepareConfig) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*cloudstack.CloudStackClient) config := state.Get("config").(*Config) ui := state.Get("ui").(packer.Ui) ui.Say("Preparing config...") var err error var errs *packer.MultiError // First get the project and zone UUID's so we can use them in other calls when needed. if config.Project != "" && !isUUID(config.Project) { config.Project, _, err = client.Project.GetProjectID(config.Project) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"project", config.Project, err}) } } if config.UserDataFile != "" { userdata, err := ioutil.ReadFile(config.UserDataFile) if err != nil { errs = packer.MultiErrorAppend(errs, fmt.Errorf("problem reading user data file: %s", err)) } config.UserData = string(userdata) } if !isUUID(config.Zone) { config.Zone, _, err = client.Zone.GetZoneID(config.Zone) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"zone", config.Zone, err}) } } // Then try to get the remaining UUID's. if config.DiskOffering != "" && !isUUID(config.DiskOffering) { config.DiskOffering, _, err = client.DiskOffering.GetDiskOfferingID(config.DiskOffering) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"disk offering", config.DiskOffering, err}) } } if config.PublicIPAddress != "" && !isUUID(config.PublicIPAddress) { // Save the public IP address before replacing it with it's UUID. config.hostAddress = config.PublicIPAddress p := client.Address.NewListPublicIpAddressesParams() p.SetIpaddress(config.PublicIPAddress) if config.Project != "" { p.SetProjectid(config.Project) } ipAddrs, err := client.Address.ListPublicIpAddresses(p) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, err}) } if err == nil && ipAddrs.Count != 1 { errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, ipAddrs}) } if err == nil && ipAddrs.Count == 1 { config.PublicIPAddress = ipAddrs.PublicIpAddresses[0].Id } } if !isUUID(config.Network) { config.Network, _, err = client.Network.GetNetworkID(config.Network, cloudstack.WithProject(config.Project)) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"network", config.Network, err}) } } if !isUUID(config.ServiceOffering) { config.ServiceOffering, _, err = client.ServiceOffering.GetServiceOfferingID(config.ServiceOffering) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"service offering", config.ServiceOffering, err}) } } if config.SourceISO != "" { if isUUID(config.SourceISO) { config.instanceSource = config.SourceISO } else { config.instanceSource, _, err = client.ISO.GetIsoID(config.SourceISO, "executable", config.Zone) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"ISO", config.SourceISO, err}) } } } if config.SourceTemplate != "" { if isUUID(config.SourceTemplate) { config.instanceSource = config.SourceTemplate } else { config.instanceSource, _, err = client.Template.GetTemplateID(config.SourceTemplate, "executable", config.Zone) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"template", config.SourceTemplate, err}) } } } if !isUUID(config.TemplateOS) { p := client.GuestOS.NewListOsTypesParams() p.SetDescription(config.TemplateOS) types, err := client.GuestOS.ListOsTypes(p) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"OS type", config.TemplateOS, err}) } if err == nil && types.Count != 1 { errs = packer.MultiErrorAppend(errs, &retrieveErr{"OS type", config.TemplateOS, types}) } if err == nil && types.Count == 1 { config.TemplateOS = types.OsTypes[0].Id } } // This is needed because nil is not always nil. When returning *packer.MultiError(nil) // as an error interface, that interface will no longer be equal to nil but it will be // an interface with type *packer.MultiError and value nil which is different then a // nil interface. if errs != nil && len(errs.Errors) > 0 { ui.Error(errs.Error()) return multistep.ActionHalt } ui.Message("Config has been prepared!") return multistep.ActionContinue }
func createSecurityGroupRules(d *schema.ResourceData, meta interface{}, rules *schema.Set, nrs *schema.Set) error { cs := meta.(*cloudstack.CloudStackClient) var errs *multierror.Error var wg sync.WaitGroup wg.Add(nrs.Len()) sem := make(chan struct{}, d.Get("parallelism").(int)) for _, rule := range nrs.List() { // Put in a tiny sleep here to avoid DoS'ing the API time.Sleep(500 * time.Millisecond) go func(rule map[string]interface{}) { defer wg.Done() sem <- struct{}{} // Make sure all required parameters are there if err := verifySecurityGroupRuleParams(d, rule); err != nil { errs = multierror.Append(errs, err) return } var p authorizeSecurityGroupParams if cidrList, ok := rule["cidr_list"].(*schema.Set); ok && cidrList.Len() > 0 { for _, cidr := range cidrList.List() { // Create a new parameter struct switch rule["traffic_type"].(string) { case "ingress": p = cs.SecurityGroup.NewAuthorizeSecurityGroupIngressParams() case "egress": p = cs.SecurityGroup.NewAuthorizeSecurityGroupEgressParams() } p.SetSecuritygroupid(d.Id()) p.SetCidrlist([]string{cidr.(string)}) // Create a single rule err := createSecurityGroupRule(d, meta, rule, p, cidr.(string)) if err != nil { errs = multierror.Append(errs, err) } } } if usgList, ok := rule["user_security_group_list"].(*schema.Set); ok && usgList.Len() > 0 { for _, usg := range usgList.List() { sg, _, err := cs.SecurityGroup.GetSecurityGroupByName( usg.(string), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { errs = multierror.Append(errs, err) continue } // Create a new parameter struct switch rule["traffic_type"].(string) { case "ingress": p = cs.SecurityGroup.NewAuthorizeSecurityGroupIngressParams() case "egress": p = cs.SecurityGroup.NewAuthorizeSecurityGroupEgressParams() } p.SetSecuritygroupid(d.Id()) p.SetUsersecuritygrouplist(map[string]string{sg.Account: usg.(string)}) // Create a single rule err = createSecurityGroupRule(d, meta, rule, p, usg.(string)) if err != nil { errs = multierror.Append(errs, err) } } } // If we have at least one UUID, we need to save the rule if len(rule["uuids"].(map[string]interface{})) > 0 { rules.Add(rule) } <-sem }(rule.(map[string]interface{})) } wg.Wait() return errs.ErrorOrNil() }
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() network, ok := d.GetOk("network_id") if !ok { network, ok = d.GetOk("network") } if ok { // Retrieve the network ID networkid, e := retrieveID( cs, "network", network.(string), cloudstack.WithProject(d.Get("project").(string)), ) if e != nil { return e.Error() } // Set the networkid p.SetNetworkid(networkid) } vpc, ok := d.GetOk("vpc_id") if !ok { vpc, ok = d.GetOk("vpc") } if ok { // Retrieve the vpc ID vpcid, e := retrieveID( cs, "vpc", vpc.(string), cloudstack.WithProject(d.Get("project").(string)), ) if e != nil { return e.Error() } // Set the vpcid p.SetVpcid(vpcid) } // 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) return resourceCloudStackIPAddressRead(d, meta) }
func resourceCloudStackNetworkACLRuleRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // First check if the ACL itself still exists _, count, err := cs.NetworkACL.GetNetworkACLListByID( d.Id(), cloudstack.WithProject(d.Get("project").(string)), ) if err != nil { if count == 0 { log.Printf( "[DEBUG] Network ACL list %s does no longer exist", d.Id()) d.SetId("") return nil } return err } // Get all the rules from the running environment p := cs.NetworkACL.NewListNetworkACLsParams() p.SetAclid(d.Id()) p.SetListall(true) l, err := cs.NetworkACL.ListNetworkACLs(p) if err != nil { return err } // Make a map of all the rules so we can easily find a rule ruleMap := make(map[string]*cloudstack.NetworkACL, l.Count) for _, r := range l.NetworkACLs { ruleMap[r.Id] = r } // Create an empty schema.Set to hold all rules rules := resourceCloudStackNetworkACLRule().Schema["rule"].ZeroValue().(*schema.Set) // Read all rules that are configured if rs := d.Get("rule").(*schema.Set); rs.Len() > 0 { for _, rule := range rs.List() { rule := rule.(map[string]interface{}) uuids := rule["uuids"].(map[string]interface{}) if rule["protocol"].(string) == "icmp" { id, ok := uuids["icmp"] if !ok { continue } // Get the rule r, ok := ruleMap[id.(string)] if !ok { delete(uuids, "icmp") continue } // Delete the known rule so only unknown rules remain in the ruleMap delete(ruleMap, id.(string)) // Create a set with all CIDR's cidrs := &schema.Set{F: schema.HashString} for _, cidr := range strings.Split(r.Cidrlist, ",") { cidrs.Add(cidr) } // Update the values rule["action"] = strings.ToLower(r.Action) rule["protocol"] = r.Protocol rule["icmp_type"] = r.Icmptype rule["icmp_code"] = r.Icmpcode rule["traffic_type"] = strings.ToLower(r.Traffictype) rule["cidr_list"] = cidrs rules.Add(rule) } if rule["protocol"].(string) == "all" { id, ok := uuids["all"] if !ok { continue } // Get the rule r, ok := ruleMap[id.(string)] if !ok { delete(uuids, "all") continue } // Delete the known rule so only unknown rules remain in the ruleMap delete(ruleMap, id.(string)) // Create a set with all CIDR's cidrs := &schema.Set{F: schema.HashString} for _, cidr := range strings.Split(r.Cidrlist, ",") { cidrs.Add(cidr) } // Update the values rule["action"] = strings.ToLower(r.Action) rule["protocol"] = r.Protocol rule["traffic_type"] = strings.ToLower(r.Traffictype) rule["cidr_list"] = cidrs rules.Add(rule) } // If protocol is tcp or udp, loop through all ports if rule["protocol"].(string) == "tcp" || rule["protocol"].(string) == "udp" { if ps := rule["ports"].(*schema.Set); ps.Len() > 0 { // Create an empty schema.Set to hold all ports ports := &schema.Set{F: schema.HashString} // Loop through all ports and retrieve their info for _, port := range ps.List() { id, ok := uuids[port.(string)] if !ok { continue } // Get the rule r, ok := ruleMap[id.(string)] if !ok { delete(uuids, port.(string)) continue } // Delete the known rule so only unknown rules remain in the ruleMap delete(ruleMap, id.(string)) // Create a set with all CIDR's cidrs := &schema.Set{F: schema.HashString} for _, cidr := range strings.Split(r.Cidrlist, ",") { cidrs.Add(cidr) } // Update the values rule["action"] = strings.ToLower(r.Action) rule["protocol"] = r.Protocol rule["traffic_type"] = strings.ToLower(r.Traffictype) rule["cidr_list"] = cidrs ports.Add(port) } // If there is at least one port found, add this rule to the rules set if ports.Len() > 0 { rule["ports"] = ports rules.Add(rule) } } } } } // If this is a managed firewall, add all unknown rules into dummy rules managed := d.Get("managed").(bool) if managed && len(ruleMap) > 0 { for uuid := range ruleMap { // We need to create and add a dummy value to a schema.Set as the // cidr_list is a required field and thus needs a value cidrs := &schema.Set{F: schema.HashString} cidrs.Add(uuid) // Make a dummy rule to hold the unknown UUID rule := map[string]interface{}{ "cidr_list": cidrs, "protocol": uuid, "uuids": map[string]interface{}{uuid: uuid}, } // Add the dummy rule to the rules set rules.Add(rule) } } if rules.Len() > 0 { d.Set("rule", rules) } else if !managed { d.SetId("") } return nil }
func (s *stepSetupNetworking) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*cloudstack.CloudStackClient) config := state.Get("config").(*Config) ui := state.Get("ui").(packer.Ui) ui.Say("Setup networking...") if config.UseLocalIPAddress { ui.Message("Using the local IP address...") ui.Message("Networking has been setup!") return multistep.ActionContinue } // Generate a random public port used to configure our port forward. rand.Seed(time.Now().UnixNano()) s.publicPort = 50000 + rand.Intn(10000) // Set the currently configured port to be the private port. s.privatePort = config.Comm.Port() // Set the SSH or WinRM port to be the randomly generated public port. switch config.Comm.Type { case "ssh": config.Comm.SSHPort = s.publicPort case "winrm": config.Comm.WinRMPort = s.publicPort } // Retrieve the instance ID from the previously saved state. instanceID, ok := state.Get("instance_id").(string) if !ok || instanceID == "" { ui.Error("Could not retrieve instance_id from state!") return multistep.ActionHalt } network, _, err := client.Network.GetNetworkByID( config.Network, cloudstack.WithProject(config.Project), ) if err != nil { ui.Error(fmt.Sprintf("Failed to retrieve the network object: %s", err)) return multistep.ActionHalt } if config.PublicIPAddress == "" { ui.Message("Associating public IP address...") p := client.Address.NewAssociateIpAddressParams() if config.Project != "" { p.SetProjectid(config.Project) } if network.Vpcid != "" { p.SetVpcid(network.Vpcid) } else { p.SetNetworkid(network.Id) } // Associate a new public IP address. ipAddr, err := client.Address.AssociateIpAddress(p) if err != nil { ui.Error(fmt.Sprintf("Failed to associate public IP address: %s", err)) return multistep.ActionHalt } // Set the IP address and it's ID. config.PublicIPAddress = ipAddr.Id config.hostAddress = ipAddr.Ipaddress // Store the IP address ID. state.Put("ip_address_id", ipAddr.Id) } ui.Message("Creating port forward...") p := client.Firewall.NewCreatePortForwardingRuleParams( config.PublicIPAddress, s.privatePort, "TCP", s.publicPort, instanceID, ) // Configure the port forward. p.SetNetworkid(network.Id) p.SetOpenfirewall(false) // Create the port forward. forward, err := client.Firewall.CreatePortForwardingRule(p) if err != nil { ui.Error(fmt.Sprintf("Failed to create port forward: %s", err)) } // Store the port forward ID. state.Put("port_forward_id", forward.Id) if network.Vpcid != "" { ui.Message("Creating network ACL rule...") if network.Aclid == "" { ui.Error("Failed to configure the firewall: no ACL connected to the VPC network") return multistep.ActionHalt } // Create a new parameter struct. p := client.NetworkACL.NewCreateNetworkACLParams("TCP") // Configure the network ACL rule. p.SetAclid(network.Aclid) p.SetAction("allow") p.SetCidrlist(config.CIDRList) p.SetStartport(s.privatePort) p.SetEndport(s.privatePort) p.SetTraffictype("ingress") // Create the network ACL rule. aclRule, err := client.NetworkACL.CreateNetworkACL(p) if err != nil { ui.Error(fmt.Sprintf("Failed to create network ACL rule: %s", err)) return multistep.ActionHalt } // Store the network ACL rule ID. state.Put("network_acl_rule_id", aclRule.Id) } else { ui.Message("Creating firewall rule...") // Create a new parameter struct. p := client.Firewall.NewCreateFirewallRuleParams(config.PublicIPAddress, "TCP") // Configure the firewall rule. p.SetCidrlist(config.CIDRList) p.SetStartport(s.publicPort) p.SetEndport(s.publicPort) fwRule, err := client.Firewall.CreateFirewallRule(p) if err != nil { ui.Error(fmt.Sprintf("Failed to create firewall rule: %s", err)) return multistep.ActionHalt } // Store the firewall rule ID. state.Put("firewall_rule_id", fwRule.Id) } ui.Message("Networking has been setup!") return multistep.ActionContinue }
func resourceCloudStackPortForwardRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) // First check if the IP address is still associated _, 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 } // Get all the forwards from the running environment p := cs.Firewall.NewListPortForwardingRulesParams() p.SetIpaddressid(d.Id()) p.SetListall(true) if err := setProjectid(p, cs, d); err != nil { return err } l, err := cs.Firewall.ListPortForwardingRules(p) if err != nil { return err } // Make a map of all the forwards so we can easily find a forward forwardMap := make(map[string]*cloudstack.PortForwardingRule, l.Count) for _, f := range l.PortForwardingRules { forwardMap[f.Id] = f } // Create an empty schema.Set to hold all forwards forwards := resourceCloudStackPortForward().Schema["forward"].ZeroValue().(*schema.Set) // Read all forwards that are configured if rs := d.Get("forward").(*schema.Set); rs.Len() > 0 { for _, forward := range rs.List() { forward := forward.(map[string]interface{}) id, ok := forward["uuid"] if !ok || id.(string) == "" { continue } // Get the forward f, ok := forwardMap[id.(string)] if !ok { forward["uuid"] = "" continue } // Delete the known rule so only unknown rules remain in the ruleMap delete(forwardMap, id.(string)) privPort, err := strconv.Atoi(f.Privateport) if err != nil { return err } pubPort, err := strconv.Atoi(f.Publicport) if err != nil { return err } // Update the values forward["protocol"] = f.Protocol forward["private_port"] = privPort forward["public_port"] = pubPort forward["virtual_machine_id"] = f.Virtualmachineid forward["vm_guest_ip"] = f.Vmguestip forwards.Add(forward) } } // If this is a managed resource, add all unknown forwards to dummy forwards managed := d.Get("managed").(bool) if managed && len(forwardMap) > 0 { for uuid := range forwardMap { // Make a dummy forward to hold the unknown UUID forward := map[string]interface{}{ "protocol": uuid, "private_port": 0, "public_port": 0, "virtual_machine_id": uuid, "uuid": uuid, } // Add the dummy forward to the forwards set forwards.Add(forward) } } if forwards.Len() > 0 { d.Set("forward", forwards) } else if !managed { d.SetId("") } return nil }
func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) name := d.Get("name").(string) // Retrieve the network_offering ID networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_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() } // Compute/set the display text displaytext, ok := d.GetOk("display_text") if !ok { displaytext = name } // Create a new parameter struct p := cs.Network.NewCreateNetworkParams(displaytext.(string), name, networkofferingid, zoneid) m, err := parseCIDR(d) if err != nil { return err } // Set the needed IP config p.SetStartip(m["startip"]) p.SetGateway(m["gateway"]) p.SetEndip(m["endip"]) p.SetNetmask(m["netmask"]) if vlan, ok := d.GetOk("vlan"); ok { p.SetVlan(strconv.Itoa(vlan.(int))) } // Check is this network needs to be created in a VPC vpc, ok := d.GetOk("vpc_id") if !ok { vpc, ok = d.GetOk("vpc") } if ok { // Retrieve the vpc ID vpcid, e := retrieveID( cs, "vpc", vpc.(string), cloudstack.WithProject(d.Get("project").(string)), ) if e != nil { return e.Error() } // Set the vpcid p.SetVpcid(vpcid) // Since we're in a VPC, check if we want to assiciate an ACL list aclid, ok := d.GetOk("acl_id") if !ok { aclid, ok = d.GetOk("acl") } if ok { // Set the acl ID p.SetAclid(aclid.(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 network r, err := cs.Network.CreateNetwork(p) if err != nil { return fmt.Errorf("Error creating network %s: %s", name, err) } d.SetId(r.Id) err = setTags(cs, d, "network") if err != nil { return fmt.Errorf("Error setting tags: %s", err) } return resourceCloudStackNetworkRead(d, meta) }