lib/vcloud-rest/vcloud/vapp.rb
def compose_vapp_from_vm(vdc, vapp_name, vapp_description, vm_list={}, network_config={})
      builder = Nokogiri::XML::Builder.new do |xml|
      xml.ComposeVAppParams(
        "xmlns" => "http://www.vmware.com/vcloud/v1.5",
        "xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1",
        "name" => vapp_name) {
        xml.Description vapp_description
        xml.InstantiationParams {
          xml.NetworkConfigSection {
            xml['ovf'].Info "Configuration parameters for logical networks"
            xml.NetworkConfig("networkName" => network_config[:name]) {
              xml.Configuration {
                xml.IpScopes {
                  xml.IpScope {
                    xml.IsInherited(network_config[:is_inherited] || "false")
                    xml.Gateway network_config[:gateway]
                    xml.Netmask network_config[:netmask]
                    xml.Dns1 network_config[:dns1] if network_config[:dns1]
                    xml.Dns2 network_config[:dns2] if network_config[:dns2]
                    xml.DnsSuffix network_config[:dns_suffix] if network_config[:dns_suffix]
                    xml.IpRanges {
                      xml.IpRange {
                        xml.StartAddress network_config[:start_address]
                        xml.EndAddress network_config[:end_address]
                      }
                    }
                  }
                }
                xml.ParentNetwork("href" => "#{@api_url}/network/#{network_config[:parent_network]}")
                xml.FenceMode network_config[:fence_mode]

                xml.Features {
                  xml.FirewallService {
                    xml.IsEnabled(network_config[:enable_firewall] || "false")
                  }
                  if network_config.has_key? :nat_type
                    xml.NatService {
                      xml.IsEnabled "true"
                      xml.NatType network_config[:nat_type]
                      xml.Policy(network_config[:nat_policy_type] || "allowTraffic")
                    }
                  end
                }
              }
            }
          }
        }
        vm_list.each do |vm_name, vm_id|
          xml.SourcedItem {
            xml.Source("href" => "#{@api_url}/vAppTemplate/vm-#{vm_id}", "name" => vm_name)
            xml.InstantiationParams {
              xml.NetworkConnectionSection(
                "xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1",
                "type" => "application/vnd.vmware.vcloud.networkConnectionSection+xml",
                "href" => "#{@api_url}/vAppTemplate/vm-#{vm_id}/networkConnectionSection/") {
                  xml['ovf'].Info "Network config for sourced item"
                  xml.PrimaryNetworkConnectionIndex "0"
                  xml.NetworkConnection("network" => network_config[:name]) {
                    xml.NetworkConnectionIndex "0"
                    xml.IsConnected "true"
                    xml.IpAddressAllocationMode(network_config[:ip_allocation_mode] || "POOL")
                }
              }
            }
            xml.NetworkAssignment("containerNetwork" => network_config[:name], "innerNetwork" => network_config[:name])
          }
        end
        xml.AllEULAsAccepted "true"
      }
      end

      params = {
        "method" => :post,
        "command" => "/vdc/#{vdc}/action/composeVApp"
      }

      response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.composeVAppParams+xml")

      vapp_id = headers[:location].gsub(/.*\/vApp\/vapp\-/, "")

      task = response.css("VApp Task[operationName='vdcComposeVapp']").first
      task_id = task["href"].gsub(/.*\/task\//, "")

      { :vapp_id => vapp_id, :task_id => task_id }
    end
def compose_vapp_from_vm(vdc, vapp_name, vapp_description, vm_list={}, network_config={})
      builder = Nokogiri::XML::Builder.new do |xml|
      xml.ComposeVAppParams(
        "xmlns" => "http://www.vmware.com/vcloud/v1.5",
        "xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1",
        "name" => vapp_name) {
        xml.Description vapp_description
        xml.InstantiationParams {
          xml.NetworkConfigSection {
            xml['ovf'].Info "Configuration parameters for logical networks"
            xml.NetworkConfig("networkName" => network_config[:name]) {
              xml.Configuration {
                xml.IpScopes {
                  xml.IpScope {
                    xml.IsInherited(network_config[:is_inherited] || "false")
                    xml.Gateway network_config[:gateway]
                    xml.Netmask network_config[:netmask]
                    xml.Dns1 network_config[:dns1] if network_config[:dns1]
                    xml.Dns2 network_config[:dns2] if network_config[:dns2]
                    xml.DnsSuffix network_config[:dns_suffix] if network_config[:dns_suffix]
                    xml.IpRanges {
                      xml.IpRange {
                        xml.StartAddress network_config[:start_address]
                        xml.EndAddress network_config[:end_address]
                      }
                    }
                  }
                }
                xml.ParentNetwork("href" => "#{@api_url}/network/#{network_config[:parent_network]}")
                xml.FenceMode network_config[:fence_mode]

                xml.Features {
                  xml.FirewallService {
                    xml.IsEnabled(network_config[:enable_firewall] || "false")
                  }
                  if network_config.has_key? :nat_type
                    xml.NatService {
                      xml.IsEnabled "true"
                      xml.NatType network_config[:nat_type]
                      xml.Policy(network_config[:nat_policy_type] || "allowTraffic")
                    }
                  end
                }
              }
            }
          }
        }
        vm_list.each do |vm_name, vm_id|
          xml.SourcedItem {
            xml.Source("href" => "#{@api_url}/vAppTemplate/vm-#{vm_id}", "name" => vm_name)
            xml.InstantiationParams {
              xml.NetworkConnectionSection(
                "xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1",
                "type" => "application/vnd.vmware.vcloud.networkConnectionSection+xml",
                "href" => "#{@api_url}/vAppTemplate/vm-#{vm_id}/networkConnectionSection/") {
                  xml['ovf'].Info "Network config for sourced item"
                  xml.PrimaryNetworkConnectionIndex "0"
                  xml.NetworkConnection("network" => network_config[:name]) {
                    xml.NetworkConnectionIndex "0"
                    xml.IsConnected "true"
                    xml.IpAddressAllocationMode(network_config[:ip_allocation_mode] || "POOL")
                }
              }
            }
            xml.NetworkAssignment("containerNetwork" => network_config[:name], "innerNetwork" => network_config[:name])
          }
        end
        xml.AllEULAsAccepted "true"
      }
      end

      params = {
        "method" => :post,
        "command" => "/vdc/#{vdc}/action/composeVApp"
      }

      response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.composeVAppParams+xml")

      vapp_id = headers[:location].gsub(/.*\/vApp\/vapp\-/, "")

      task = response.css("VApp Task[operationName='vdcComposeVapp']").first
      task_id = task["href"].gsub(/.*\/task\//, "")

      { :vapp_id => vapp_id, :task_id => task_id }
    end
Compose a vapp using existing virtual machines

 Params:
 - vdc: the associated VDC
 - vapp_name: name of the target vapp
 - vapp_description: description of the target vapp
 - vm_list: hash with IDs of the VMs to be used in the composing process
 - network_config: hash of the network configuration for the vapp