diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index de5589fcaa..64c77bd0b0 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -129,6 +129,11 @@
{
"ImportPath": "google.golang.org/api/googleapi",
"Rev": "aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5"
+ },
+ {
+ "ImportPath": "github.com/vmware/govcloudair",
+ "Comment": "v0.0.1-1-g9672590",
+ "Rev": "9672590d5e5795b2d29fce97084fd5810665fc27"
}
]
}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/.gitignore b/Godeps/_workspace/src/github.com/vmware/govcloudair/.gitignore
new file mode 100644
index 0000000000..975162838b
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+.cover
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
\ No newline at end of file
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/.travis.yml b/Godeps/_workspace/src/github.com/vmware/govcloudair/.travis.yml
new file mode 100644
index 0000000000..ff7ba7a7c1
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+
+install:
+ - go get -t ./...
+ - go get code.google.com/p/go.tools/cmd/cover
+ - go get github.com/mattn/goveralls
+
+script:
+ - PATH="$HOME/gopath/bin:$PATH"
+ - script/coverage --coveralls
\ No newline at end of file
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/LICENSE b/Godeps/_workspace/src/github.com/vmware/govcloudair/LICENSE
new file mode 100644
index 0000000000..6a5b84c732
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/LICENSE
@@ -0,0 +1,569 @@
+govcloudair is distributed under the Apache License 2.0
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2014 Fabio Rapposelli
+
+ Licensed 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.
+
+
+testutil/http.go is distributed with a Mozilla Public License 2.0
+
+ Mozilla Public License, version 2.0
+
+ 1. Definitions
+
+ 1.1. "Contributor"
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+ 1.2. "Contributor Version"
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor's Contribution.
+
+ 1.3. "Contribution"
+
+ means Covered Software of a particular Contributor.
+
+ 1.4. "Covered Software"
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+ 1.5. "Incompatible With Secondary Licenses"
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the terms of
+ a Secondary License.
+
+ 1.6. "Executable Form"
+
+ means any form of the work other than Source Code Form.
+
+ 1.7. "Larger Work"
+
+ means a work that combines Covered Software with other material, in a
+ separate file or files, that is not Covered Software.
+
+ 1.8. "License"
+
+ means this document.
+
+ 1.9. "Licensable"
+
+ means having the right to grant, to the maximum extent possible, whether
+ at the time of the initial grant or subsequently, any and all of the
+ rights conveyed by this License.
+
+ 1.10. "Modifications"
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+ 1.11. "Patent Claims" of a Contributor
+
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the License,
+ by the making, using, selling, offering for sale, having made, import,
+ or transfer of either its Contributions or its Contributor Version.
+
+ 1.12. "Secondary License"
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+ 1.13. "Source Code Form"
+
+ means the form of the work preferred for making modifications.
+
+ 1.14. "You" (or "Your")
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, "control" means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+ 2. License Grants and Conditions
+
+ 2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+ 2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution
+ become effective for each Contribution on the date the Contributor first
+ distributes such Contribution.
+
+ 2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under
+ this License. No additional rights or licenses will be implied from the
+ distribution or licensing of Covered Software under this License.
+ Notwithstanding Section 2.1(b) above, no patent license is granted by a
+ Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+ This License does not grant any rights in the trademarks, service marks,
+ or logos of any Contributor (except as may be necessary to comply with
+ the notice requirements in Section 3.4).
+
+ 2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this
+ License (see Section 10.2) or under the terms of a Secondary License (if
+ permitted under the terms of Section 3.3).
+
+ 2.5. Representation
+
+ Each Contributor represents that the Contributor believes its
+ Contributions are its original creation(s) or it has sufficient rights to
+ grant the rights to its Contributions conveyed by this License.
+
+ 2.6. Fair Use
+
+ This License is not intended to limit any rights You have under
+ applicable copyright doctrines of fair use, fair dealing, or other
+ equivalents.
+
+ 2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+ 3. Responsibilities
+
+ 3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under
+ the terms of this License. You must inform recipients that the Source
+ Code Form of the Covered Software is governed by the terms of this
+ License, and how they can obtain a copy of this License. You may not
+ attempt to alter or restrict the recipients' rights in the Source Code
+ Form.
+
+ 3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter the
+ recipients' rights in the Source Code Form under this License.
+
+ 3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for
+ the Covered Software. If the Larger Work is a combination of Covered
+ Software with a work governed by one or more Secondary Licenses, and the
+ Covered Software is not Incompatible With Secondary Licenses, this
+ License permits You to additionally distribute such Covered Software
+ under the terms of such Secondary License(s), so that the recipient of
+ the Larger Work may, at their option, further distribute the Covered
+ Software under the terms of either this License or such Secondary
+ License(s).
+
+ 3.4. Notices
+
+ You may not remove or alter the substance of any license notices
+ (including copyright notices, patent notices, disclaimers of warranty, or
+ limitations of liability) contained within the Source Code Form of the
+ Covered Software, except that You may alter any license notices to the
+ extent required to remedy known factual inaccuracies.
+
+ 3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on
+ behalf of any Contributor. You must make it absolutely clear that any
+ such warranty, support, indemnity, or liability obligation is offered by
+ You alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+ 4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute,
+ judicial order, or regulation then You must: (a) comply with the terms of
+ this License to the maximum extent possible; and (b) describe the
+ limitations and the code they affect. Such description must be placed in a
+ text file included with all distributions of the Covered Software under
+ this License. Except to the extent prohibited by statute or regulation,
+ such description must be sufficiently detailed for a recipient of ordinary
+ skill to be able to understand it.
+
+ 5. Termination
+
+ 5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing
+ basis, if such Contributor fails to notify You of the non-compliance by
+ some reasonable means prior to 60 days after You have come back into
+ compliance. Moreover, Your grants from a particular Contributor are
+ reinstated on an ongoing basis if such Contributor notifies You of the
+ non-compliance by some reasonable means, this is the first time You have
+ received notice of non-compliance with this License from such
+ Contributor, and You become compliant prior to 30 days after Your receipt
+ of the notice.
+
+ 5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions,
+ counter-claims, and cross-claims) alleging that a Contributor Version
+ directly or indirectly infringes any patent, then the rights granted to
+ You by any and all Contributors for the Covered Software under Section
+ 2.1 of this License shall terminate.
+
+ 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+ 6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an "as is" basis,
+ without warranty of any kind, either expressed, implied, or statutory,
+ including, without limitation, warranties that the Covered Software is free
+ of defects, merchantable, fit for a particular purpose or non-infringing.
+ The entire risk as to the quality and performance of the Covered Software
+ is with You. Should any Covered Software prove defective in any respect,
+ You (not any Contributor) assume the cost of any necessary servicing,
+ repair, or correction. This disclaimer of warranty constitutes an essential
+ part of this License. No use of any Covered Software is authorized under
+ this License except under this disclaimer.
+
+ 7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from
+ such party's negligence to the extent applicable law prohibits such
+ limitation. Some jurisdictions do not allow the exclusion or limitation of
+ incidental or consequential damages, so this exclusion and limitation may
+ not apply to You.
+
+ 8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts
+ of a jurisdiction where the defendant maintains its principal place of
+ business and such litigation shall be governed by laws of that
+ jurisdiction, without reference to its conflict-of-law provisions. Nothing
+ in this Section shall prevent a party's ability to bring cross-claims or
+ counter-claims.
+
+ 9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. Any law or regulation which provides that
+ the language of a contract shall be construed against the drafter shall not
+ be used to construe this License against a Contributor.
+
+
+ 10. Versions of the License
+
+ 10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+ 10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version
+ of the License under which You originally received the Covered Software,
+ or under the terms of any subsequent version published by the license
+ steward.
+
+ 10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a
+ modified version of this License if you rename the license and remove
+ any references to the name of the license steward (except to note that
+ such modified license differs from this License).
+
+ 10.4. Distributing Source Code Form that is Incompatible With Secondary
+ Licenses If You choose to distribute Source Code Form that is
+ Incompatible With Secondary Licenses under the terms of this version of
+ the License, the notice described in Exhibit B of this License must be
+ attached.
+
+ Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+ If it is not possible or desirable to put the notice in a particular file,
+ then You may include the notice in a location (such as a LICENSE file in a
+ relevant directory) where a recipient would be likely to look for such a
+ notice.
+
+ You may add additional accurate notices of copyright ownership.
+
+ Exhibit B - "Incompatible With Secondary Licenses" Notice
+
+ This Source Code Form is "Incompatible
+ With Secondary Licenses", as defined by
+ the Mozilla Public License, v. 2.0.
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/Readme.md b/Godeps/_workspace/src/github.com/vmware/govcloudair/Readme.md
new file mode 100644
index 0000000000..64a51c7f4c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/Readme.md
@@ -0,0 +1,7 @@
+## govcloudair
+
+This package provides the `govcloudair` package which offers an interface to the vCloud Air 5.6 API.
+
+It serves as a foundation for a project currently in development, there are plans to make it a general purpose API in the future.
+
+The API is currently under heavy development, its coverage is extremely limited at the moment.
\ No newline at end of file
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/api.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/api.go
new file mode 100644
index 0000000000..3e778b219e
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/api.go
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+// Package govcloudair provides a simple binding for vCloud Air REST APIs.
+package govcloudair
+
+import (
+ "encoding/xml"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "os"
+ "time"
+
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+// Client provides a client to vCloud Air, values can be populated automatically using the Authenticate method.
+type Client struct {
+ VAToken string // vCloud Air authorization token
+ VAEndpoint url.URL // vCloud Air API endpoint
+ Region string // Region where the compute resource lives.
+ VCDToken string // Access Token (authorization header)
+ VCDAuthHeader string // Authorization header
+ VCDVDCHREF url.URL // HREF of the backend VDC you're using
+ Http http.Client // HttpClient is the client to use. Default will be used if not provided.
+}
+
+// VCHS API
+
+type services struct {
+ Service []struct {
+ Region string `xml:"region,attr"`
+ ServiceID string `xml:"serviceId,attr"`
+ ServiceType string `xml:"serviceType,attr"`
+ Type string `xml:"type,attr"`
+ HREF string `xml:"href,attr"`
+ } `xml:"Service"`
+}
+
+type session struct {
+ Link []*types.Link `xml:"Link"`
+}
+
+type computeResources struct {
+ VdcRef []struct {
+ Status string `xml:"status,attr"`
+ Name string `xml:"name,attr"`
+ Type string `xml:"type,attr"`
+ HREF string `xml:"href,attr"`
+ Link []*types.Link `xml:"Link"`
+ } `xml:"VdcRef"`
+}
+
+type vCloudSession struct {
+ VdcLink []struct {
+ AuthorizationToken string `xml:"authorizationToken,attr"`
+ AuthorizationHeader string `xml:"authorizationHeader,attr"`
+ Name string `xml:"name,attr"`
+ HREF string `xml:"href,attr"`
+ } `xml:"VdcLink"`
+}
+
+//
+
+func (c *Client) vaauthorize(user, pass string) (u url.URL, err error) {
+
+ if user == "" {
+ user = os.Getenv("VCLOUDAIR_USERNAME")
+ }
+
+ if pass == "" {
+ pass = os.Getenv("VCLOUDAIR_PASSWORD")
+ }
+
+ s := c.VAEndpoint
+ s.Path += "/vchs/sessions"
+
+ // No point in checking for errors here
+ req := c.NewRequest(map[string]string{}, "POST", s, nil)
+
+ // Set Basic Authentication Header
+ req.SetBasicAuth(user, pass)
+
+ // Add the Accept header for vCA
+ req.Header.Add("Accept", "application/xml;version=5.6")
+
+ resp, err := checkResp(c.Http.Do(req))
+ if err != nil {
+ return url.URL{}, err
+ }
+ defer resp.Body.Close()
+
+ // Store the authentication header
+ c.VAToken = resp.Header.Get("X-Vchs-Authorization")
+
+ session := new(session)
+
+ if err = decodeBody(resp, session); err != nil {
+ return url.URL{}, fmt.Errorf("error decoding session response: %s", err)
+ }
+
+ // Loop in the session struct to find right service and compute resource.
+ for _, s := range session.Link {
+ if s.Type == "application/xml;class=vnd.vmware.vchs.servicelist" && s.Rel == "down" {
+ u, err := url.ParseRequestURI(s.HREF)
+ return *u, err
+ }
+ }
+ return url.URL{}, fmt.Errorf("couldn't find a Service List in current session")
+}
+
+func (c *Client) vaacquireservice(s url.URL, cid string) (u url.URL, err error) {
+
+ if cid == "" {
+ cid = os.Getenv("VCLOUDAIR_COMPUTEID")
+ }
+
+ req := c.NewRequest(map[string]string{}, "GET", s, nil)
+
+ // Add the Accept header for vCA
+ req.Header.Add("Accept", "application/xml;version=5.6")
+
+ // Set Authorization Header for vCA
+ req.Header.Add("x-vchs-authorization", c.VAToken)
+
+ resp, err := checkResp(c.Http.Do(req))
+ if err != nil {
+ return url.URL{}, fmt.Errorf("error processing compute action: %s", err)
+ }
+
+ services := new(services)
+
+ if err = decodeBody(resp, services); err != nil {
+ return url.URL{}, fmt.Errorf("error decoding services response: %s", err)
+ }
+
+ // Loop in the Services struct to find right service and compute resource.
+ for _, s := range services.Service {
+ if s.ServiceID == cid {
+ c.Region = s.Region
+ u, err := url.ParseRequestURI(s.HREF)
+ return *u, err
+ }
+ }
+ return url.URL{}, fmt.Errorf("couldn't find a Compute Resource in current service list")
+}
+
+func (c *Client) vaacquirecompute(s url.URL, vid string) (u url.URL, err error) {
+
+ if vid == "" {
+ vid = os.Getenv("VCLOUDAIR_VDCID")
+ }
+
+ req := c.NewRequest(map[string]string{}, "GET", s, nil)
+
+ // Add the Accept header for vCA
+ req.Header.Add("Accept", "application/xml;version=5.6")
+
+ // Set Authorization Header
+ req.Header.Add("x-vchs-authorization", c.VAToken)
+
+ // TODO: wrap into checkresp to parse error
+ resp, err := checkResp(c.Http.Do(req))
+ if err != nil {
+ return url.URL{}, fmt.Errorf("error processing compute action: %s", err)
+ }
+
+ computeresources := new(computeResources)
+
+ if err = decodeBody(resp, computeresources); err != nil {
+ return url.URL{}, fmt.Errorf("error decoding computeresources response: %s", err)
+ }
+
+ // Iterate through the ComputeResources struct searching for the right
+ // backend server
+ for _, s := range computeresources.VdcRef {
+ if s.Name == vid {
+ for _, t := range s.Link {
+ if t.Name == vid {
+ u, err := url.ParseRequestURI(t.HREF)
+ return *u, err
+ }
+ }
+ }
+ }
+ return url.URL{}, fmt.Errorf("couldn't find a VDC Resource in current Compute list")
+}
+
+func (c *Client) vagetbackendauth(s url.URL, cid string) error {
+
+ if cid == "" {
+ cid = os.Getenv("VCLOUDAIR_COMPUTEID")
+ }
+
+ req := c.NewRequest(map[string]string{}, "POST", s, nil)
+
+ // Add the Accept header for vCA
+ req.Header.Add("Accept", "application/xml;version=5.6")
+
+ // Set Authorization Header
+ req.Header.Add("x-vchs-authorization", c.VAToken)
+
+ // TODO: wrap into checkresp to parse error
+ resp, err := checkResp(c.Http.Do(req))
+ if err != nil {
+ return fmt.Errorf("error processing backend url action: %s", err)
+ }
+ defer resp.Body.Close()
+
+ vcloudsession := new(vCloudSession)
+
+ if err = decodeBody(resp, vcloudsession); err != nil {
+ return fmt.Errorf("error decoding vcloudsession response: %s", err)
+ }
+
+ // Get the backend session information
+ for _, s := range vcloudsession.VdcLink {
+ if s.Name == cid {
+ // Fetch the authorization token
+ c.VCDToken = s.AuthorizationToken
+
+ // Fetch the authorization header
+ c.VCDAuthHeader = s.AuthorizationHeader
+
+ u, err := url.ParseRequestURI(s.HREF)
+ if err != nil {
+ return fmt.Errorf("error decoding href: %s", err)
+ }
+ c.VCDVDCHREF = *u
+ return nil
+ }
+ }
+ return fmt.Errorf("error finding the right backend resource")
+}
+
+// NewClient returns a new empty client to authenticate against the vCloud Air
+// service, the vCloud Air endpoint can be overridden by setting the
+// VCLOUDAIR_ENDPOINT environment variable.
+func NewClient() (*Client, error) {
+
+ var u *url.URL
+ var err error
+
+ if os.Getenv("VCLOUDAIR_ENDPOINT") != "" {
+ u, err = url.ParseRequestURI(os.Getenv("VCLOUDAIR_ENDPOINT"))
+ if err != nil {
+ return &Client{}, fmt.Errorf("cannot parse endpoint coming from VCLOUDAIR_ENDPOINT")
+ }
+ } else {
+ // Implicitly trust this URL parse.
+ u, _ = url.ParseRequestURI("https://vchs.vmware.com/api")
+ }
+
+ Client := Client{
+ VAEndpoint: *u,
+ // Patching things up as we're hitting several TLS timeouts.
+ Http: http.Client{Transport: &http.Transport{TLSHandshakeTimeout: 120 * time.Second}},
+ }
+ return &Client, nil
+}
+
+// Authenticate is an helper function that performs a complete login in vCloud
+// Air and in the backend vCloud Director instance.
+func (c *Client) Authenticate(username, password, computeid, vdcid string) (Vdc, error) {
+ // Authorize
+ vaservicehref, err := c.vaauthorize(username, password)
+ if err != nil {
+ return Vdc{}, fmt.Errorf("error Authorizing: %s", err)
+ }
+
+ // Get Service
+ vacomputehref, err := c.vaacquireservice(vaservicehref, computeid)
+ if err != nil {
+ return Vdc{}, fmt.Errorf("error Acquiring Service: %s", err)
+ }
+
+ // Get Compute
+ vavdchref, err := c.vaacquirecompute(vacomputehref, vdcid)
+ if err != nil {
+ return Vdc{}, fmt.Errorf("error Acquiring Compute: %s", err)
+ }
+
+ // Get Backend Authorization
+ if err = c.vagetbackendauth(vavdchref, computeid); err != nil {
+ return Vdc{}, fmt.Errorf("error Acquiring Backend Authorization: %s", err)
+ }
+
+ v, err := c.retrieveVDC()
+ if err != nil {
+ return Vdc{}, fmt.Errorf("error Acquiring VDC: %s", err)
+ }
+
+ return v, nil
+
+}
+
+// NewRequest creates a new HTTP request and applies necessary auth headers if
+// set.
+func (c *Client) NewRequest(params map[string]string, method string, u url.URL, body io.Reader) *http.Request {
+
+ p := url.Values{}
+
+ // Build up our request parameters
+ for k, v := range params {
+ p.Add(k, v)
+ }
+
+ // Add the params to our URL
+ u.RawQuery = p.Encode()
+
+ // Build the request, no point in checking for errors here as we're just
+ // passing a string version of an url.URL struct and http.NewRequest returns
+ // error only if can't process an url.ParseRequestURI().
+ req, _ := http.NewRequest(method, u.String(), body)
+
+ if c.VCDAuthHeader != "" && c.VCDToken != "" {
+ // Add the authorization header
+ req.Header.Add(c.VCDAuthHeader, c.VCDToken)
+ // Add the Accept header for VCD
+ req.Header.Add("Accept", "application/*+xml;version=5.6")
+ }
+
+ return req
+
+}
+
+// Disconnect performs a disconnection from the vCloud Air API endpoint.
+func (c *Client) Disconnect() error {
+ if c.VCDToken == "" && c.VCDAuthHeader == "" && c.VAToken == "" {
+ return fmt.Errorf("cannot disconnect, client is not authenticated")
+ }
+
+ s := c.VAEndpoint
+ s.Path += "/vchs/session"
+
+ req := c.NewRequest(map[string]string{}, "DELETE", s, nil)
+
+ // Add the Accept header for vCA
+ req.Header.Add("Accept", "application/xml;version=5.6")
+
+ // Set Authorization Header
+ req.Header.Add("x-vchs-authorization", c.VAToken)
+
+ if _, err := checkResp(c.Http.Do(req)); err != nil {
+ return fmt.Errorf("error processing session delete for vchs: %s", err)
+ }
+
+ return nil
+}
+
+// parseErr takes an error XML resp and returns a single string for use in error messages.
+func parseErr(resp *http.Response) error {
+
+ errBody := new(types.Error)
+
+ // if there was an error decoding the body, just return that
+ if err := decodeBody(resp, errBody); err != nil {
+ return fmt.Errorf("error parsing error body for non-200 request: %s", err)
+ }
+
+ return fmt.Errorf("API Error: %d: %s", errBody.MajorErrorCode, errBody.Message)
+}
+
+// decodeBody is used to XML decode a response body
+func decodeBody(resp *http.Response, out interface{}) error {
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return err
+ }
+
+ // Unmarshal the XML.
+ if err = xml.Unmarshal(body, &out); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// checkResp wraps http.Client.Do() and verifies the request, if status code
+// is 2XX it passes back the response, if it's a known invalid status code it
+// parses the resultant XML error and returns a descriptive error, if the
+// status code is not handled it returns a generic error with the status code.
+func checkResp(resp *http.Response, err error) (*http.Response, error) {
+ if err != nil {
+ return resp, err
+ }
+
+ switch i := resp.StatusCode; {
+ // Valid request, return the response.
+ case i == 200 || i == 201 || i == 202 || i == 204:
+ return resp, nil
+ // Invalid request, parse the XML error returned and return it.
+ case i == 400 || i == 401 || i == 403 || i == 404 || i == 405 || i == 406 || i == 409 || i == 415 || i == 500 || i == 503 || i == 504:
+ return nil, parseErr(resp)
+ // Unhandled response.
+ default:
+ return nil, fmt.Errorf("unhandled API response, please report this issue, status code: %s", resp.Status)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/api_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/api_test.go
new file mode 100644
index 0000000000..e033a09868
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/api_test.go
@@ -0,0 +1,749 @@
+/*
+ * @Author: frapposelli
+ * @Project: govcloudair
+ * @Filename: api_test.go
+ * @Last Modified by: frapposelli
+ */
+
+package govcloudair
+
+import (
+ "net/url"
+ "os"
+ "testing"
+
+ "github.com/vmware/govcloudair/testutil"
+ . "gopkg.in/check.v1"
+)
+
+var au, _ = url.ParseRequestURI("http://localhost:4444/api")
+var aus, _ = url.ParseRequestURI("http://localhost:4444/api/vchs/services")
+var auc, _ = url.ParseRequestURI("http://localhost:4444/api/vchs/compute/00000000-0000-0000-0000-000000000000")
+var aucs, _ = url.ParseRequestURI("http://localhost:4444/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession")
+
+func Test(t *testing.T) { TestingT(t) }
+
+type S struct {
+ client *Client
+ vdc Vdc
+ vapp *VApp
+}
+
+var _ = Suite(&S{})
+
+var testServer = testutil.NewHTTPServer()
+
+var authheader = map[string]string{"x-vchs-authorization": "012345678901234567890123456789"}
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ var err error
+
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+
+ s.client, err = NewClient()
+ if err != nil {
+ panic(err)
+ }
+
+ testServer.ResponseMap(5, testutil.ResponseMap{
+ "/api/vchs/sessions": testutil.Response{201, authheader, vaauthorization},
+ "/api/vchs/services": testutil.Response{200, nil, vaservices},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vacompute},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession": testutil.Response{201, nil, vabackend},
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ })
+
+ s.vdc, err = s.client.Authenticate("username", "password", "CI123456-789", "VDC12345-6789")
+ s.vapp = NewVApp(s.client)
+ _ = testServer.WaitRequests(5)
+ testServer.Flush()
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func TestClient_vaauthorize(t *testing.T) {
+ testServer.Start()
+ var err error
+
+ // Set up a working client
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ // Set up a correct conversation
+ testServer.Response(201, authheader, vaauthorization)
+ _, err = client.vaauthorize("username", "password")
+ _ = testServer.WaitRequest()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ // Test if token is correctly set on client.
+ if client.VAToken != "012345678901234567890123456789" {
+ t.Fatalf("VAtoken not set on client: %s", client.VAToken)
+ }
+
+ // Test client errors
+
+ // Test a correct response with a wrong status code
+ testServer.Response(404, authheader, notfoundErr)
+ _, err = client.vaauthorize("username", "password")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+ // Test an API error
+ testServer.Response(500, authheader, vcdError)
+ _, err = client.vaauthorize("username", "password")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+ // Test an API response that doesn't contain the param we're looking for.
+ testServer.Response(200, authheader, vaauthorizationErr)
+ _, err = client.vaauthorize("username", "password")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+ // Test an un-parsable response.
+ testServer.Response(200, authheader, notfoundErr)
+ _, err = client.vaauthorize("username", "password")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+}
+
+func TestClient_vaacquireservice(t *testing.T) {
+ testServer.Start()
+ var err error
+
+ // Set up a working client
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+ client.VAToken = "012345678901234567890123456789"
+
+ // Test a correct conversation
+ testServer.Response(200, nil, vaservices)
+ vacomputehref, err := client.vaacquireservice(*aus, "CI123456-789")
+ _ = testServer.WaitRequest()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if vacomputehref.String() != "http://localhost:4444/api/vchs/compute/00000000-0000-0000-0000-000000000000" {
+ t.Fatalf("VAComputeHREF not set on client: %s", vacomputehref)
+ }
+
+ if client.Region != "US - Anywhere" {
+ t.Fatalf("Region not set on client: %s", client.Region)
+ }
+
+ // Test client errors
+
+ // Test a 404
+ testServer.Response(404, nil, notfoundErr)
+ _, err = client.vaacquireservice(*aus, "CI123456-789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+ // Test an API error
+ testServer.Response(500, nil, vcdError)
+ _, err = client.vaacquireservice(*aus, "CI123456-789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+ // Test an unknown Compute ID
+ testServer.Response(200, nil, vaservices)
+ _, err = client.vaacquireservice(*aus, "NOTVALID-789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+ // Test an un-parsable response
+ testServer.Response(200, nil, notfoundErr)
+ _, err = client.vaacquireservice(*aus, "CI123456-789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+}
+
+func TestClient_vaacquirecompute(t *testing.T) {
+ testServer.Start()
+ var err error
+
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+ client.VAToken = "012345678901234567890123456789"
+ client.Region = "US - Anywhere"
+
+ testServer.Response(200, nil, vacompute)
+ vavdchref, err := client.vaacquirecompute(*auc, "VDC12345-6789")
+ _ = testServer.WaitRequest()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if vavdchref.String() != "http://localhost:4444/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession" {
+ t.Fatalf("VAVDCHREF not set on client: %s", vavdchref)
+ }
+
+ // Test client errors
+
+ // Test a 404
+ testServer.Response(404, nil, notfoundErr)
+ _, err = client.vaacquirecompute(*auc, "VDC12345-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+ // Test an API error
+ testServer.Response(500, nil, vcdError)
+ _, err = client.vaacquirecompute(*auc, "VDC12345-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+ // Test an unknown VDC ID
+ testServer.Response(200, nil, vacompute)
+ _, err = client.vaacquirecompute(*auc, "INVALID-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+ // Test an un-parsable response
+ testServer.Response(200, nil, notfoundErr)
+ _, err = client.vaacquirecompute(*auc, "VDC12345-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+}
+
+func TestClient_vagetbackendauth(t *testing.T) {
+ testServer.Start()
+ var err error
+
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+ client.VAToken = "012345678901234567890123456789"
+ client.Region = "US - Anywhere"
+
+ testServer.Response(201, nil, vabackend)
+ err = client.vagetbackendauth(*aucs, "CI123456-789")
+ _ = testServer.WaitRequest()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if client.VCDToken != "01234567890123456789012345678901" {
+ t.Fatalf("VCDToken not set on client: %s", client.VCDToken)
+ }
+ if client.VCDAuthHeader != "x-vcloud-authorization" {
+ t.Fatalf("VCDAuthHeader not set on client: %s", client.VCDAuthHeader)
+ }
+ if client.VCDVDCHREF.String() != "http://localhost:4444/api/vdc/00000000-0000-0000-0000-000000000000" {
+ t.Fatalf("VDC not set on client: %s", client.VCDVDCHREF)
+ }
+
+ // Test client errors
+
+ // Test a 404
+ testServer.Response(404, nil, notfoundErr)
+ err = client.vagetbackendauth(*aucs, "VDC12345-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+ // Test an API error
+ testServer.Response(500, nil, vcdError)
+ err = client.vagetbackendauth(*aucs, "VDC12345-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+ // Test an unknown backend VDC IC
+ testServer.Response(201, nil, vabackend)
+ err = client.vagetbackendauth(*aucs, "INVALID-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+ // Test an un-parsable response
+ testServer.Response(201, nil, notfoundErr)
+ err = client.vagetbackendauth(*aucs, "VDC12345-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+ // Test a botched backend VDC IC
+ testServer.Response(201, nil, vabackendErr)
+ err = client.vagetbackendauth(*aucs, "VDC12345-6789")
+ _ = testServer.WaitRequest()
+ if err == nil {
+ t.Fatalf("Request error not caught: %v", err)
+ }
+
+}
+
+// Env variable tests
+
+func TestClient_vaauthorize_env(t *testing.T) {
+
+ os.Setenv("VCLOUDAIR_USERNAME", "username")
+ os.Setenv("VCLOUDAIR_PASSWORD", "password")
+
+ testServer.Start()
+ var err error
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ testServer.Response(201, authheader, vaauthorization)
+ _, err = client.vaauthorize("", "")
+ _ = testServer.WaitRequest()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if client.VAToken != "012345678901234567890123456789" {
+ t.Fatalf("VAtoken not set on client: %s", client.VAToken)
+ }
+
+}
+
+func TestClient_vaacquireservice_env(t *testing.T) {
+
+ os.Setenv("VCLOUDAIR_COMPUTEID", "CI123456-789")
+
+ testServer.Start()
+ var err error
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+ client.VAToken = "012345678901234567890123456789"
+
+ testServer.Response(200, nil, vaservices)
+ vacomputehref, err := client.vaacquireservice(*aus, "")
+ _ = testServer.WaitRequest()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if vacomputehref.String() != "http://localhost:4444/api/vchs/compute/00000000-0000-0000-0000-000000000000" {
+ t.Fatalf("VAComputeHREF not set on client: %s", vacomputehref)
+ }
+
+ if client.Region != "US - Anywhere" {
+ t.Fatalf("Region not set on client: %s", client.Region)
+ }
+
+}
+
+func TestClient_vaacquirecompute_env(t *testing.T) {
+
+ os.Setenv("VCLOUDAIR_VDCID", "VDC12345-6789")
+
+ testServer.Start()
+ var err error
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+ client.VAToken = "012345678901234567890123456789"
+ client.Region = "US - Anywhere"
+
+ testServer.Response(200, nil, vacompute)
+ vavdchref, err := client.vaacquirecompute(*auc, "")
+ _ = testServer.WaitRequest()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if vavdchref.String() != "http://localhost:4444/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession" {
+ t.Fatalf("VAVDCHREF not set on client: %s", vavdchref)
+ }
+
+}
+
+func TestClient_vagetbackendauth_env(t *testing.T) {
+
+ os.Setenv("VCLOUDAIR_VDCID", "VDC12345-6789")
+
+ testServer.Start()
+ var err error
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+ client.VAToken = "012345678901234567890123456789"
+ client.Region = "US - Anywhere"
+
+ testServer.Response(201, nil, vabackend)
+ err = client.vagetbackendauth(*aucs, "")
+ _ = testServer.WaitRequest()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if client.VCDToken != "01234567890123456789012345678901" {
+ t.Fatalf("VCDToken not set on client: %s", client.VCDToken)
+ }
+ if client.VCDAuthHeader != "x-vcloud-authorization" {
+ t.Fatalf("VCDAuthHeader not set on client: %s", client.VCDAuthHeader)
+ }
+ if client.VCDVDCHREF.String() != "http://localhost:4444/api/vdc/00000000-0000-0000-0000-000000000000" {
+ t.Fatalf("VDC not set on client: %s", client.VCDVDCHREF)
+ }
+
+}
+
+func TestClient_NewClient(t *testing.T) {
+
+ var err error
+ os.Setenv("VCLOUDAIR_ENDPOINT", "")
+ if _, err = NewClient(); err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ os.Setenv("VCLOUDAIR_ENDPOINT", "💩")
+ if _, err = NewClient(); err == nil {
+ t.Fatalf("err: %v", err)
+ }
+
+}
+
+func TestClient_Disconnect(t *testing.T) {
+
+ testServer.Start()
+ var err error
+
+ // Test an authenticated client
+ c := makeClient(t)
+ testServer.Response(201, nil, "")
+ err = c.Disconnect()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ // Test an empty client
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+ err = client.Disconnect()
+ if err == nil {
+ t.Fatalf("err: %v", err)
+ }
+
+}
+
+func TestClient_Authenticate(t *testing.T) {
+
+ testServer.Start()
+ var err error
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ // Botched auth
+ testServer.ResponseMap(5, testutil.ResponseMap{
+ "/api/vchs/sessions": testutil.Response{401, nil, vcdError},
+ "/api/vchs/services": testutil.Response{200, nil, vaservices},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vacompute},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession": testutil.Response{201, nil, vabackend},
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ })
+
+ _, err = client.Authenticate("username", "password", "CI123456-789", "VDC12345-6789")
+ _ = testServer.WaitRequests(1)
+ testServer.Flush()
+ if err == nil {
+ t.Fatalf("Uncatched error: %v", err)
+ }
+
+ // Botched services
+ testServer.ResponseMap(5, testutil.ResponseMap{
+ "/api/vchs/sessions": testutil.Response{201, authheader, vaauthorization},
+ "/api/vchs/services": testutil.Response{500, nil, vcdError},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vacompute},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession": testutil.Response{201, nil, vabackend},
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ })
+
+ _, err = client.Authenticate("username", "password", "CI123456-789", "VDC12345-6789")
+ _ = testServer.WaitRequests(2)
+ testServer.Flush()
+ if err == nil {
+ t.Fatalf("Uncatched error: %v", err)
+ }
+
+ // Botched compute
+ testServer.ResponseMap(5, testutil.ResponseMap{
+ "/api/vchs/sessions": testutil.Response{201, authheader, vaauthorization},
+ "/api/vchs/services": testutil.Response{200, nil, vaservices},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000": testutil.Response{500, nil, vcdError},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession": testutil.Response{201, nil, vabackend},
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ })
+
+ _, err = client.Authenticate("username", "password", "CI123456-789", "VDC12345-6789")
+ _ = testServer.WaitRequests(3)
+ testServer.Flush()
+ if err == nil {
+ t.Fatalf("Uncatched error: %v", err)
+ }
+
+ // Botched backend
+ testServer.ResponseMap(5, testutil.ResponseMap{
+ "/api/vchs/sessions": testutil.Response{201, authheader, vaauthorization},
+ "/api/vchs/services": testutil.Response{200, nil, vaservices},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vacompute},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession": testutil.Response{500, nil, vcdError},
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ })
+
+ _, err = client.Authenticate("username", "password", "CI123456-789", "VDC12345-6789")
+ _ = testServer.WaitRequests(4)
+ testServer.Flush()
+ if err == nil {
+ t.Fatalf("Uncatched error: %v", err)
+ }
+
+ // Botched vdc
+ testServer.ResponseMap(5, testutil.ResponseMap{
+ "/api/vchs/sessions": testutil.Response{201, authheader, vaauthorization},
+ "/api/vchs/services": testutil.Response{200, nil, vaservices},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vacompute},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession": testutil.Response{201, nil, vabackend},
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{500, nil, vcdError},
+ })
+
+ _, err = client.Authenticate("username", "password", "CI123456-789", "VDC12345-6789")
+ _ = testServer.WaitRequests(5)
+ testServer.Flush()
+ if err == nil {
+ t.Fatalf("Uncatched error: %v", err)
+ }
+
+}
+
+func makeClient(t *testing.T) Client {
+
+ testServer.Start()
+ var err error
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ testServer.ResponseMap(5, testutil.ResponseMap{
+ "/api/vchs/sessions": testutil.Response{201, authheader, vaauthorization},
+ "/api/vchs/services": testutil.Response{200, nil, vaservices},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vacompute},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession": testutil.Response{201, nil, vabackend},
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ })
+
+ _, err = client.Authenticate("username", "password", "CI123456-789", "VDC12345-6789")
+
+ _ = testServer.WaitRequests(5)
+ testServer.Flush()
+
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if client.VAToken != "012345678901234567890123456789" {
+ t.Fatalf("VAtoken not set on client: %s", client.VAToken)
+ }
+
+ if client.Region != "US - Anywhere" {
+ t.Fatalf("Region not set on client: %s", client.Region)
+ }
+
+ if client.VCDToken != "01234567890123456789012345678901" {
+ t.Fatalf("VCDToken not set on client: %s", client.VCDToken)
+ }
+ if client.VCDAuthHeader != "x-vcloud-authorization" {
+ t.Fatalf("VCDAuthHeader not set on client: %s", client.VCDAuthHeader)
+ }
+ if client.VCDVDCHREF.String() != "http://localhost:4444/api/vdc/00000000-0000-0000-0000-000000000000" {
+ t.Fatalf("VDC not set on client: %s", client.VCDVDCHREF)
+ }
+
+ return *client
+}
+
+func TestClient_parseErr(t *testing.T) {
+ testServer.Start()
+ var err error
+ os.Setenv("VCLOUDAIR_ENDPOINT", "http://localhost:4444/api")
+ client, err := NewClient()
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ // I'M A TEAPOT!
+ testServer.ResponseMap(5, testutil.ResponseMap{
+ "/api/vchs/sessions": testutil.Response{201, authheader, vaauthorization},
+ "/api/vchs/services": testutil.Response{200, nil, vaservices},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vacompute},
+ "/api/vchs/compute/00000000-0000-0000-0000-000000000000/vdc/00000000-0000-0000-0000-000000000000/vcloudsession": testutil.Response{418, nil, notfoundErr},
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ })
+
+ _, err = client.Authenticate("username", "password", "CI123456-789", "VDC12345-6789")
+
+ _ = testServer.WaitRequests(4)
+ testServer.Flush()
+
+ if err == nil {
+ t.Fatalf("Uncatched error: %v", err)
+ }
+
+}
+
+func TestClient_NewRequest(t *testing.T) {
+ c := makeClient(t)
+
+ params := map[string]string{
+ "foo": "bar",
+ "baz": "bar",
+ }
+
+ uri, _ := url.ParseRequestURI("http://localhost:4444/api/bar")
+
+ req := c.NewRequest(params, "POST", *uri, nil)
+
+ encoded := req.URL.Query()
+ if encoded.Get("foo") != "bar" {
+ t.Fatalf("bad: %v", encoded)
+ }
+
+ if encoded.Get("baz") != "bar" {
+ t.Fatalf("bad: %v", encoded)
+ }
+
+ if req.URL.String() != "http://localhost:4444/api/bar?baz=bar&foo=bar" {
+ t.Fatalf("bad base url: %v", req.URL.String())
+ }
+
+ if req.Header.Get("x-vcloud-authorization") != "01234567890123456789012345678901" {
+ t.Fatalf("bad auth header: %v", req.Header)
+ }
+
+ if req.Method != "POST" {
+ t.Fatalf("bad method: %v", req.Method)
+ }
+
+}
+
+// status: 404
+var notfoundErr = `
+
+
404 Not Found
+
+ 404 Not Found
+
nginx/1.4.6 (Ubuntu)
+
+
+ `
+
+// status: 201
+var vaauthorization = `
+
+
+
+
+
+ `
+var vaauthorizationErr = `
+
+
+
+
+ `
+
+// status: 200
+var vaservices = `
+
+
+
+
+ `
+
+// status: 200
+var vacompute = `
+
+
+
+
+
+
+
+ `
+
+// status: 201
+var vabackend = `
+
+
+
+
+
+ `
+
+// status: 201
+var vabackendErr = `
+
+
+
+
+
+ `
+
+var vcdError = `
+
+ `
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/catalog.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/catalog.go
new file mode 100644
index 0000000000..1f2926551a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/catalog.go
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "fmt"
+ "net/url"
+
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type Catalog struct {
+ Catalog *types.Catalog
+ c *Client
+}
+
+func NewCatalog(c *Client) *Catalog {
+ return &Catalog{
+ Catalog: new(types.Catalog),
+ c: c,
+ }
+}
+
+func (c *Catalog) FindCatalogItem(catalogitem string) (CatalogItem, error) {
+
+ for _, cis := range c.Catalog.CatalogItems {
+ for _, ci := range cis.CatalogItem {
+ if ci.Name == catalogitem && ci.Type == "application/vnd.vmware.vcloud.catalogItem+xml" {
+ u, err := url.ParseRequestURI(ci.HREF)
+
+ if err != nil {
+ return CatalogItem{}, fmt.Errorf("error decoding catalog response: %s", err)
+ }
+
+ req := c.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(c.c.Http.Do(req))
+ if err != nil {
+ return CatalogItem{}, fmt.Errorf("error retreiving catalog: %s", err)
+ }
+
+ cat := NewCatalogItem(c.c)
+
+ if err = decodeBody(resp, cat.CatalogItem); err != nil {
+ return CatalogItem{}, fmt.Errorf("error decoding catalog response: %s", err)
+ }
+
+ // The request was successful
+ return *cat, nil
+ }
+ }
+ }
+
+ return CatalogItem{}, fmt.Errorf("can't find catalog item: %s", catalogitem)
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/catalog_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/catalog_test.go
new file mode 100644
index 0000000000..8c8cd74ce2
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/catalog_test.go
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) Test_FindCatalogItem(c *C) {
+
+ // Get the Org populated
+ testServer.Response(200, nil, orgExample)
+ org, err := s.vdc.GetVDCOrg()
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+ c.Assert(err, IsNil)
+
+ // Populate Catalog
+ testServer.Response(200, nil, catalogExample)
+ cat, err := org.FindCatalog("Public Catalog")
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+
+ // Find Catalog Item
+ testServer.Response(200, nil, catalogitemExample)
+ catitem, err := cat.FindCatalogItem("CentOS64-32bit")
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+
+ c.Assert(err, IsNil)
+ c.Assert(catitem.CatalogItem.HREF, Equals, "http://localhost:4444/api/catalogItem/1176e485-8858-4e15-94e5-ae4face605ae")
+ c.Assert(catitem.CatalogItem.Description, Equals, "id: cts-6.4-32bit")
+
+ // Test non-existant catalog item
+ catitem, err = cat.FindCatalogItem("INVALID")
+ c.Assert(err, NotNil)
+
+}
+
+var catalogExample = `
+
+
+
+ vCHS service catalog
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 2013-10-15T01:14:22.370Z
+ 60
+
+`
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/catalogitem.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/catalogitem.go
new file mode 100644
index 0000000000..4261ef96d8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/catalogitem.go
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "fmt"
+ "net/url"
+
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type CatalogItem struct {
+ CatalogItem *types.CatalogItem
+ c *Client
+}
+
+func NewCatalogItem(c *Client) *CatalogItem {
+ return &CatalogItem{
+ CatalogItem: new(types.CatalogItem),
+ c: c,
+ }
+}
+
+func (ci *CatalogItem) GetVAppTemplate() (VAppTemplate, error) {
+ url, err := url.ParseRequestURI(ci.CatalogItem.Entity.HREF)
+
+ if err != nil {
+ return VAppTemplate{}, fmt.Errorf("error decoding catalogitem response: %s", err)
+ }
+
+ req := ci.c.NewRequest(map[string]string{}, "GET", *url, nil)
+
+ resp, err := checkResp(ci.c.Http.Do(req))
+ if err != nil {
+ return VAppTemplate{}, fmt.Errorf("error retreiving vapptemplate: %s", err)
+ }
+
+ cat := NewVAppTemplate(ci.c)
+
+ if err = decodeBody(resp, cat.VAppTemplate); err != nil {
+ return VAppTemplate{}, fmt.Errorf("error decoding vapptemplate response: %s", err)
+ }
+
+ // The request was successful
+ return *cat, nil
+
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/catalogitem_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/catalogitem_test.go
new file mode 100644
index 0000000000..4b526c9213
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/catalogitem_test.go
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) Test_GetVAppTemplate(c *C) {
+
+ // Get the Org populated
+ testServer.Response(200, nil, orgExample)
+ org, err := s.vdc.GetVDCOrg()
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+ c.Assert(err, IsNil)
+
+ // Populate Catalog
+ testServer.Response(200, nil, catalogExample)
+ cat, err := org.FindCatalog("Public Catalog")
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+
+ // Populate Catalog Item
+ testServer.Response(200, nil, catalogitemExample)
+ catitem, err := cat.FindCatalogItem("CentOS64-32bit")
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+
+ // Get VAppTemplate
+ testServer.Response(200, nil, vapptemplateExample)
+ vapptemplate, err := catitem.GetVAppTemplate()
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+
+ c.Assert(err, IsNil)
+ c.Assert(vapptemplate.VAppTemplate.HREF, Equals, "http://localhost:4444/api/vAppTemplate/vappTemplate-40cb9721-5f1a-44f9-b5c3-98c5f518c4f5")
+ c.Assert(vapptemplate.VAppTemplate.Name, Equals, "CentOS64-32bit")
+ c.Assert(vapptemplate.VAppTemplate.Description, Equals, "id: cts-6.4-32bit")
+
+}
+
+var catalogitemExample = `
+
+
+
+
+ id: cts-6.4-32bit
+
+ 2014-06-04T21:06:43.750Z
+ 4
+
+`
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/edgegateway.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/edgegateway.go
new file mode 100644
index 0000000000..7de0bfb15d
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/edgegateway.go
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "bytes"
+ "encoding/xml"
+ "fmt"
+ "net/url"
+ "os"
+
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type EdgeGateway struct {
+ EdgeGateway *types.EdgeGateway
+ c *Client
+}
+
+func NewEdgeGateway(c *Client) *EdgeGateway {
+ return &EdgeGateway{
+ EdgeGateway: new(types.EdgeGateway),
+ c: c,
+ }
+}
+
+func (e *EdgeGateway) Refresh() error {
+
+ if e.EdgeGateway == nil {
+ return fmt.Errorf("cannot refresh, Object is empty")
+ }
+
+ u, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
+
+ req := e.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(e.c.Http.Do(req))
+ if err != nil {
+ return fmt.Errorf("error retreiving Edge Gateway: %s", err)
+ }
+
+ // Empty struct before a new unmarshal, otherwise we end up with duplicate
+ // elements in slices.
+ e.EdgeGateway = &types.EdgeGateway{}
+
+ if err = decodeBody(resp, e.EdgeGateway); err != nil {
+ return fmt.Errorf("error decoding Edge Gateway response: %s", err)
+ }
+
+ // The request was successful
+ return nil
+}
+
+func (e *EdgeGateway) Remove1to1Mapping(internal, external string) (Task, error) {
+
+ // Refresh EdgeGateway rules
+ err := e.Refresh()
+ if err != nil {
+ fmt.Printf("error: %v\n", err)
+ }
+
+ var uplinkif string
+ for _, gifs := range e.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface {
+ if gifs.InterfaceType == "uplink" {
+ uplinkif = gifs.Network.HREF
+ }
+ }
+
+ newedgeconfig := e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration
+
+ // Take care of the NAT service
+ newnatservice := &types.NatService{}
+
+ // Copy over the NAT configuration
+ newnatservice.IsEnabled = newedgeconfig.NatService.IsEnabled
+ newnatservice.NatType = newedgeconfig.NatService.NatType
+ newnatservice.Policy = newedgeconfig.NatService.Policy
+ newnatservice.ExternalIP = newedgeconfig.NatService.ExternalIP
+
+ for k, v := range newedgeconfig.NatService.NatRule {
+
+ // Kludgy IF to avoid deleting DNAT rules not created by us.
+ // If matches, let's skip it and continue the loop
+ if v.RuleType == "DNAT" &&
+ v.GatewayNatRule.OriginalIP == external &&
+ v.GatewayNatRule.TranslatedIP == internal &&
+ v.GatewayNatRule.OriginalPort == "any" &&
+ v.GatewayNatRule.TranslatedPort == "any" &&
+ v.GatewayNatRule.Protocol == "any" &&
+ v.GatewayNatRule.Interface.HREF == uplinkif {
+ continue
+ }
+
+ // Kludgy IF to avoid deleting SNAT rules not created by us.
+ // If matches, let's skip it and continue the loop
+ if v.RuleType == "SNAT" &&
+ v.GatewayNatRule.OriginalIP == internal &&
+ v.GatewayNatRule.TranslatedIP == external &&
+ v.GatewayNatRule.Interface.HREF == uplinkif {
+ continue
+ }
+
+ // If doesn't match the above IFs, it's something we need to preserve,
+ // let's add it to the new NatService struct
+ newnatservice.NatRule = append(newnatservice.NatRule, newedgeconfig.NatService.NatRule[k])
+
+ }
+
+ // Fill the new NatService Section
+ newedgeconfig.NatService = newnatservice
+
+ // Take care of the Firewall service
+ newfwservice := &types.FirewallService{}
+
+ // Copy over the firewall configuration
+ newfwservice.IsEnabled = newedgeconfig.FirewallService.IsEnabled
+ newfwservice.DefaultAction = newedgeconfig.FirewallService.DefaultAction
+ newfwservice.LogDefaultAction = newedgeconfig.FirewallService.LogDefaultAction
+
+ for k, v := range newedgeconfig.FirewallService.FirewallRule {
+
+ // Kludgy IF to avoid deleting inbound FW rules not created by us.
+ // If matches, let's skip it and continue the loop
+ if v.Policy == "allow" &&
+ v.Protocols.Any == true &&
+ v.DestinationPortRange == "Any" &&
+ v.SourcePortRange == "Any" &&
+ v.SourceIP == "Any" &&
+ v.DestinationIP == external {
+ continue
+ }
+
+ // Kludgy IF to avoid deleting outbound FW rules not created by us.
+ // If matches, let's skip it and continue the loop
+ if v.Policy == "allow" &&
+ v.Protocols.Any == true &&
+ v.DestinationPortRange == "Any" &&
+ v.SourcePortRange == "Any" &&
+ v.SourceIP == internal &&
+ v.DestinationIP == "Any" {
+ continue
+ }
+
+ // If doesn't match the above IFs, it's something we need to preserve,
+ // let's add it to the new FirewallService struct
+ newfwservice.FirewallRule = append(newfwservice.FirewallRule, newedgeconfig.FirewallService.FirewallRule[k])
+
+ }
+
+ // Fill the new FirewallService Section
+ newedgeconfig.FirewallService = newfwservice
+
+ // Fix
+ newedgeconfig.NatService.IsEnabled = true
+
+ output, err := xml.MarshalIndent(newedgeconfig, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", 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, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
+ s.Path += "/action/configureServices"
+
+ 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
+
+}
+
+func (e *EdgeGateway) Create1to1Mapping(internal, external, description string) (Task, error) {
+
+ // Refresh EdgeGateway rules
+ err := e.Refresh()
+ if err != nil {
+ fmt.Printf("error: %v\n", err)
+ }
+
+ var uplinkif string
+ for _, gifs := range e.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface {
+ if gifs.InterfaceType == "uplink" {
+ uplinkif = gifs.Network.HREF
+ }
+ }
+
+ newedgeconfig := e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration
+
+ snat := &types.NatRule{
+ Description: description,
+ RuleType: "SNAT",
+ IsEnabled: true,
+ GatewayNatRule: &types.GatewayNatRule{
+ Interface: &types.Reference{
+ HREF: uplinkif,
+ },
+ OriginalIP: internal,
+ TranslatedIP: external,
+ Protocol: "any",
+ },
+ }
+
+ newedgeconfig.NatService.NatRule = append(newedgeconfig.NatService.NatRule, snat)
+
+ dnat := &types.NatRule{
+ Description: description,
+ RuleType: "DNAT",
+ IsEnabled: true,
+ GatewayNatRule: &types.GatewayNatRule{
+ Interface: &types.Reference{
+ HREF: uplinkif,
+ },
+ OriginalIP: external,
+ OriginalPort: "any",
+ TranslatedIP: internal,
+ TranslatedPort: "any",
+ Protocol: "any",
+ },
+ }
+
+ newedgeconfig.NatService.NatRule = append(newedgeconfig.NatService.NatRule, dnat)
+
+ fwin := &types.FirewallRule{
+ Description: description,
+ IsEnabled: true,
+ Policy: "allow",
+ Protocols: &types.FirewallRuleProtocols{
+ Any: true,
+ },
+ DestinationPortRange: "Any",
+ DestinationIP: external,
+ SourcePortRange: "Any",
+ SourceIP: "Any",
+ EnableLogging: false,
+ }
+
+ newedgeconfig.FirewallService.FirewallRule = append(newedgeconfig.FirewallService.FirewallRule, fwin)
+
+ fwout := &types.FirewallRule{
+ Description: description,
+ IsEnabled: true,
+ Policy: "allow",
+ Protocols: &types.FirewallRuleProtocols{
+ Any: true,
+ },
+ DestinationPortRange: "Any",
+ DestinationIP: "Any",
+ SourcePortRange: "Any",
+ SourceIP: internal,
+ EnableLogging: false,
+ }
+
+ newedgeconfig.FirewallService.FirewallRule = append(newedgeconfig.FirewallService.FirewallRule, fwout)
+
+ output, err := xml.MarshalIndent(newedgeconfig, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", 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, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
+ s.Path += "/action/configureServices"
+
+ 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/Godeps/_workspace/src/github.com/vmware/govcloudair/edgegateway_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/edgegateway_test.go
new file mode 100644
index 0000000000..70217e2503
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/edgegateway_test.go
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "github.com/vmware/govcloudair/testutil"
+
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) Test_Refresh(c *C) {
+
+ // Get the Org populated
+ testServer.ResponseMap(2, testutil.ResponseMap{
+ "/api/vdc/00000000-0000-0000-0000-000000000000/edgeGateways": testutil.Response{200, nil, edgegatewayqueryresultsExample},
+ "/api/admin/edgeGateway/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, edgegatewayExample},
+ })
+
+ edge, err := s.vdc.FindEdgeGateway("M916272752-5793")
+ _ = testServer.WaitRequests(2)
+ testServer.Flush()
+
+ c.Assert(err, IsNil)
+ c.Assert(edge.EdgeGateway.Name, Equals, "M916272752-5793")
+
+ testServer.Response(200, nil, edgegatewayExample)
+ err = edge.Refresh()
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+
+ c.Assert(err, IsNil)
+ c.Assert(edge.EdgeGateway.Name, Equals, "M916272752-5793")
+
+}
+
+func (s *S) Test_1to1Mappings(c *C) {
+
+ testServer.ResponseMap(2, testutil.ResponseMap{
+ "/api/vdc/00000000-0000-0000-0000-000000000000/edgeGateways": testutil.Response{200, nil, edgegatewayqueryresultsExample},
+ "/api/admin/edgeGateway/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, edgegatewayExample},
+ })
+
+ edge, err := s.vdc.FindEdgeGateway("M916272752-5793")
+ _ = testServer.WaitRequests(2)
+ testServer.Flush()
+
+ c.Assert(err, IsNil)
+ c.Assert(edge.EdgeGateway.Name, Equals, "M916272752-5793")
+
+ testServer.ResponseMap(2, testutil.ResponseMap{
+ "/api/admin/edgeGateway/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, edgegatewayExample},
+ "/api/admin/edgeGateway/00000000-0000-0000-0000-000000000000/action/configureServices": testutil.Response{200, nil, taskExample},
+ })
+
+ _, err = edge.Create1to1Mapping("10.0.0.1", "20.0.0.2", "description")
+ _ = testServer.WaitRequests(2)
+
+ c.Assert(err, IsNil)
+
+ testServer.ResponseMap(2, testutil.ResponseMap{
+ "/api/admin/edgeGateway/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, edgegatewayExample},
+ "/api/admin/edgeGateway/00000000-0000-0000-0000-000000000000/action/configureServices": testutil.Response{200, nil, taskExample},
+ })
+
+ _, err = edge.Remove1to1Mapping("10.0.0.1", "20.0.0.2")
+ _ = testServer.WaitRequests(2)
+
+ c.Assert(err, IsNil)
+
+}
+
+var edgegatewayqueryresultsExample = `
+
+
+
+
+
+`
+
+var edgegatewayExample = `
+
+
+
+
+
+
+
+ compact
+
+
+ JGray Network
+ JGray Network
+
+ internal
+
+ 192.168.108.1
+ 255.255.255.0
+ 192.168.108.1
+
+ false
+ false
+
+
+ M916272752-5793-default-routed
+ M916272752-5793-default-routed
+
+ internal
+
+ 192.168.109.1
+ 255.255.255.0
+ 192.168.109.1
+
+ false
+ false
+
+
+ d2p3-ext
+ d2p3-ext
+
+ uplink
+
+ 23.92.224.1
+ 255.255.254.0
+ 23.92.225.51
+
+
+ 23.92.225.73
+ 23.92.225.75
+
+
+ 23.92.225.27
+ 23.92.225.27
+
+
+ 23.92.225.11
+ 23.92.225.11
+
+
+ 23.92.225.54
+ 23.92.225.54
+
+
+ 23.92.224.34
+ 23.92.224.34
+
+
+ 23.92.225.5
+ 23.92.225.5
+
+
+ 23.92.225.34
+ 23.92.225.34
+
+
+ 23.92.224.255
+ 23.92.224.255
+
+
+ 23.92.225.49
+ 23.92.225.51
+
+
+ 23.92.225.62
+ 23.92.225.62
+
+
+ 23.92.225.43
+ 23.92.225.43
+
+
+ 23.92.225.30
+ 23.92.225.30
+
+
+
+ true
+ 1024.0
+ 1024.0
+ true
+
+
+
+
+ true
+ drop
+ false
+
+ 1
+ true
+ false
+ ssh prd-001
+ allow
+
+ true
+
+ 999
+ 999
+ 23.92.225.51
+ -1
+ Any
+ 60.241.110.111
+ false
+
+
+ 2
+ true
+ false
+ inet prd-001
+ allow
+
+ true
+
+ -1
+ Any
+ Any
+ -1
+ Any
+ 192.168.109.8
+ false
+
+
+ 3
+ true
+ false
+ suppah megah rulez creati0nz
+ allow
+
+ true
+
+ -1
+ Any
+ 23.92.224.255
+ -1
+ Any
+ Any
+ false
+
+
+ 4
+ true
+ false
+ suppah megah rulez creati0nz
+ allow
+
+ true
+
+ -1
+ Any
+ Any
+ -1
+ Any
+ 192.168.109.3
+ false
+
+
+
+ false
+
+ DNAT
+ true
+ 65537
+
+
+ 23.92.225.51
+ 999
+ 192.168.109.8
+ 22
+ Tcp
+
+
+
+ SNAT
+ true
+ 65538
+
+
+ 192.168.109.8
+ 23.92.225.51
+
+
+
+ SNAT
+ true
+ 65539
+
+
+ 192.168.109.3
+ 23.92.224.255
+
+
+
+ DNAT
+ true
+ 65540
+
+
+ 23.92.224.255
+ any
+ 192.168.109.3
+ any
+ any
+
+
+
+
+ true
+
+ Test VPN Alpha
+ For OC Pod Testing
+
+ 192.168.110.99
+
+ 64.184.133.62
+ 192.168.110.99
+ 23.92.225.51
+ 23.92.225.51
+
+ M916272752-5793-default-routed
+ 192.168.109.1
+ 255.255.255.0
+
+
+ 192.168.120.0/24
+ 192.168.120.0
+ 255.255.255.0
+
+ Blah1Blah2Blah3Blah1Blah2Blah3Blah1Blah2Blah3
+ false
+ AES256
+ 1500
+ true
+ false
+
+
+ JGray VPN
+
+ 67.172.148.74
+
+ 67.172.148.74
+ 67.172.148.74
+ 23.92.225.51
+ 23.92.225.51
+
+ JGray Network
+ 192.168.108.1
+ 255.255.255.0
+
+
+ 192.168.1.0/24
+ 192.168.1.0
+ 255.255.255.0
+
+ fM7puHkGbg6tqpd4jKNhBo45mbs8fw3yapgt3H7f97a2jrkLyYjP9eSH4oGwps7u
+ false
+ AES256
+ 1500
+ false
+ false
+
+
+
+ false
+
+
+ false
+
+
+ true
+ true
+
+
+ `
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/org.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/org.go
new file mode 100644
index 0000000000..e0059d31ae
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/org.go
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "fmt"
+ "net/url"
+
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type Org struct {
+ Org *types.Org
+ c *Client
+}
+
+func NewOrg(c *Client) *Org {
+ return &Org{
+ Org: new(types.Org),
+ c: c,
+ }
+}
+
+func (o *Org) FindCatalog(catalog string) (Catalog, error) {
+
+ for _, av := range o.Org.Link {
+ if av.Rel == "down" && av.Type == "application/vnd.vmware.vcloud.catalog+xml" && av.Name == catalog {
+ u, err := url.ParseRequestURI(av.HREF)
+
+ if err != nil {
+ return Catalog{}, fmt.Errorf("error decoding org response: %s", err)
+ }
+
+ req := o.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(o.c.Http.Do(req))
+ if err != nil {
+ return Catalog{}, fmt.Errorf("error retreiving catalog: %s", err)
+ }
+
+ cat := NewCatalog(o.c)
+
+ if err = decodeBody(resp, cat.Catalog); err != nil {
+ return Catalog{}, fmt.Errorf("error decoding catalog response: %s", err)
+ }
+
+ // The request was successful
+ return *cat, nil
+
+ }
+ }
+
+ return Catalog{}, fmt.Errorf("can't find catalog: %s", catalog)
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/org_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/org_test.go
new file mode 100644
index 0000000000..401d430804
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/org_test.go
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) Test_FindCatalog(c *C) {
+
+ // Get the Org populated
+ testServer.Response(200, nil, orgExample)
+ org, err := s.vdc.GetVDCOrg()
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+ c.Assert(err, IsNil)
+
+ // Find Catalog
+ testServer.Response(200, nil, catalogExample)
+ cat, err := org.FindCatalog("Public Catalog")
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+ c.Assert(err, IsNil)
+ c.Assert(cat.Catalog.Description, Equals, "vCHS service catalog")
+
+}
+
+var orgExample = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OrganizationName
+
+ `
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/orgvdcnetwork.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/orgvdcnetwork.go
new file mode 100644
index 0000000000..979dfd0eb8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/orgvdcnetwork.go
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type OrgVDCNetwork struct {
+ OrgVDCNetwork *types.OrgVDCNetwork
+ c *Client
+}
+
+func NewOrgVDCNetwork(c *Client) *OrgVDCNetwork {
+ return &OrgVDCNetwork{
+ OrgVDCNetwork: new(types.OrgVDCNetwork),
+ c: c,
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/orgvdcnetwork_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/orgvdcnetwork_test.go
new file mode 100644
index 0000000000..a230d5ef0c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/orgvdcnetwork_test.go
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+var orgvdcnetExample = `
+
+
+
+
+
+ This routed network was created with Create VDC.
+
+
+
+ false
+ 192.168.109.1
+ 255.255.255.0
+ true
+
+
+ 192.168.109.2
+ 192.168.109.100
+
+
+
+
+ natRouted
+ false
+
+ false
+
+ `
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/script/coverage b/Godeps/_workspace/src/github.com/vmware/govcloudair/script/coverage
new file mode 100755
index 0000000000..5ffa996a35
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/script/coverage
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Generate test coverage statistics for Go packages.
+#
+# Works around the fact that `go test -coverprofile` currently does not work
+# with multiple packages, see https://code.google.com/p/go/issues/detail?id=6909
+#
+# Usage: script/coverage [--html|--coveralls]
+#
+# --html Additionally create HTML report and open it in browser
+# --coveralls Push coverage statistics to coveralls.io
+#
+
+set -e
+
+workdir=.cover
+profile="$workdir/cover.out"
+mode=count
+
+generate_cover_data() {
+ rm -rf "$workdir"
+ mkdir "$workdir"
+
+ for pkg in "$@"; do
+ f="$workdir/$(echo $pkg | tr / -).cover"
+ go test -covermode="$mode" -coverprofile="$f" "$pkg"
+ done
+
+ echo "mode: $mode" >"$profile"
+ grep -h -v "^mode:" "$workdir"/*.cover >>"$profile"
+}
+
+show_cover_report() {
+ go tool cover -${1}="$profile"
+}
+
+push_to_coveralls() {
+ echo "Pushing coverage statistics to coveralls.io"
+ goveralls -coverprofile="$profile"
+}
+
+generate_cover_data $(go list ./...)
+show_cover_report func
+case "$1" in
+"")
+ ;;
+--html)
+ show_cover_report html ;;
+--coveralls)
+ push_to_coveralls ;;
+*)
+ echo >&2 "error: invalid option: $1"; exit 1 ;;
+esac
\ No newline at end of file
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/task.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/task.go
new file mode 100644
index 0000000000..c6629369c3
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/task.go
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "fmt"
+ "net/url"
+ "time"
+
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type Task struct {
+ Task *types.Task
+ c *Client
+}
+
+func NewTask(c *Client) *Task {
+ return &Task{
+ Task: new(types.Task),
+ c: c,
+ }
+}
+
+func (t *Task) Refresh() error {
+
+ if t.Task == nil {
+ return fmt.Errorf("cannot refresh, Object is empty")
+ }
+
+ u, _ := url.ParseRequestURI(t.Task.HREF)
+
+ req := t.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(t.c.Http.Do(req))
+ if err != nil {
+ return fmt.Errorf("error retrieving task: %s", err)
+ }
+
+ // Empty struct before a new unmarshal, otherwise we end up with duplicate
+ // elements in slices.
+ t.Task = &types.Task{}
+
+ if err = decodeBody(resp, t.Task); err != nil {
+ return fmt.Errorf("error decoding task response: %s", err)
+ }
+
+ // The request was successful
+ return nil
+}
+
+func (t *Task) WaitTaskCompletion() error {
+
+ if t.Task == nil {
+ return fmt.Errorf("cannot refresh, Object is empty")
+ }
+
+ for {
+ err := t.Refresh()
+ if err != nil {
+ return fmt.Errorf("error retreiving task: %s", err)
+ }
+
+ // If task is not in a waiting status we're done, check if there's an error and return it.
+ if t.Task.Status != "queued" && t.Task.Status != "preRunning" && t.Task.Status != "running" {
+ if t.Task.Status == "error" {
+ return fmt.Errorf("task did not complete succesfully: %s", t.Task.Description)
+ }
+ return nil
+ }
+
+ // Sleep for 3 seconds and try again.
+ time.Sleep(3 * time.Second)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/task_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/task_test.go
new file mode 100644
index 0000000000..f743772463
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/task_test.go
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) Test_WaitTaskCompletion(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.Deploy()
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+ c.Assert(err, IsNil)
+
+ testServer.Response(200, nil, taskExample)
+ err = task.WaitTaskCompletion()
+ _ = testServer.WaitRequest()
+ testServer.Flush()
+ c.Assert(err, IsNil)
+
+}
+
+var taskExample = `
+
+
+
+
+
+
+
+ `
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/testutil/http.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/testutil/http.go
new file mode 100644
index 0000000000..5ce9e66c59
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/testutil/http.go
@@ -0,0 +1,186 @@
+//
+// The software in this package is published under the terms of the Mozilla
+// Public License, version 2.0 a copy of which has been included with this
+// distribution in the LICENSE file.
+//
+
+package testutil
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "time"
+)
+
+type HTTPServer struct {
+ URL string
+ Timeout time.Duration
+ started bool
+ request chan *http.Request
+ response chan ResponseFunc
+}
+
+type Response struct {
+ Status int
+ Headers map[string]string
+ Body string
+}
+
+var DefaultClient = &http.Client{
+ Transport: &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
+ },
+}
+
+func NewHTTPServer() *HTTPServer {
+ return &HTTPServer{URL: "http://localhost:4444", Timeout: 5 * time.Second}
+}
+
+type ResponseFunc func(path string) Response
+
+func (s *HTTPServer) Start() {
+ if s.started {
+ return
+ }
+ s.started = true
+ s.request = make(chan *http.Request, 1024)
+ s.response = make(chan ResponseFunc, 1024)
+ u, err := url.Parse(s.URL)
+ if err != nil {
+ panic(err)
+ }
+ l, err := net.Listen("tcp", u.Host)
+ if err != nil {
+ panic(err)
+ }
+ go http.Serve(l, s)
+
+ s.Response(203, nil, "")
+ for {
+ // Wait for it to be up.
+ resp, err := http.Get(s.URL)
+ if err == nil && resp.StatusCode == 203 {
+ break
+ }
+ time.Sleep(1e8)
+ }
+ s.WaitRequest() // Consume dummy request.
+}
+
+// Flush discards all pending requests and responses.
+func (s *HTTPServer) Flush() {
+ for {
+ select {
+ case <-s.request:
+ case <-s.response:
+ default:
+ return
+ }
+ }
+}
+
+func body(req *http.Request) string {
+ data, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ panic(err)
+ }
+ return string(data)
+}
+
+func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ req.ParseMultipartForm(1e6)
+ data, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ panic(err)
+ }
+ req.Body = ioutil.NopCloser(bytes.NewBuffer(data))
+ s.request <- req
+ var resp Response
+ select {
+ case respFunc := <-s.response:
+ resp = respFunc(req.URL.Path)
+ case <-time.After(s.Timeout):
+ const msg = "ERROR: Timeout waiting for test to prepare a response\n"
+ fmt.Fprintf(os.Stderr, msg)
+ resp = Response{500, nil, msg}
+ }
+ if resp.Headers != nil {
+ h := w.Header()
+ for k, v := range resp.Headers {
+ h.Set(k, v)
+ }
+ }
+ if resp.Status != 0 {
+ w.WriteHeader(resp.Status)
+ }
+ w.Write([]byte(resp.Body))
+}
+
+// WaitRequests returns the next n requests made to the http server from
+// the queue. If not enough requests were previously made, it waits until
+// the timeout value for them to be made.
+func (s *HTTPServer) WaitRequests(n int) []*http.Request {
+ reqs := make([]*http.Request, 0, n)
+ for i := 0; i < n; i++ {
+ select {
+ case req := <-s.request:
+ reqs = append(reqs, req)
+ case <-time.After(s.Timeout):
+ panic("Timeout waiting for request")
+ }
+ }
+ return reqs
+}
+
+// WaitRequest returns the next request made to the http server from
+// the queue. If no requests were previously made, it waits until the
+// timeout value for one to be made.
+func (s *HTTPServer) WaitRequest() *http.Request {
+ return s.WaitRequests(1)[0]
+}
+
+// ResponseFunc prepares the test server to respond the following n
+// requests using f to build each response.
+func (s *HTTPServer) ResponseFunc(n int, f ResponseFunc) {
+ for i := 0; i < n; i++ {
+ s.response <- f
+ }
+}
+
+// ResponseMap maps request paths to responses.
+type ResponseMap map[string]Response
+
+// ResponseMap prepares the test server to respond the following n
+// requests using the m to obtain the responses.
+func (s *HTTPServer) ResponseMap(n int, m ResponseMap) {
+ f := func(path string) Response {
+ for rpath, resp := range m {
+ if rpath == path {
+ return resp
+ }
+ }
+ body := "Path not found in response map: " + path
+ return Response{Status: 500, Body: body}
+ }
+ s.ResponseFunc(n, f)
+}
+
+// Responses prepares the test server to respond the following n requests
+// using the provided response parameters.
+func (s *HTTPServer) Responses(n int, status int, headers map[string]string, body string) {
+ f := func(path string) Response {
+ return Response{status, headers, body}
+ }
+ s.ResponseFunc(n, f)
+}
+
+// Response prepares the test server to respond the following request
+// using the provided response parameters.
+func (s *HTTPServer) Response(status int, headers map[string]string, body string) {
+ s.Responses(1, status, headers, body)
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/types/v56/types.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/types/v56/types.go
new file mode 100644
index 0000000000..186ae31ffe
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/types/v56/types.go
@@ -0,0 +1,1394 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package types
+
+import (
+ "encoding/xml"
+)
+
+// Maps status Attribute Values for VAppTemplate, VApp, Vm, and Media Objects
+var VAppStatuses = map[int]string{
+ -1: "FAILED_CREATION",
+ 0: "UNRESOLVED",
+ 1: "RESOLVED",
+ 2: "DEPLOYED",
+ 3: "SUSPENDED",
+ 4: "POWERED_ON",
+ 5: "WAITING_FOR_INPUT",
+ 6: "UNKNOWN",
+ 7: "UNRECOGNIZED",
+ 8: "POWERED_OFF",
+ 9: "INCONSISTENT_STATE",
+ 10: "MIXED",
+ 11: "DESCRIPTOR_PENDING",
+ 12: "COPYING_CONTENTS",
+ 13: "DISK_CONTENTS_PENDING",
+ 14: "QUARANTINED",
+ 15: "QUARANTINE_EXPIRED",
+ 16: "REJECTED",
+ 17: "TRANSFER_TIMEOUT",
+ 18: "VAPP_UNDEPLOYED",
+ 19: "VAPP_PARTIALLY_DEPLOYED",
+}
+
+// Maps status Attribute Values for VDC Objects
+var VDCStatuses = map[int]string{
+ -1: "FAILED_CREATION",
+ 0: "NOT_READY",
+ 1: "READY",
+ 2: "UNKNOWN",
+ 3: "UNRECOGNIZED",
+}
+
+// VCD API
+
+// Type: DefaultStorageProfileSection_Type
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Name of the storage profile that will be specified for this virtual machine. The named storage profile must exist in the organization vDC that contains the virtual machine. If not specified, the default storage profile for the vDC is used.
+// Since: 5.1
+type DefaultStorageProfileSection struct {
+ StorageProfile string `xml:"StorageProfile,omitempty"`
+}
+
+// Type: CustomizationSectionType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a vApp template customization settings.
+// Since: 1.0
+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"`
+ Link []*Link `xml:"Link,omitempty"`
+}
+
+// Type: LeaseSettingsSectionType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents vApp lease settings.
+// Since: 0.9
+type LeaseSettingsSection struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ DeploymentLeaseExpiration string `xml:"DeploymentLeaseExpiration,omitempty"`
+ DeploymentLeaseInSeconds int `xml:"DeploymentLeaseInSeconds,omitempty"`
+ Link *Link `xml:"Link,omitempty"`
+ StorageLeaseExpiration string `xml:"StorageLeaseExpiration,omitempty"`
+ StorageLeaseInSeconds int `xml:"StorageLeaseInSeconds,omitempty"`
+}
+
+// Type: IpRangeType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a range of IP addresses, start and end inclusive.
+// Since: 0.9
+type IPRange struct {
+ EndAddress string `xml:"EndAddress"` // End address of the IP range.
+ StartAddress string `xml:"StartAddress"` // Start address of the IP range.
+}
+
+// Type: DhcpServiceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a DHCP network service.
+// Since:
+type DhcpService struct {
+ DefaultLeaseTime int `xml:"DefaultLeaseTime,omitempty"` // Default lease in seconds for DHCP addresses.
+ DomainName string `xml:"DomainName,omitempty"` // The domain name.
+ IPRange *IPRange `xml:"IpRange"` // IP range for DHCP addresses.
+ IsEnabled bool `xml:"IsEnabled"` // Enable or disable the service using this flag
+ MaxLeaseTime int `xml:"MaxLeaseTime"` // Max lease in seconds for DHCP addresses.
+ PrimaryNameServer string `xml:"PrimaryNameServer,omitempty"` // The primary name server.
+ RouterIP string `xml:"RouterIp,omitempty"` // Router IP.
+ SecondaryNameServer string `xml:"SecondaryNameServer,omitempty"` // The secondary name server.
+ SubMask string `xml:"SubMask,omitempty"` // The subnet mask.
+}
+
+// Type: NetworkFeaturesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents features of a network.
+// Since:
+type NetworkFeatures struct {
+ DhcpService *DhcpService `xml:"DhcpService,omitempty"` // Substitute for NetworkService. DHCP service settings
+ FirewallService *FirewallService `xml:"FirewallService,omitempty"` // Substitute for NetworkService. Firewall service settings
+ NatService *NatService `xml:"NatService,omitempty"` // Substitute for NetworkService. NAT service settings
+ LoadBalancerService *LoadBalancerService `xml:"LoadBalancerService,omitempty"` // Substitute for NetworkService. Load Balancer service settings
+ StaticRoutingService *StaticRoutingService `xml:"StaticRoutingService,omitempty"` // Substitute for NetworkService. Static Routing service settings
+ // TODO: Not Implemented
+ // IpsecVpnService IpsecVpnService `xml:"IpsecVpnService,omitempty"` // Substitute for NetworkService. Ipsec Vpn service settings
+}
+
+// Type: IpAddressesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: A list of IP addresses.
+// Since: 0.9
+type IPAddresses struct {
+ IPAddress string `xml:"IpAddress,omitempty"` // An IP address.
+}
+
+// Type: IpRangesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a list of IP ranges.
+// Since: 0.9
+type IPRanges struct {
+ IPRange []*IPRange `xml:"IpRange,omitempty"` // IP range.
+}
+
+// Type: IpScopeType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Specify network settings like gateway, network mask, DNS servers, IP ranges, etc.
+// Since: 0.9
+type IPScope struct {
+ IsInherited bool `xml:"IsInherited"` // True if the IP scope is inherit from parent network.
+ Gateway string `xml:"Gateway,omitempty"` // Gateway of the network.
+ Netmask string `xml:"Netmask,omitempty"` // Network mask.
+ DNS1 string `xml:"Dns1,omitempty"` // Primary DNS server.
+ DNS2 string `xml:"Dns2,omitempty"` // Secondary DNS server.
+ DNSSuffix string `xml:"DnsSuffix,omitempty"` // DNS suffix.
+ IsEnabled bool `xml:"IsEnabled"` // Indicates if subnet is enabled or not. Default value is True.
+ IPRanges *IPRanges `xml:"IpRanges,omitempty"` // IP ranges used for static pool allocation in the network.
+ AllocatedIPAddresses *IPAddresses `xml:"AllocatedIpAddresses,omitempty"` // Read-only list of allocated IP addresses in the network.
+ SubAllocations *SubAllocations `xml:"SubAllocations,omitempty"` // Read-only list of IP addresses that are sub allocated to edge gateways.
+}
+
+// Type: SubAllocationsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: A list of IP addresses that are sub allocated to edge gateways.
+// Since: 5.1
+type SubAllocations struct {
+ // Attributes
+ 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 []*Link `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.
+}
+
+// Type: SubAllocationType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: IP range sub allocated to an edge gateway.
+// Since: 5.1
+type SubAllocation struct {
+ EdgeGateway *Reference `xml:"EdgeGateway,omitempty"` // Edge gateway that uses this sub allocation.
+ IPRanges *IPRanges `xml:"IpRanges,omitempty"` // IP range sub allocated to the edge gateway.
+}
+
+// Type: IpScopesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a list of IP scopes.
+// Since: 5.1
+type IPScopes struct {
+ IPScope IPScope `xml:"IpScope"` // IP scope.
+}
+
+// Type: NetworkConfigurationType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: The configurations applied to a network. This is an abstract base type. The concrete types include those for vApp and Organization wide networks.
+// Since: 0.9
+type NetworkConfiguration struct {
+ BackwardCompatibilityMode bool `xml:"BackwardCompatibilityMode"`
+ Features *NetworkFeatures `xml:"Features,omitempty"`
+ ParentNetwork *Reference `xml:"ParentNetwork,omitempty"`
+ FenceMode string `xml:"FenceMode"`
+ IPScopes *IPScopes `xml:"IpScopes,omitempty"`
+ RetainNetInfoAcrossDeployments bool `xml:"RetainNetInfoAcrossDeployments"`
+ // TODO: Not Implemented
+ // RouterInfo RouterInfo `xml:"RouterInfo,omitempty"`
+ // SyslogServerSettings SyslogServerSettings `xml:"SyslogServerSettings,omitempty"`
+}
+
+// Type: VAppNetworkConfigurationType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a vApp network configuration.
+// Since: 0.9
+type VAppNetworkConfiguration struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ NetworkName string `xml:"networkName,attr"`
+
+ Configuration *NetworkConfiguration `xml:"Configuration"`
+ Description string `xml:"Description,omitempty"`
+ IsDeployed bool `xml:"IsDeployed"`
+ Link *Link `xml:"Link,omitempty"`
+}
+
+// Type: NetworkConfigSectionType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for vApp networks.
+// Since: 0.9
+type NetworkConfigSection struct {
+ // Extends OVF Section_Type
+ // FIXME: Fix the OVF section
+ Info string `xml:"ovf:Info"`
+ //
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Link *Link `xml:"Link,omitempty"`
+ NetworkConfig *VAppNetworkConfiguration `xml:"NetworkConfig,omitempty"`
+}
+
+// Type: NetworkConnectionType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a network connection in the virtual machine.
+// Since: 0.9
+type NetworkConnection struct {
+ Network string `xml:"network,attr"` // Name of the network to which this NIC is connected.
+ NetworkConnectionIndex int `xml:"NetworkConnectionIndex"` // Virtual slot number associated with this NIC. First slot number is 0.
+ IsConnected bool `xml:"IsConnected"` // If the virtual machine is undeployed, this value specifies whether the NIC should be connected upon deployment. If the virtual machine is deployed, this value reports the current status of this NIC's connection, and can be updated to change that connection status.
+ NeedsCustomization bool `xml:"needsCustomization,attr,omitempty"` // True if this NIC needs customization.
+ ExternalIPAddress string `xml:"ExternalIpAddress,omitempty"` // If the network to which this NIC connects provides NAT services, the external address assigned to this NIC appears here.
+ IPAddress string `xml:"IpAddress,omitempty"` // IP address assigned to this NIC.
+ IPAddressAllocationMode string `xml:"IpAddressAllocationMode"` // IP address allocation mode for this connection. One of: POOL (A static IP address is allocated automatically from a pool of addresses.) DHCP (The IP address is obtained from a DHCP service.) MANUAL (The IP address is assigned manually in the IpAddress element.) NONE (No IP addressing mode specified.)
+ MACAddress string `xml:"MACAddress,omitempty"` // MAC address associated with the NIC.
+}
+
+// Type: NetworkConnectionSectionType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for the network connections of this virtual machine.
+// Since: 0.9
+type NetworkConnectionSection struct {
+ // Extends OVF Section_Type
+ // FIXME: Fix the OVF section
+ Info string `xml:"ovf:Info"`
+ //
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Link *Link `xml:"Link,omitempty"`
+ PrimaryNetworkConnectionIndex int `xml:"PrimaryNetworkConnectionIndex"`
+ NetworkConnection *NetworkConnection `xml:"NetworkConnection,omitempty"`
+}
+
+// Type: InstantiationParamsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for ovf:Section_Type elements that specify vApp configuration on instantiate, compose, or recompose.
+// Since: 0.9
+type InstantiationParams struct {
+ CustomizationSection *CustomizationSection `xml:"CustomizationSection,omitempty"`
+ DefaultStorageProfileSection *DefaultStorageProfileSection `xml:"DefaultStorageProfileSection,omitempty"`
+ GuestCustomizationSection *GuestCustomizationSection `xml:"GuestCustomizationSection,omitempty"`
+ LeaseSettingsSection *LeaseSettingsSection `xml:"LeaseSettingsSection,omitempty"`
+ NetworkConfigSection *NetworkConfigSection `xml:"NetworkConfigSection,omitempty"`
+ NetworkConnectionSection *NetworkConnectionSection `xml:"NetworkConnectionSection,omitempty"`
+ // TODO: Not Implemented
+ // SnapshotSection SnapshotSection `xml:"SnapshotSection,omitempty"`
+}
+
+// Type: OrgVdcNetworkType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents an Org vDC network in the vCloud model.
+// Since: 5.1
+type OrgVDCNetwork struct {
+ XMLName xml.Name `xml:"OrgVdcNetwork"`
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ ID string `xml:"id,attr,omitempty"`
+ OperationKey string `xml:"operationKey,attr,omitempty"`
+ Name string `xml:"name,attr"`
+ Status string `xml:"status,attr,omitempty"`
+ Configuration *NetworkConfiguration `xml:"Configuration,omitempty"`
+ Description string `xml:"Description,omitempty"`
+ EdgeGateway *Reference `xml:"EdgeGateway,omitempty"`
+ IsShared bool `xml:"IsShared"`
+ Link []Link `xml:"Link"`
+ ServiceConfig *GatewayFeatures `xml:"ServiceConfig,omitempty"` // Specifies the service configuration for an isolated Org vDC networks
+ Tasks TasksInProgress `xml:"Tasks,omitempty"`
+}
+
+// Type: SupportedHardwareVersionType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a supported virtual hardware version.
+// Since: 1.5
+type SupportedHardwareVersion struct {
+ SupportedHardwareVersion string `xml:"SupportedHardwareVersion"`
+}
+
+// Type: SupportedHardwareVersionsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Contains a list of VMware virtual hardware versions supported in this vDC.
+// Since: 1.5
+type SupportedHardwareVersions struct {
+ SupportedHardwareVersion []*SupportedHardwareVersion `xml:"SupportedHardwareVersion,omitempty"` // A virtual hardware version supported in this vDC.
+}
+
+// Type: CapabilitiesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Collection of supported hardware capabilities.
+// Since: 1.5
+type Capabilities struct {
+ SupportedHardwareVersions *SupportedHardwareVersions `xml:"SupportedHardwareVersions,omitempty"` // Read-only list of virtual hardware versions supported by this vDC.
+}
+
+// Type: VdcType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the user view of an organization vDC.
+// Since: 0.9
+type Vdc struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ ID string `xml:"id,attr,omitempty"`
+ OperationKey string `xml:"operationKey,attr,omitempty"`
+ Name string `xml:"name,attr"`
+ Status string `xml:"status,attr,omitempty"`
+
+ AllocationModel string `xml:"AllocationModel"`
+ AvailableNetworks []*AvailableNetworks `xml:"AvailableNetworks,omitempty"`
+ Capabilities []*Capabilities `xml:"Capabilities,omitempty"`
+ ComputeCapacity []*ComputeCapacity `xml:"ComputeCapacity"`
+ Description string `xml:"Description,omitempty"`
+ IsEnabled bool `xml:"IsEnabled"`
+ Link []*Link `xml:"Link,omitempty"`
+ NetworkQuota int `xml:"NetworkQuota"`
+ NicQuota int `xml:"NicQuota"`
+ ResourceEntities []*ResourceEntities `xml:"ResourceEntities,omitempty"`
+ Tasks *TasksInProgress `xml:"Taks,omitempty"`
+ UsedNetworkCount int `xml:"UsedNetworkCount,omitempty"`
+ VdcStorageProfiles []*VdcStorageProfiles `xml:"VdcStorageProfiles"`
+ VMQuota int `xml:"VmQuota"`
+}
+
+// Type: TaskType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents an asynchronous operation in vCloud Director.
+// Since: 0.9
+type Task struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ ID string `xml:"id,attr,omitempty"`
+ OperationKey string `xml:"operationKey,attr,omitempty"`
+ Name string `xml:"name,attr"`
+ Status string `xml:"status,attr"`
+ Operation string `xml:"operation,attr,omitempty"`
+ OperationName string `xml:"operationName,attr,omitempty"`
+ ServiceNamespace string `xml:"serviceNamespace,attr,omitempty"`
+ StartTime string `xml:"startTime,attr,omitempty"`
+ EndTime string `xml:"endTime,attr,omitempty"`
+ ExpiryTime string `xml:"expiryTime,attr,omitempty"`
+ CancelRequested bool `xml:"cancelRequested,attr,omitempty"`
+ Description string `xml:"Description,omitempty"`
+ Details string `xml:"Details,omitempty"`
+ Error *Error `xml:"Error,omitempty"`
+ Link *Link `xml:"Link,omitempty"`
+ Organization *Reference `xml:"Organization,omitempty"`
+ Owner *Reference `xml:"Owner,omitempty"`
+ Progress int `xml:"Progress,omitempty"`
+ Tasks *TasksInProgress `xml:"Tasks,omitempty"`
+ User *Reference `xml:"User,omitempty"`
+}
+
+// Type: CapacityWithUsageType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a capacity and usage of a given resource.
+// Since: 0.9
+type CapacityWithUsage struct {
+ Allocated int64 `xml:"Allocated,omitempty"`
+ Limit int64 `xml:"Limit,omitempty"`
+ Overhead int64 `xml:"Overhead,omitempty"`
+ Reserved int64 `xml:"Reserved,omitempty"`
+ Units string `xml:"Units"`
+ Used int64 `xml:"Used,omitempty"`
+}
+
+// Type: ComputeCapacityType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents vDC compute capacity.
+// Since: 0.9
+type ComputeCapacity struct {
+ CPU *CapacityWithUsage `xml:"Cpu"`
+ Memory *CapacityWithUsage `xml:"Memory"`
+}
+
+// Type: ReferenceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: A reference to a resource. Contains an href attribute and optional name and type attributes.
+// Since: 0.9
+type Reference struct {
+ HREF string `xml:"href,attr"`
+ ID string `xml:"id,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Name string `xml:"name,attr,omitempty"`
+}
+
+// Type: ResourceReferenceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a reference to a resource. Contains an href attribute, a resource status attribute, and optional name and type attributes.
+// Since: 0.9
+type ResourceReference struct {
+ HREF string `xml:"href,attr"`
+ ID string `xml:"id,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Name string `xml:"name,attr,omitempty"`
+ Status string `xml:"status,attr,omitempty"`
+}
+
+// Element: VdcStorageProfiles
+// Type: VdcStorageProfilesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for references to storage profiles associated with a vDC.
+// Since: 5.1
+type VdcStorageProfiles struct {
+ VdcStorageProfile []*Reference `xml:"VdcStorageProfile,omitempty"`
+}
+
+// Type: ResourceEntitiesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for references to ResourceEntity objects in this vDC.
+// Since: 0.9
+type ResourceEntities struct {
+ ResourceEntity []*ResourceReference `xml:"ResourceEntity,omitempty"`
+}
+
+// Type: AvailableNetworksType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for references to available organization vDC networks.
+// Since: 0.9
+type AvailableNetworks struct {
+ Network []*Reference `xml:"Network,omitempty"`
+}
+
+// Type: LinkType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Extends reference type by adding relation attribute. Defines a hyper-link with a relationship, hyper-link reference, and an optional MIME type.
+// Since: 0.9
+type Link struct {
+ HREF string `xml:"href,attr"`
+ ID string `xml:"id,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Name string `xml:"name,attr,omitempty"`
+ Rel string `xml:"rel,attr"`
+}
+
+// Type: OrgType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the user view of a vCloud Director organization.
+// Since: 0.9
+type Org struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ ID string `xml:"id,attr,omitempty"`
+ OperationKey string `xml:"operationKey,attr,omitempty"`
+ Name string `xml:"name,attr"`
+ Description string `xml:"Description,omitempty"`
+ FullName string `xml:"FullName"`
+ IsEnabled bool `xml:"IsEnabled,omitempty"`
+ Link []*Link `xml:"Link,omitempty"`
+ Tasks *TasksInProgress `xml:"Tasks,omitempty"`
+}
+
+// Type: CatalogItemType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Contains a reference to a VappTemplate or Media object and related metadata.
+// Since: 0.9
+type CatalogItem struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ ID string `xml:"id,attr,omitempty"`
+ OperationKey string `xml:"operationKey,attr,omitempty"`
+ Name string `xml:"name,attr"`
+ Size int64 `xml:"size,attr,omitempty"`
+ DateCreated string `xml:"DateCreated,omitempty"`
+ Description string `xml:"Description,omitempty"`
+ Entity *Entity `xml:"Entity"`
+ Link []*Link `xml:"Link,omitempty"`
+ Tasks *TasksInProgress `xml:"Tasks,omitempty"`
+ VersionNumber int64 `xml:"VersionNumber,omitempty"`
+}
+
+// Type: EntityType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Basic entity type in the vCloud object model. Includes a name, an optional description, and an optional list of links.
+// Since: 0.9
+type Entity struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ ID string `xml:"id,attr,omitempty"`
+ OperationKey string `xml:"operationKey,attr,omitempty"`
+ Name string `xml:"name,attr"`
+ Description string `xml:"Description,omitempty"`
+ Link []*Link `xml:"Link,omitempty"`
+ Tasks *TasksInProgress `xml:"Tasks,omitempty"`
+}
+
+// Type: CatalogItemsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for references to catalog items.
+// Since: 0.9
+type CatalogItems struct {
+ CatalogItem []*Reference `xml:"CatalogItem"`
+}
+
+// Type: CatalogType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the user view of a Catalog object.
+// Since: 0.9
+type Catalog struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ ID string `xml:"id,attr,omitempty"`
+ OperationKey string `xml:"operationKey,attr,omitempty"`
+ Name string `xml:"name,attr"`
+ CatalogItems []*CatalogItems `xml:"CatalogItems"`
+ DateCreated string `xml:"DateCreated"`
+ Description string `xml:"Description"`
+ IsPublished bool `xml:"IsPublished"`
+ Link []*Link `xml:"Link"`
+ Owner *Owner `xml:"Owner,omitempty"`
+ Tasks *TasksInProgress `xml:"Tasks,omitempty"`
+ VersionNumber int64 `xml:"VersionNumber"`
+}
+
+// Type: OwnerType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the owner of this entity.
+// Since: 1.5
+type Owner struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Link []*Link `xml:"Link,omitempty"`
+ User *Reference `xml:"User"`
+}
+
+// Type: ErrorType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: The standard error message type used in the vCloud REST API.
+// Since: 0.9
+type Error struct {
+ Message string `xml:"message,attr"`
+ MajorErrorCode int `xml:"majorErrorCode,attr"`
+ MinorErrorCode string `xml:"minorErrorCode,attr"`
+ VendorSpecificErrorCode string `xml:"vendorSpecificErrorCode,attr,omitempty"`
+ StackTrace string `xml:"stackTrace,attr,omitempty"`
+}
+
+// Type: FileType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a file to be transferred (uploaded or downloaded).
+// Since: 0.9
+type File struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ ID string `xml:"id,attr,omitempty"`
+ OperationKey string `xml:"operationKey,attr,omitempty"`
+ Name string `xml:"name,attr"`
+ Size int64 `xml:"size,attr,omitempty"`
+ BytesTransferred int64 `xml:"bytesTransferred,attr,omitempty"`
+ Checksum string `xml:"checksum,attr,omitempty"`
+ Description string `xml:"Description,omitempty"`
+ Link []*Link `xml:"Link,omitempty"`
+ Tasks *TasksInProgress `xml:"Tasks,omitempty"`
+}
+
+// Type: FilesListType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a list of files to be transferred (uploaded or downloaded).
+// Since: 0.9
+type FilesList struct {
+ File []*File `xml:"File"`
+}
+
+// Type: UndeployVAppParamsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Parameters to an undeploy vApp request.
+// Since: 0.9
+type UndeployVAppParams struct {
+ Xmlns string `xml:"xmlns,attr"`
+ UndeployPowerAction string `xml:"UndeployPowerAction,omitempty"`
+}
+
+// Type: VmCapabilitiesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// 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"`
+ Link []*Link `xml:"Link,omitempty"`
+ MemoryHotAddEnabled bool `xml:"MemoryHotAddEnabled,omitempty"`
+}
+
+// Type: VmsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a list of virtual machines.
+// Since: 5.1
+type VMs struct {
+ HREF string `xml:"href,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Link []*Link `xml:"Link,omitempty"`
+ VMReference []*Reference `xml:"VmReference,omitempty"`
+}
+
+/*
+ * Types that are completely valid (position, comment, coverage complete)
+ */
+
+// Type: ComposeVAppParamsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents vApp composition parameters.
+// Since: 0.9
+type ComposeVAppParams struct {
+ XMLName xml.Name `xml:"ComposeVAppParams"`
+ 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"` // 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: SourcedCompositionItemParamType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a vApp, vApp template or Vm to include in a composed vApp.
+// Since: 0.9
+type SourcedCompositionItemParam struct {
+ // Attributes
+ SourceDelete bool `xml:"sourceDelete,attr,omitempty"` // True if the source item should be deleted after composition is complete.
+ // Elements
+ Source *Reference `xml:"Source"` // Reference to a vApp, vApp template or virtual machine to include in the composition. Changing the name of the newly created VM by specifying name attribute is deprecated. Include VmGeneralParams element instead.
+ VMGeneralParams *VMGeneralParams `xml:"VmGeneralParams,omitempty"` // Specify name, description, and other properties of a VM during instantiation.
+ VAppScopedLocalID string `xml:"VAppScopedLocalId,omitempty"` // If Source references a Vm, this value provides a unique identifier for the Vm in the scope of the composed vApp.
+ InstantiationParams *InstantiationParams `xml:"InstantiationParams,omitempty"` // If Source references a Vm this can include any of the following OVF sections: VirtualHardwareSection OperatingSystemSection NetworkConnectionSection GuestCustomizationSection.
+ NetworkAssignment *NetworkAssignment `xml:"NetworkAssignment,omitempty"` // If Source references a Vm, this element maps a network name specified in the Vm to the network name of a vApp network defined in the composed vApp.
+ StorageProfile *Reference `xml:"StorageProfile,omitempty"` // If Source references a Vm, this element contains a reference to a storage profile to be used for the Vm. The specified storage profile must exist in the organization vDC that contains the composed vApp. If not specified, the default storage profile for the vDC is used.
+ LocalityParams *LocalityParams `xml:"LocalityParams,omitempty"` // Represents locality parameters. Locality parameters provide a hint that may help the placement engine optimize placement of a VM and an independent a Disk so that the VM can make efficient use of the disk.
+}
+
+// Type: LocalityParamsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents locality parameters. Locality parameters provide a hint that may help the placement engine optimize placement of a VM with respect to another VM or an independent disk.
+// Since: 5.1
+type LocalityParams struct {
+ // Elements
+ ResourceEntity *Reference `xml:"ResourceEntity,omitempty"` // Reference to a Disk, or a VM.
+}
+
+// Type: NetworkAssignmentType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Maps a network name specified in a Vm to the network name of a vApp network defined in the VApp that contains the Vm
+// Since: 0.9
+type NetworkAssignment struct {
+ // Attributes
+ InnerNetwork string `xml:"innerNetwork,attr"` // Name of the network as specified in the Vm.
+ ContainerNetwork string `xml:"containerNetwork,attr"` // Name of the vApp network to map to.
+}
+
+// Type: VmGeneralParamsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: A set of overrides to source VM properties to apply to target VM during copying.
+// Since: 5.6
+type VMGeneralParams struct {
+ // Elements
+ Name string `xml:"Name,omitempty"` // Name of VM
+ Description string `xml:"Description,omitempty"` // VM description
+ NeedsCustomization bool `xml:"NeedsCustomization,omitempty"` // True if this VM needs guest customization
+}
+
+// Type: VAppType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a vApp.
+// Since: 0.9
+type VApp struct {
+ // Attributes
+ HREF string `xml:"href,attr,omitempty"` // The URI of the entity.
+ Type string `xml:"type,attr,omitempty"` // The MIME type of the entity.
+ ID string `xml:"id,attr,omitempty"` // The entity identifier, expressed in URN format. The value of this attribute uniquely identifies the entity, persists for the life of the entity, and is never reused.
+ OperationKey string `xml:"operationKey,attr,omitempty"` // Optional unique identifier to support idempotent semantics for create and delete operations.
+ Name string `xml:"name,attr"` // The name of the entity.
+ Status int `xml:"status,attr,omitempty"` // Creation status of the resource entity.
+ 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 []*Link `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.
+ VAppParent *Reference `xml:"VAppParent,omitempty"` // Reserved. Unimplemented.
+ // TODO: OVF Sections to be implemented
+ // Section OVF_Section `xml:"Section"`
+ DateCreated string `xml:"DateCreated,omitempty"` // Creation date/time of the vApp.
+ Owner *Owner `xml:"Owner,omitempty"` // vApp owner.
+ InMaintenanceMode bool `xml:"InMaintenanceMode,omitempty"` // True if this vApp is in maintenance mode. Prevents users from changing vApp metadata.
+ Children *VAppChildren `xml:"Children,omitempty"` // Container for virtual machines included in this vApp.
+}
+
+// Type: VAppChildrenType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for virtual machines included in this vApp.
+// Since: 0.9
+type VAppChildren struct {
+ VM []*VM `xml:"Vm,omitempty"` // Rerpresents a virtual machine.
+}
+
+// Type: TasksInProgressType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: A list of queued, running, or recently completed tasks.
+// Since: 0.9
+type TasksInProgress struct {
+ // Elements
+ Task []*Task `xml:"Task"` // A task.
+}
+
+// Type: VAppTemplateChildrenType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for virtual machines included in this vApp template.
+// Since: 0.9
+type VAppTemplateChildren struct {
+ // Elements
+ VM []*VAppTemplate `xml:"Vm"` // Represents a virtual machine in this vApp template.
+}
+
+// Type: VAppTemplateType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a vApp template.
+// Since: 0.9
+type VAppTemplate struct {
+ // Attributes
+ HREF string `xml:"href,attr,omitempty"` // The URI of the entity.
+ Type string `xml:"type,attr,omitempty"` // The MIME type of the entity.
+ ID string `xml:"id,attr,omitempty"` // The entity identifier, expressed in URN format. The value of this attribute uniquely identifies the entity, persists for the life of the entity, and is never reused.
+ OperationKey string `xml:"operationKey,attr,omitempty"` // Optional unique identifier to support idempotent semantics for create and delete operations.
+ Name string `xml:"name,attr"` // The name of the entity.
+ Status int `xml:"status,attr,omitempty"` // Creation status of the resource entity.
+ 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 []*Link `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.
+ Owner *Owner `xml:"Owner,omitempty"` // vAppTemplate owner.
+ Children *VAppTemplateChildren `xml:"Children,omitempty"` // Container for virtual machines included in this vApp template.
+ VAppScopedLocalID string `xml:"VAppScopedLocalId"` // A unique identifier for the Vm in the scope of the vApp template.
+ DefaultStorageProfile string `xml:"DefaultStorageProfile,omitempty"` // The name of the storage profile to be used for this object. The named storage profile must exist in the organization vDC that contains the object. If not specified, the default storage profile for the vDC is used.
+ DateCreated string `xml:"DateCreated,omitempty"` // Creation date/time of the template.
+ // FIXME: Upstream bug? Missing NetworkConfigSection, LeaseSettingSection and
+ // CustomizationSection at least, NetworkConnectionSection is required when
+ // using ComposeVApp action in the context of a Children VM (still
+ // referenced by VAppTemplateType).
+ NetworkConfigSection *NetworkConfigSection `xml:"NetworkConfigSection,omitempty"`
+ NetworkConnectionSection *NetworkConnectionSection `xml:"NetworkConnectionSection,omitempty"`
+ LeaseSettingsSection *LeaseSettingsSection `xml:"LeaseSettingsSection,omitempty"`
+ CustomizationSection *CustomizationSection `xml:"CustomizationSection,omitempty"`
+ // OVF Section needs to be added
+ // Section Section `xml:"Section,omitempty"`
+}
+
+// Type: VmType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a virtual machine.
+// Since: 0.9
+type VM struct {
+ // Attributes
+ Ovf string `xml:"xmlns:ovf,attr,omitempty"`
+ Xsi string `xml:"xmlns:xsi,attr,omitempty"`
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+
+ HREF string `xml:"href,attr,omitempty"` // The URI of the entity.
+ Type string `xml:"type,attr,omitempty"` // The MIME type of the entity.
+ ID string `xml:"id,attr,omitempty"` // The entity identifier, expressed in URN format. The value of this attribute uniquely identifies the entity, persists for the life of the entity, and is never reused
+ OperationKey string `xml:"operationKey,attr,omitempty"` // Optional unique identifier to support idempotent semantics for create and delete operations.
+ Name string `xml:"name,attr"` // The name of the entity.
+ Status int `xml:"status,attr,omitempty"` // Creation status of the resource entity.
+ Deployed bool `xml:"deployed,attr,omitempty"` // True if the virtual machine is deployed.
+ 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 []*Link `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.
+ VAppParent *Reference `xml:"VAppParent,omitempty"` // Reserved. Unimplemented.
+ // TODO: OVF Sections to be implemented
+ // Section OVF_Section `xml:"Section,omitempty"
+ DateCreated string `xml:"DateCreated"` // Creation date/time of the vApp.
+
+ // FIXME: Upstream bug? Missing NetworkConnectionSection
+ NetworkConnectionSection *NetworkConnectionSection `xml:"NetworkConnectionSection,omitempty"`
+
+ VAppScopedLocalID string `xml:"VAppScopedLocalId,omitempty"` // A unique identifier for the virtual machine in the scope of the vApp.
+
+ // TODO: OVF Sections to be implemented
+ // Environment OVF_Environment `xml:"Environment,omitempty"
+
+ VMCapabilities *VMCapabilities `xml:"VmCapabilities,omitempty"` // Allows you to specify certain capabilities of this virtual machine.
+ StorageProfile *Reference `xml:"StorageProfile,omitempty"` // A reference to a storage profile to be used for this object. The specified storage profile must exist in the organization vDC that contains the object. If not specified, the default storage profile for the vDC is used.
+}
+
+// Horrible kludge to process OVF, needs to be fixed with proper types.
+type OVFItem struct {
+ XMLName xml.Name `xml:"vcloud:Item"`
+ XmlnsRasd string `xml:"xmlns:rasd,attr"`
+ XmlnsVCloud string `xml:"xmlns:vcloud,attr"`
+ XmlnsXsi string `xml:"xmlns:xsi,attr"`
+ VCloudHREF string `xml:"vcloud:href,attr"`
+ VCloudType string `xml:"vcloud:type,attr"`
+ AllocationUnits string `xml:"rasd:AllocationUnits"`
+ Description string `xml:"rasd:Description"`
+ ElementName string `xml:"rasd:ElementName"`
+ InstanceID int `xml:"rasd:InstanceID"`
+ Reservation int `xml:"rasd:Reservation"`
+ ResourceType int `xml:"rasd:ResourceType"`
+ VirtualQuantity int `xml:"rasd:VirtualQuantity"`
+ Weight int `xml:"rasd:Weight"`
+ Link *Link `xml:"vcloud:Link"`
+}
+
+// Type: DeployVAppParamsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Parameters to a deploy vApp request.
+// Since: 0.9
+type DeployVAppParams struct {
+ XMLName xml.Name `xml:"DeployVAppParams"`
+ Xmlns string `xml:"xmlns,attr"`
+ // Attributes
+ PowerOn bool `xml:"powerOn,attr"` // Used to specify whether to power on vapp on deployment, if not set default value is true.
+ DeploymentLeaseSeconds int `xml:"deploymentLeaseSeconds,attr,omitempty"` // Lease in seconds for deployment. A value of 0 is replaced by the organization default deploymentLeaseSeconds value.
+ ForceCustomization bool `xml:"forceCustomization,attr,omitempty"` // Used to specify whether to force customization on deployment, if not set default value is false
+}
+
+// Type: GuestCustomizationSectionType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a guest customization settings.
+// Since: 1.0
+type GuestCustomizationSection struct {
+ // Extends OVF Section_Type
+ // Attributes
+ Ovf string `xml:"xmlns:ovf,attr,omitempty"`
+ Xsi string `xml:"xmlns:xsi,attr,omitempty"`
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+
+ HREF string `xml:"href,attr,omitempty"` // A reference to the section in URL format.
+ Type string `xml:"type,attr,omitempty"` // The MIME type of the section.
+ // 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 xxx; where xxxx is the character number.
+ ComputerName string `xml:"ComputerName,omitempty"` // Computer name to assign to this virtual machine.
+ Link []*Link `xml:"Link,omitempty"` // A link to an operation on this section.
+}
+
+// Type: InstantiateVAppTemplateParamsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents vApp template instantiation parameters.
+// Since: 0.9
+type InstantiateVAppTemplateParams struct {
+ XMLName xml.Name `xml:"InstantiateVAppTemplateParams"`
+ 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.
+ Source *Reference `xml:"Source"` // A reference to a source object such as a vApp or vApp template.
+ IsSourceDelete bool `xml:"IsSourceDelete,omitempty"` // Set to true to delete the source object after the operation completes.
+ SourcedItem *SourcedCompositionItemParam `xml:"SourcedItem,omitempty"` // Composition item. One of: vApp vAppTemplate Vm.
+ 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.
+}
+
+// Element: EdgeGateway
+// Type: GatewayType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a gateway.
+// Since: 5.1
+type EdgeGateway struct {
+ // Attributes
+ HREF string `xml:"href,attr,omitempty"` // The URI of the entity.
+ Type string `xml:"type,attr,omitempty"` // The MIME type of the entity.
+ ID string `xml:"id,attr,omitempty"` // The entity identifier, expressed in URN format. The value of this attribute uniquely identifies the entity, persists for the life of the entity, and is never reused
+ OperationKey string `xml:"operationKey,attr,omitempty"` // Optional unique identifier to support idempotent semantics for create and delete operations.
+ 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 []*Link `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.
+}
+
+// Type: GatewayConfigurationType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Gateway Configuration.
+// Since: 5.1
+type GatewayConfiguration struct {
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+ // Elements
+ BackwardCompatibilityMode bool `xml:"BackwardCompatibilityMode,omitempty"` // Compatibilty mode. Default is false. If set to true, will allow users to write firewall rules in the old 1.5 format. The new format does not require to use direction in firewall rules. Also, for firewall rules to allow NAT traffic the filter is applied on the original IP addresses. Once set to true cannot be reverted back to false.
+ GatewayBackingConfig string `xml:"GatewayBackingConfig"` // Configuration of the vShield edge VM for this gateway. One of: compact, full.
+ GatewayInterfaces *GatewayInterfaces `xml:"GatewayInterfaces"` // List of Gateway interfaces.
+ EdgeGatewayServiceConfiguration *GatewayFeatures `xml:"EdgeGatewayServiceConfiguration,omitempty"` // Represents Gateway Features.
+ HaEnabled bool `xml:"HaEnabled,omitempty"` // True if this gateway is highly available. (Requires two vShield edge VMs.)
+ UseDefaultRouteForDNSRelay bool `xml:"UseDefaultRouteForDnsRelay,omitempty"` // True if the default gateway on the external network selected for default route should be used as the DNS relay.
+}
+
+// Type: GatewayInterfacesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: A list of Gateway Interfaces.
+// Since: 5.1
+type GatewayInterfaces struct {
+ GatewayInterface []*GatewayInterface `xml:"GatewayInterface"` // Gateway Interface.
+}
+
+// Type: GatewayInterfaceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Gateway Interface configuration.
+// Since: 5.1
+type GatewayInterface struct {
+ Name string `xml:"Name,omitempty"` // Internally generated name for the Gateway Interface.
+ DisplayName string `xml:"DisplayName,omitempty"` // Gateway Interface display name.
+ Network *Reference `xml:"Network"` // A reference to the network connected to the gateway interface.
+ InterfaceType string `xml:"InterfaceType"` // The type of interface: One of: Uplink, Internal
+ SubnetParticipation *SubnetParticipation `xml:"SubnetParticipation,omitempty"` // IP allocation per subnet.
+ ApplyRateLimit bool `xml:"ApplyRateLimit,omitempty"` // True if rate limiting is applied on this interface.
+ InRateLimit float64 `xml:"InRateLimit,omitempty"` // Incoming rate limit expressed as Gbps.
+ OutRateLimit float64 `xml:"OutRateLimit,omitempty"` // Outgoing rate limit expressed as Gbps.
+ UseForDefaultRoute bool `xml:"UseForDefaultRoute,omitempty"` // True if this network is default route for the gateway.
+}
+
+// Type: SubnetParticipationType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Allows to chose which subnets a gateway can be part of
+// Since: 5.1
+type SubnetParticipation struct {
+ Gateway string `xml:"Gateway"` // Gateway for subnet
+ IPAddress string `xml:"IpAddress,omitempty"` // Ip Address to be assigned. Keep empty or ommit element for auto assignment
+ IPRanges *IPRanges `xml:"IpRanges,omitempty"` // Range of IP addresses available for external interfaces.
+ Netmask string `xml:"Netmask"` // Nestmask for the subnet
+}
+
+// Element: EdgeGatewayServiceConfiguration
+// Type: GatewayFeaturesType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents edge gateway services.
+// Since: 5.1
+type GatewayFeatures struct {
+ XMLName xml.Name
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+ FirewallService *FirewallService `xml:"FirewallService,omitempty"` // Substitute for NetworkService. Firewall service settings
+ NatService *NatService `xml:"NatService,omitempty"` // Substitute for NetworkService. NAT service settings
+ GatewayDhcpService *GatewayDhcpService `xml:"GatewayDhcpService,omitempty"` // Substitute for NetworkService. Gateway DHCP service settings
+ GatewayIpsecVpnService *GatewayIpsecVpnService `xml:"GatewayIpsecVpnService,omitempty"` // Substitute for NetworkService. Gateway Ipsec VPN service settings
+ LoadBalancerService *LoadBalancerService `xml:"LoadBalancerService,omitempty"` // Substitute for NetworkService. Load Balancer service settings
+ StaticRoutingService *StaticRoutingService `xml:"StaticRoutingService,omitempty"` // Substitute for NetworkService. Static Routing service settings
+}
+
+// Type: StaticRoutingServiceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents Static Routing network service.
+// Since: 1.5
+type StaticRoutingService struct {
+ IsEnabled bool `xml:"IsEnabled"` // Enable or disable the service using this flag
+ StaticRoute *StaticRoute `xml:"StaticRoute,omitempty"` // Details of each Static Route.
+}
+
+// Type: StaticRouteType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description:
+// Since:
+type StaticRoute struct {
+ Name string `xml:"Name"` // Name for the static route.
+ Network string `xml:"Network"` // Network specification in CIDR.
+ NextHopIp string `xml:"NextHopIp"` // IP Address of Next Hop router/gateway.
+ Interface string `xml:"Interface,omitempty"` // Interface to use for static routing. Internal and External are the supported values.
+ GatewayInterface *Reference `xml:"GatewayInterface,omitempty"` // Gateway interface to which static route is bound.
+}
+
+// Type: LoadBalancerServiceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents gateway load balancer service.
+// Since: 5.1
+type LoadBalancerService struct {
+ IsEnabled bool `xml:"IsEnabled"` // Enable or disable the service using this flag
+ Pool *LoadBalancerPool `xml:"Pool,omitempty"` // List of load balancer pools.
+ VirtualServer *LoadBalancerVirtualServer `xml:"VirtualServer,omitempty"` // List of load balancer virtual servers.
+}
+
+// Type: LoadBalancerPoolType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a load balancer pool.
+// Since: 5.1
+type LoadBalancerPool struct {
+ ID string `xml:"Id,omitempty"` // Load balancer pool id.
+ Name string `xml:"Name"` // Load balancer pool name.
+ Description string `xml:"Description,omitempty"` // Load balancer pool description.
+ ServicePort *LBPoolServicePort `xml:"ServicePort"` // Load balancer pool service port.
+ Member *LBPoolMember `xml:"Member"` // Load balancer pool member.
+ Operational bool `xml:"Operational,omitempty"` // True if the load balancer pool is operational.
+ ErrorDetails string `xml:"ErrorDetails,omitempty"` // Error details for this pool.
+}
+
+// Type: LBPoolServicePortType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a service port in a load balancer pool.
+// Since: 5.1
+type LBPoolServicePort struct {
+ IsEnabled bool `xml:"IsEnabled,omitempty"` // True if this service port is enabled.
+ Protocol string `xml:"Protocol"` // Load balancer protocol type. One of: HTTP, HTTPS, TCP.
+ Algorithm string `xml:"Algorithm"` // Load Balancer algorithm type. One of: IP_HASH, ROUND_ROBIN, URI, LEAST_CONN.
+ Port string `xml:"Port"` // Port for this service profile.
+ HealthCheckPort string `xml:"HealthCheckPort,omitempty"` // Health check port for this profile.
+ HealthCheck *LBPoolHealthCheck `xml:"HealthCheck,omitempty"` // Health check list.
+}
+
+// Type: LBPoolHealthCheckType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a service port health check list.
+// Since: 5.1
+type LBPoolHealthCheck struct {
+ Mode string `xml:"Mode"` // Load balancer service port health check mode. One of: TCP, HTTP, SSL.
+ Uri string `xml:"Uri,omitempty"` // Load balancer service port health check URI.
+ HealthThreshold string `xml:"HealthThreshold,omitempty"` // Health threshold for this service port.
+ UnhealthThreshold string `xml:"UnhealthThreshold,omitempty"` // Unhealth check port for this profile.
+ Interval string `xml:"Interval,omitempty"` // Interval between health checks.
+ Timeout string `xml:"Timeout,omitempty"` // Health check timeout.
+}
+
+// Type: LBPoolMemberType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a member in a load balancer pool.
+// Since: 5.1
+type LBPoolMember struct {
+ IPAddress string `xml:"IpAddress"` // Ip Address for load balancer member.
+ Weight string `xml:"Weight"` // Weight of this member.
+ ServicePort *LBPoolServicePort `xml:"ServicePort,omitempty"` // Load balancer member service port.
+}
+
+// Type: LoadBalancerVirtualServerType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a load balancer virtual server.
+// Since: 5.1
+type LoadBalancerVirtualServer struct {
+ IsEnabled bool `xml:"IsEnabled,omitempty"` // True if this virtual server is enabled.
+ Name string `xml:"Name"` // Load balancer virtual server name.
+ Description string `xml:"Description,omitempty"` // Load balancer virtual server description.
+ Interface *Reference `xml:"Interface"` // Gateway Interface to which Load Balancer Virtual Server is bound.
+ IPAddress string `xml:"IpAddress"` // Load balancer virtual server Ip Address.
+ ServiceProfile *LBVirtualServerServiceProfile `xml:"ServiceProfile"` // Load balancer virtual server service profiles.
+ Logging bool `xml:"Logging,omitempty"` // Enable logging for this virtual server.
+ Pool string `xml:"Pool"` // Name of Load balancer pool associated with this virtual server.
+ LoadBalancerTemplates *VendorTemplate `xml:"LoadBalancerTemplates,omitempty"` // Service template related attributes.
+}
+
+// Type: LBVirtualServerServiceProfileType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents service profile for a load balancing virtual server.
+// Since: 5.1
+type LBVirtualServerServiceProfile struct {
+ IsEnabled bool `xml:"IsEnabled,omitempty"` // True if this service profile is enabled.
+ Protocol string `xml:"Protocol"` // Load balancer Protocol type. One of: HTTP, HTTPS, TCP.
+ Port string `xml:"Port"` // Port for this service profile.
+ Persistence *LBPersistence `xml:"Persistence,omitempty"` // Persistence type for service profile.
+}
+
+// Type: LBPersistenceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents persistence type for a load balancer service profile.
+// Since: 5.1
+type LBPersistence struct {
+ Method string `xml:"Method"` // Persistence method. One of: COOKIE, SSL_SESSION_ID.
+ CookieName string `xml:"CookieName,omitempty"` // Cookie name when persistence method is COOKIE.
+ CookieMode string `xml:"CookieMode,omitempty"` // Cookie Mode. One of: INSERT, PREFIX, APP.
+}
+
+// Type: VendorTemplateType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Information about a vendor service template. This is optional.
+// Since: 5.1
+type VendorTemplate struct {
+ Name string `xml:"Name"` // Name of the vendor template. This is required.
+ ID string `xml:"Id"` // ID of the vendor template. This is required.
+}
+
+// Type: GatewayIpsecVpnServiceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents gateway IPsec VPN service.
+// Since: 5.1
+type GatewayIpsecVpnService struct {
+ IsEnabled bool `xml:"IsEnabled"` // Enable or disable the service using this flag
+ Endpoint *GatewayIpsecVpnEndpoint `xml:"Endpoint,omitempty"` // List of IPSec VPN Service Endpoints.
+ Tunnel []*GatewayIpsecVpnTunnel `xml:"Tunnel"` // List of IPSec VPN tunnels.
+}
+
+// Type: GatewayIpsecVpnEndpointType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents an IPSec VPN endpoint.
+// Since: 5.1
+type GatewayIpsecVpnEndpoint struct {
+ Network *Reference `xml:"Network"` // External network reference.
+ PublicIP string `xml:"PublicIp,omitempty"` // Public IP for IPSec endpoint.
+}
+
+// Type: GatewayIpsecVpnTunnelType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents an IPSec VPN tunnel.
+// Since: 5.1
+type GatewayIpsecVpnTunnel struct {
+ Name string `xml:"Name"` // The name of the tunnel.
+ 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.
+ 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.
+ 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
+ Mtu int `xml:"Mtu"` // MTU for the tunnel.
+ IsEnabled bool `xml:"IsEnabled,omitempty"` // True if the tunnel is enabled.
+ IsOperational bool `xml:"IsOperational,omitempty"` // True if the tunnel is operational.
+ ErrorDetails string `xml:"ErrorDetails,omitempty"` // Error details of the tunnel.
+}
+
+type IpsecVpnThirdPartyPeer struct {
+ PeerID string `xml:"PeerId,omitempty"` // Id for the peer end point
+}
+
+// Type: IpsecVpnSubnetType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents subnet details.
+// Since: 5.1
+type IpsecVpnSubnet struct {
+ Name string `xml:"Name"` // Gateway Name.
+ Gateway string `xml:"Gateway"` // Subnet Gateway.
+ Netmask string `xml:"Netmask"` // Subnet Netmask.
+}
+
+// Type: GatewayDhcpServiceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents Gateway DHCP service.
+// Since: 5.1
+type GatewayDhcpService struct {
+ IsEnabled bool `xml:"IsEnabled,omitempty"` // Enable or disable the service using this flag
+ Pool *DhcpPoolService `xml:"Pool,omitempty"` // A DHCP pool.
+}
+
+// Type: DhcpPoolServiceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents DHCP pool service.
+// Since: 5.1
+type DhcpPoolService struct {
+ IsEnabled bool `xml:"IsEnabled,omitempty"` // True if this DHCP Pool is enabled.
+ Network *Reference `xml:"Network"` // Org vDC network to which the DHCP range is applicable.
+ DefaultLeaseTime int `xml:"DefaultLeaseTime,omitempty"` // Default lease period for DHCP range.
+ MaxLeaseTime int `xml:"MaxLeaseTime"` // Maximum lease period for DHCP range.
+ LowIPAddress string `xml:"LowIpAddress"` // Low IP address in DHCP range.
+ HighIPAddress string `xml:"HighIpAddress"` // High IP address in DHCP range.
+}
+
+// Type: VmSelectionType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents details of an vm+nic+iptype selection.
+// Since: 5.1
+type VMSelection struct {
+ VAppScopedVMID string `xml:"VAppScopedVmId"` // VAppScopedVmId of VM to which this rule applies.
+ VMNicID int `xml:"VmNicId"` // VM NIC ID to which this rule applies.
+ IPType string `xml:"IpType"` // The value can be one of:- assigned: assigned internal IP be automatically choosen. NAT: NATed external IP will be automatically choosen.
+}
+
+// Type: FirewallRuleType/Protocols
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description:
+// Since:
+type FirewallRuleProtocols struct {
+ Icmp bool `xml:"Icmp,omitempty"` // True if the rule applies to the ICMP protocol.
+ Any bool `xml:"Any,omitempty"` // True if the rule applies to any protocol.
+ Tcp bool `xml:"Tcp,omitempty"` // True if the rule applies to the TCP protocol.
+ Udp bool `xml:"Udp,omitempty"` // True if the rule applies to the UDP protocol.
+ // FIXME: this is supposed to extend protocol support to all the VSM supported protocols
+ // Other string `xml:"Other,omitempty"` // Any other protocol supported by vShield Manager
+}
+
+// Type: FirewallRuleType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a firewall rule.
+// Since: 0.9
+type FirewallRule struct {
+ ID string `xml:"Id,omitempty"` // Firewall rule identifier.
+ IsEnabled bool `xml:"IsEnabled"` // Used to enable or disable the firewall rule. Default value is true.
+ MatchOnTranslate bool `xml:"MatchOnTranslate"` // For DNATed traffic, match the firewall rules only after the destination IP is translated.
+ Description string `xml:"Description,omitempty"` // A description of the rule.
+ Policy string `xml:"Policy,omitempty"` // One of: drop (drop packets that match the rule), allow (allow packets that match the rule to pass through the firewall)
+ Protocols *FirewallRuleProtocols `xml:"Protocols,omitempty"` // Specify the protocols to which the rule should be applied.
+ IcmpSubType string `xml:"IcmpSubType,omitempty"` // ICMP subtype. One of: address-mask-request, address-mask-reply, destination-unreachable, echo-request, echo-reply, parameter-problem, redirect, router-advertisement, router-solicitation, source-quench, time-exceeded, timestamp-request, timestamp-reply, any.
+ Port int `xml:"Port,omitempty"` // The port to which this rule applies. A value of -1 matches any port.
+ DestinationPortRange string `xml:"DestinationPortRange,omitempty"` // Destination port range to which this rule applies.
+ DestinationIP string `xml:"DestinationIp,omitempty"` // Destination IP address to which the rule applies. A value of Any matches any IP address.
+ DestinationVM *VMSelection `xml:"DestinationVm,omitempty"` // Details of the destination VM
+ SourcePort int `xml:"SourcePort,omitempty"` // Destination port to which this rule applies. A value of -1 matches any port.
+ SourcePortRange string `xml:"SourcePortRange,omitempty"` // Source port range to which this rule applies.
+ SourceIP string `xml:"SourceIp,omitempty"` // Source IP address to which the rule applies. A value of Any matches any IP address.
+ SourceVM *VMSelection `xml:"SourceVm,omitempty"` // Details of the source Vm
+ Direction string `xml:"Direction,omitempty"` // Direction of traffic to which rule applies. One of: in (rule applies to incoming traffic. This is the default value), out (rule applies to outgoing traffic).
+ EnableLogging bool `xml:"EnableLogging"` // Used to enable or disable firewall rule logging. Default value is false.
+}
+
+// Type: FirewallServiceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a network firewall service.
+// Since:
+type FirewallService struct {
+ IsEnabled bool `xml:"IsEnabled"` // Enable or disable the service using this flag
+ DefaultAction string `xml:"DefaultAction,omitempty"` // Default action of the firewall. One of: drop (Default. Drop packets that match the rule.), allow (Allow packets that match the rule to pass through the firewall)
+ LogDefaultAction bool `xml:"LogDefaultAction"` // Flag to enable logging for default action. Default value is false.
+ FirewallRule []*FirewallRule `xml:"FirewallRule,omitempty"` // A firewall rule.
+}
+
+// Type: NatServiceType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a NAT network service.
+// Since:
+type NatService struct {
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+ // Elements
+ IsEnabled bool `xml:"IsEnabled"` // Enable or disable the service using this flag
+ NatType string `xml:"NatType,omitempty"` // One of: ipTranslation (use IP translation), portForwarding (use port forwarding)
+ Policy string `xml:"Policy,omitempty"` // One of: allowTraffic (Allow all traffic), allowTrafficIn (Allow inbound traffic only)
+ NatRule []*NatRule `xml:"NatRule,omitempty"` // A NAT rule.
+ ExternalIP string `xml:"ExternalIp,omitempty"` // External IP address for rule.
+}
+
+// Type: NatRuleType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents a NAT rule.
+// Since: 0.9
+type NatRule struct {
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+ // Elements
+ Description string `xml:"Description,omitempty"` // A description of the rule.
+ RuleType string `xml:"RuleType,omitempty"` // Type of NAT rule. One of: SNAT (source NAT), DNAT (destination NAT)
+ IsEnabled bool `xml:"IsEnabled"` // Used to enable or disable the firewall rule. Default value is true.
+ ID string `xml:"Id,omitempty"` // Firewall rule identifier.
+ GatewayNatRule *GatewayNatRule `xml:"GatewayNatRule,omitempty"` // Defines SNAT and DNAT types.
+ OneToOneBasicRule *NatOneToOneBasicRule `xml:"OneToOneBasicRule,omitempty"` // Maps one internal IP address to one external IP address.
+ OneToOneVMRule *NatOneToOneVMRule `xml:"OneToOneVmRule,omitempty"` // Maps one VM NIC to one external IP addresses.
+ PortForwardingRule *NatPortForwardingRule `xml:"PortForwardingRule,omitempty"` // Port forwarding internal to external IP addresses.
+ VMRule *NatVMRule `xml:"VmRule,omitempty"` // Port forwarding VM NIC to external IP addresses.
+}
+
+// Type: GatewayNatRuleType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the SNAT and DNAT rules.
+// Since: 5.1
+type GatewayNatRule struct {
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+ // Elements
+ Interface *Reference `xml:"Interface,omitempty"` // Interface to which rule is applied.
+ OriginalIP string `xml:"OriginalIp"` // Original IP for rule.
+ OriginalPort string `xml:"OriginalPort,omitempty"` // Original port for rule.
+ TranslatedIP string `xml:"TranslatedIp"` // Translated IP for rule.
+ TranslatedPort string `xml:"TranslatedPort,omitempty"` // Translated port for rule.
+ Protocol string `xml:"Protocol,omitempty"` // Protocol for rule.
+ IcmpSubType string `xml:"IcmpSubType,omitempty"` // ICMP subtype. One of: address-mask-request, address-mask-reply, destination-unreachable, echo-request, echo-reply, parameter-problem, redirect, router-advertisement, router-solicitation, source-quench, time-exceeded, timestamp-request, timestamp-reply, any.
+}
+
+// Type: NatOneToOneBasicRuleType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the NAT basic rule for one to one mapping of internal and external IP addresses from a network.
+// Since: 0.9
+type NatOneToOneBasicRule struct {
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+ // Elements
+ MappingMode string `xml:"MappingMode"` // One of: automatic (map IP addresses automatically), manual (map IP addresses manually using ExternalIpAddress and InternalIpAddress)
+ ExternalIPAddress string `xml:"ExternalIpAddress"` // External IP address to map.
+ InternalIPAddress string `xml:"InternalIpAddress"` // Internal IP address to map.
+}
+
+// Type: NatOneToOneVmRuleType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the NAT rule for one to one mapping of VM NIC and external IP addresses from a network.
+// Since: 0.9
+type NatOneToOneVMRule struct {
+ Xmlns string `xml:"xmlns,attr,omitempty"`
+ // Elements
+ MappingMode string `xml:"MappingMode"` // Mapping mode.
+ ExternalIPAddress string `xml:"ExternalIpAddress"` // External IP address to map.
+ VAppScopedVMID string `xml:"VAppScopedVmId"` // VAppScopedVmId of VM to which this rule applies.
+ VMNicID int `xml:"VmNicId"` // VM NIC ID to which this rule applies.
+}
+
+// Type: NatPortForwardingRuleType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the NAT rule for port forwarding between internal IP/port and external IP/port.
+// Since: 0.9
+type NatPortForwardingRule struct {
+ ExternalIPAddress string `xml:"ExternalIpAddress"` // External IP address to map.
+ ExternalPort int `xml:"ExternalPort"` // External port to forward to.
+ InternalIPAddress string `xml:"InternalIpAddress"` // Internal IP address to map.
+ InternalPort int `xml:"InternalPort"` // Internal port to forward to.
+ Protocol string `xml:"Protocol,omitempty"` // Protocol to forward. One of: TCP (forward TCP packets), UDP (forward UDP packets), TCP_UDP (forward TCP and UDP packets).
+}
+
+// Type: NatVmRuleType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Represents the NAT rule for port forwarding between VM NIC/port and external IP/port.
+// Since: 0.9
+type NatVMRule struct {
+ ExternalIPAddress string `xml:"ExternalIpAddress,omitempty"` // External IP address to map.
+ ExternalPort int `xml:"ExternalPort"` // External port to forward to.
+ VAppScopedVMID string `xml:"VAppScopedVmId"` // VAppScopedVmId of VM to which this rule applies.
+ VMNicID int `xml:"VmNicId"` // VM NIC ID to which this rule applies.
+ InternalPort int `xml:"InternalPort"` // Internal port to forward to.
+ Protocol string `xml:"Protocol,omitempty"` // Protocol to forward. One of: TCP (forward TCP packets), UDP (forward UDP packets), TCP_UDP (forward TCP and UDP packets).
+}
+
+// Type: QueryResultRecordsType
+// Namespace: http://www.vmware.com/vcloud/v1.5
+// Description: Container for query results in records format.
+// Since: 1.5
+type QueryResultEdgeGatewayRecordsType struct {
+ // Attributes
+ HREF string `xml:"href,attr,omitempty"` // The URI of the entity.
+ Type string `xml:"type,attr,omitempty"` // The MIME type of the entity.
+ Name string `xml:"name,attr,omitempty"` // The name of the entity.
+ Page int `xml:"page,attr,omitempty"` // Page of the result set that this container holds. The first page is page number 1.
+ 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 []*Link `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object.
+ EdgeGatewayRecord *QueryResultEdgeGatewayRecordType `xml:"EdgeGatewayRecord"` // A record representing a query result.
+}
+
+type QueryResultEdgeGatewayRecordType struct {
+ // Attributes
+ HREF string `xml:"href,attr,omitempty"` // The URI of the entity.
+ Type string `xml:"type,attr,omitempty"` // The MIME type of the entity.
+ Name string `xml:"name,attr,omitempty"` // EdgeGateway name.
+ Vdc string `xml:"vdc,attr,omitempty"` // VDC Reference or ID
+ NumberOfExtNetworks int `xml:"numberOfExtNetworks,attr,omitempty"` // Number of external networks connected to the edgeGateway. Yes Yes
+ NumberOfOrgNetworks int `xml:"numberOfOrgNetworks,attr,omitempty"` // Number of org VDC networks connected to the edgeGateway Yes Yes
+ IsBusy bool `xml:"isBusy,attr"` // True if this Edge Gateway is busy. Yes Yes
+ GatewayStatus string `xml:"gatewayStatus,attr,omitempty"` //
+ HaStatus string `xml:"haStatus,attr,omitempty"` // High Availability Status of the edgeGateway Yes Yes
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/vapp.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/vapp.go
new file mode 100644
index 0000000000..d87f1e4b08
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/vapp.go
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "bytes"
+ "encoding/xml"
+ "fmt"
+ "net/url"
+ "os"
+ "strconv"
+
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type VApp struct {
+ VApp *types.VApp
+ c *Client
+}
+
+func NewVApp(c *Client) *VApp {
+ return &VApp{
+ VApp: new(types.VApp),
+ c: c,
+ }
+}
+
+func (v *VApp) Refresh() error {
+
+ if v.VApp.HREF == "" {
+ return fmt.Errorf("cannot refresh, Object is empty")
+ }
+
+ u, _ := url.ParseRequestURI(v.VApp.HREF)
+
+ req := v.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return fmt.Errorf("error retrieving task: %s", err)
+ }
+
+ // Empty struct before a new unmarshal, otherwise we end up with duplicate
+ // elements in slices.
+ v.VApp = &types.VApp{}
+
+ if err = decodeBody(resp, v.VApp); err != nil {
+ return fmt.Errorf("error decoding task response: %s", err)
+ }
+
+ // The request was successful
+ return nil
+}
+
+func (v *VApp) ComposeVApp(orgvdcnetwork OrgVDCNetwork, vapptemplate VAppTemplate, name string, description string) (Task, error) {
+
+ if vapptemplate.VAppTemplate.Children == nil || orgvdcnetwork.OrgVDCNetwork == nil {
+ return Task{}, fmt.Errorf("can't compose a new vApp, objects passed are not valid")
+ }
+
+ // Build request XML
+ 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,
+ Description: description,
+ InstantiationParams: &types.InstantiationParams{
+ NetworkConfigSection: &types.NetworkConfigSection{
+ Info: "Configuration parameters for logical networks",
+ NetworkConfig: &types.VAppNetworkConfiguration{
+ NetworkName: orgvdcnetwork.OrgVDCNetwork.Name,
+ Configuration: &types.NetworkConfiguration{
+ FenceMode: "bridged",
+ ParentNetwork: &types.Reference{
+ HREF: orgvdcnetwork.OrgVDCNetwork.HREF,
+ Name: orgvdcnetwork.OrgVDCNetwork.Name,
+ Type: orgvdcnetwork.OrgVDCNetwork.Type,
+ },
+ },
+ },
+ },
+ },
+ SourcedItem: &types.SourcedCompositionItemParam{
+ Source: &types.Reference{
+ HREF: vapptemplate.VAppTemplate.Children.VM[0].HREF,
+ Name: vapptemplate.VAppTemplate.Children.VM[0].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, err := xml.MarshalIndent(vcomp, " ", " ")
+ if err != nil {
+ return Task{}, 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 Task{}, fmt.Errorf("error instantiating a new vApp: %s", err)
+ }
+
+ if err = decodeBody(resp, v.VApp); err != nil {
+ return Task{}, fmt.Errorf("error decoding vApp response: %s", err)
+ }
+
+ task := NewTask(v.c)
+ task.Task = v.VApp.Tasks.Task[0]
+
+ // The request was successful
+ return *task, nil
+
+}
+
+func (v *VApp) PowerOn() (Task, error) {
+
+ s, _ := url.ParseRequestURI(v.VApp.HREF)
+ s.Path += "/power/action/powerOn"
+
+ req := v.c.NewRequest(map[string]string{}, "POST", *s, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error powering on vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) PowerOff() (Task, error) {
+
+ s, _ := url.ParseRequestURI(v.VApp.HREF)
+ s.Path += "/power/action/powerOff"
+
+ req := v.c.NewRequest(map[string]string{}, "POST", *s, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error powering off vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) Reboot() (Task, error) {
+
+ s, _ := url.ParseRequestURI(v.VApp.HREF)
+ s.Path += "/power/action/reboot"
+
+ req := v.c.NewRequest(map[string]string{}, "POST", *s, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error rebooting vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) Reset() (Task, error) {
+
+ s, _ := url.ParseRequestURI(v.VApp.HREF)
+ s.Path += "/power/action/reset"
+
+ req := v.c.NewRequest(map[string]string{}, "POST", *s, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error resetting vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) Suspend() (Task, error) {
+
+ s, _ := url.ParseRequestURI(v.VApp.HREF)
+ s.Path += "/power/action/suspend"
+
+ req := v.c.NewRequest(map[string]string{}, "POST", *s, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error suspending vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) Shutdown() (Task, error) {
+
+ s, _ := url.ParseRequestURI(v.VApp.HREF)
+ s.Path += "/power/action/shutdown"
+
+ req := v.c.NewRequest(map[string]string{}, "POST", *s, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error shutting down vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) Undeploy() (Task, error) {
+
+ vu := &types.UndeployVAppParams{
+ Xmlns: "http://www.vmware.com/vcloud/v1.5",
+ UndeployPowerAction: "powerOff",
+ }
+
+ output, err := xml.MarshalIndent(vu, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", 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, _ := url.ParseRequestURI(v.VApp.HREF)
+ s.Path += "/action/undeploy"
+
+ req := v.c.NewRequest(map[string]string{}, "POST", *s, b)
+
+ req.Header.Add("Content-Type", "application/vnd.vmware.vcloud.undeployVAppParams+xml")
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error undeploy vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) Deploy() (Task, error) {
+
+ vu := &types.DeployVAppParams{
+ Xmlns: "http://www.vmware.com/vcloud/v1.5",
+ PowerOn: false,
+ }
+
+ output, err := xml.MarshalIndent(vu, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", 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, _ := url.ParseRequestURI(v.VApp.HREF)
+ s.Path += "/action/deploy"
+
+ req := v.c.NewRequest(map[string]string{}, "POST", *s, b)
+
+ req.Header.Add("Content-Type", "application/vnd.vmware.vcloud.deployVAppParams+xml")
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error undeploy vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) Delete() (Task, error) {
+
+ s, _ := url.ParseRequestURI(v.VApp.HREF)
+
+ req := v.c.NewRequest(map[string]string{}, "DELETE", *s, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error deleting vApp: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) RunCustomizationScript(computername, script string) (Task, error) {
+
+ err := v.Refresh()
+ if err != nil {
+ return Task{}, fmt.Errorf("error refreshing vapp before running customization: %v", err)
+ }
+
+ // Check if VApp Children is populated
+ if v.VApp.Children == nil {
+ return Task{}, fmt.Errorf("vApp doesn't contain any children, aborting customization")
+ }
+
+ vu := &types.GuestCustomizationSection{
+ Ovf: "http://schemas.dmtf.org/ovf/envelope/1",
+ Xsi: "http://www.w3.org/2001/XMLSchema-instance",
+ Xmlns: "http://www.vmware.com/vcloud/v1.5",
+
+ HREF: v.VApp.Children.VM[0].HREF,
+ Type: "application/vnd.vmware.vcloud.guestCustomizationSection+xml",
+ Info: "Specifies Guest OS Customization Settings",
+ Enabled: true,
+ ComputerName: computername,
+ CustomizationScript: script,
+ }
+
+ output, err := xml.MarshalIndent(vu, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", 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, _ := url.ParseRequestURI(v.VApp.Children.VM[0].HREF)
+ s.Path += "/guestCustomizationSection/"
+
+ req := v.c.NewRequest(map[string]string{}, "PUT", *s, b)
+
+ req.Header.Add("Content-Type", "application/vnd.vmware.vcloud.guestCustomizationSection+xml")
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error customizing VM: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) GetStatus() (string, error) {
+ err := v.Refresh()
+ if err != nil {
+ return "", fmt.Errorf("error refreshing vapp: %v", err)
+ }
+ return types.VAppStatuses[v.VApp.Status], nil
+}
+
+func (v *VApp) ChangeCPUcount(size int) (Task, error) {
+
+ err := v.Refresh()
+ if err != nil {
+ return Task{}, fmt.Errorf("error refreshing vapp before running customization: %v", err)
+ }
+
+ // Check if VApp Children is populated
+ if v.VApp.Children == nil {
+ return Task{}, fmt.Errorf("vApp doesn't contain any children, aborting customization")
+ }
+
+ newcpu := &types.OVFItem{
+ XmlnsRasd: "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
+ XmlnsVCloud: "http://www.vmware.com/vcloud/v1.5",
+ XmlnsXsi: "http://www.w3.org/2001/XMLSchema-instance",
+ VCloudHREF: v.VApp.Children.VM[0].HREF + "/virtualHardwareSection/cpu",
+ VCloudType: "application/vnd.vmware.vcloud.rasdItem+xml",
+ AllocationUnits: "hertz * 10^6",
+ Description: "Number of Virtual CPUs",
+ ElementName: strconv.Itoa(size) + " virtual CPU(s)",
+ InstanceID: 4,
+ Reservation: 0,
+ ResourceType: 3,
+ VirtualQuantity: size,
+ Weight: 0,
+ Link: &types.Link{
+ HREF: v.VApp.Children.VM[0].HREF + "/virtualHardwareSection/cpu",
+ Rel: "edit",
+ Type: "application/vnd.vmware.vcloud.rasdItem+xml",
+ },
+ }
+
+ output, err := xml.MarshalIndent(newcpu, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", 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, _ := url.ParseRequestURI(v.VApp.Children.VM[0].HREF)
+ s.Path += "/virtualHardwareSection/cpu"
+
+ req := v.c.NewRequest(map[string]string{}, "PUT", *s, b)
+
+ req.Header.Add("Content-Type", "application/vnd.vmware.vcloud.rasdItem+xml")
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error customizing VM: %s", err)
+ }
+
+ task := NewTask(v.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
+
+}
+
+func (v *VApp) ChangeMemorySize(size int) (Task, error) {
+
+ err := v.Refresh()
+ if err != nil {
+ return Task{}, fmt.Errorf("error refreshing vapp before running customization: %v", err)
+ }
+
+ // Check if VApp Children is populated
+ if v.VApp.Children == nil {
+ return Task{}, fmt.Errorf("vApp doesn't contain any children, aborting customization")
+ }
+
+ newmem := &types.OVFItem{
+ XmlnsRasd: "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
+ XmlnsVCloud: "http://www.vmware.com/vcloud/v1.5",
+ XmlnsXsi: "http://www.w3.org/2001/XMLSchema-instance",
+ VCloudHREF: v.VApp.Children.VM[0].HREF + "/virtualHardwareSection/memory",
+ VCloudType: "application/vnd.vmware.vcloud.rasdItem+xml",
+ AllocationUnits: "byte * 2^20",
+ Description: "Memory Size",
+ ElementName: strconv.Itoa(size) + " MB of memory",
+ InstanceID: 5,
+ Reservation: 0,
+ ResourceType: 4,
+ VirtualQuantity: size,
+ Weight: 0,
+ Link: &types.Link{
+ HREF: v.VApp.Children.VM[0].HREF + "/virtualHardwareSection/memory",
+ Rel: "edit",
+ Type: "application/vnd.vmware.vcloud.rasdItem+xml",
+ },
+ }
+
+ output, err := xml.MarshalIndent(newmem, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", 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, _ := url.ParseRequestURI(v.VApp.Children.VM[0].HREF)
+ s.Path += "/virtualHardwareSection/memory"
+
+ req := v.c.NewRequest(map[string]string{}, "PUT", *s, b)
+
+ req.Header.Add("Content-Type", "application/vnd.vmware.vcloud.rasdItem+xml")
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Task{}, fmt.Errorf("error customizing VM: %s", err)
+ }
+
+ task := NewTask(v.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/Godeps/_workspace/src/github.com/vmware/govcloudair/vapp_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/vapp_test.go
new file mode 100644
index 0000000000..a218d1d70a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/vapp_test.go
@@ -0,0 +1,597 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "github.com/vmware/govcloudair/testutil"
+
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) Test_ComposeVApp(c *C) {
+
+ testServer.ResponseMap(7, testutil.ResponseMap{
+ "/api/org/11111111-1111-1111-1111-111111111111": testutil.Response{200, nil, orgExample},
+ "/api/network/44444444-4444-4444-4444-4444444444444": testutil.Response{200, nil, orgvdcnetExample},
+ "/api/catalog/e8a20fdf-8a78-440c-ac71-0420db59f854": testutil.Response{200, nil, catalogExample},
+ "/api/catalogItem/1176e485-8858-4e15-94e5-ae4face605ae": testutil.Response{200, nil, catalogitemExample},
+ "/api/vAppTemplate/vappTemplate-40cb9721-5f1a-44f9-b5c3-98c5f518c4f5": testutil.Response{200, nil, vapptemplateExample},
+ "/api/vdc/00000000-0000-0000-0000-000000000000/action/composeVApp": testutil.Response{200, nil, instantiatedvappExample},
+ "/api/vApp/vapp-00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vappExample},
+ })
+
+ // Get the Org populated
+ org, err := s.vdc.GetVDCOrg()
+ c.Assert(err, IsNil)
+
+ // Populate OrgVDCNetwork
+ net, err := s.vdc.FindVDCNetwork("networkName")
+ c.Assert(err, IsNil)
+
+ // Populate Catalog
+ cat, err := org.FindCatalog("Public Catalog")
+ c.Assert(err, IsNil)
+
+ // Populate Catalog Item
+ catitem, err := cat.FindCatalogItem("CentOS64-32bit")
+ c.Assert(err, IsNil)
+
+ // Get VAppTemplate
+ vapptemplate, err := catitem.GetVAppTemplate()
+ c.Assert(err, IsNil)
+
+ // Compose VApp
+ task, err := s.vapp.ComposeVApp(net, vapptemplate, "name", "description")
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.OperationName, Equals, "vdcInstantiateVapp")
+ c.Assert(s.vapp.VApp.HREF, Equals, "http://localhost:4444/api/vApp/vapp-00000000-0000-0000-0000-000000000000")
+
+ status, err := s.vapp.GetStatus()
+
+ c.Assert(err, IsNil)
+ c.Assert(status, Equals, "POWERED_OFF")
+
+ _ = testServer.WaitRequests(7)
+
+}
+
+func (s *S) Test_PowerOn(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.PowerOn()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_PowerOff(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.PowerOff()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_Reboot(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.Reboot()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_Reset(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.Reset()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_Suspend(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.Suspend()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_Shutdown(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.Shutdown()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_Undeploy(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.Undeploy()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_Deploy(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.Deploy()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_Delete(c *C) {
+
+ testServer.Response(200, nil, taskExample)
+ task, err := s.vapp.Delete()
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+}
+
+func (s *S) Test_RunCustomizationScript(c *C) {
+
+ testServer.ResponseMap(8, testutil.ResponseMap{
+ "/api/org/11111111-1111-1111-1111-111111111111": testutil.Response{200, nil, orgExample},
+ "/api/network/44444444-4444-4444-4444-4444444444444": testutil.Response{200, nil, orgvdcnetExample},
+ "/api/catalog/e8a20fdf-8a78-440c-ac71-0420db59f854": testutil.Response{200, nil, catalogExample},
+ "/api/catalogItem/1176e485-8858-4e15-94e5-ae4face605ae": testutil.Response{200, nil, catalogitemExample},
+ "/api/vAppTemplate/vappTemplate-40cb9721-5f1a-44f9-b5c3-98c5f518c4f5": testutil.Response{200, nil, vapptemplateExample},
+ "/api/vdc/00000000-0000-0000-0000-000000000000/action/composeVApp": testutil.Response{200, nil, instantiatedvappExample},
+ "/api/vApp/vapp-00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vappExample},
+ "/api/vApp/vm-00000000-0000-0000-0000-000000000000/guestCustomizationSection/": testutil.Response{200, nil, taskExample},
+ })
+
+ // Get the Org populated
+ org, err := s.vdc.GetVDCOrg()
+ c.Assert(err, IsNil)
+
+ // Populate OrgVDCNetwork
+ net, err := s.vdc.FindVDCNetwork("networkName")
+ c.Assert(err, IsNil)
+
+ // Populate Catalog
+ cat, err := org.FindCatalog("Public Catalog")
+ c.Assert(err, IsNil)
+
+ // Populate Catalog Item
+ catitem, err := cat.FindCatalogItem("CentOS64-32bit")
+ c.Assert(err, IsNil)
+
+ // Get VAppTemplate
+ vapptemplate, err := catitem.GetVAppTemplate()
+ c.Assert(err, IsNil)
+
+ // Compose VApp
+ task, err := s.vapp.ComposeVApp(net, vapptemplate, "name", "description")
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.OperationName, Equals, "vdcInstantiateVapp")
+ c.Assert(s.vapp.VApp.HREF, Equals, "http://localhost:4444/api/vApp/vapp-00000000-0000-0000-0000-000000000000")
+
+ task, err = s.vapp.RunCustomizationScript("computername", "this is my script")
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+ _ = testServer.WaitRequests(8)
+
+}
+
+func (s *S) Test_ChangeCPUcount(c *C) {
+
+ testServer.ResponseMap(8, testutil.ResponseMap{
+ "/api/org/11111111-1111-1111-1111-111111111111": testutil.Response{200, nil, orgExample},
+ "/api/network/44444444-4444-4444-4444-4444444444444": testutil.Response{200, nil, orgvdcnetExample},
+ "/api/catalog/e8a20fdf-8a78-440c-ac71-0420db59f854": testutil.Response{200, nil, catalogExample},
+ "/api/catalogItem/1176e485-8858-4e15-94e5-ae4face605ae": testutil.Response{200, nil, catalogitemExample},
+ "/api/vAppTemplate/vappTemplate-40cb9721-5f1a-44f9-b5c3-98c5f518c4f5": testutil.Response{200, nil, vapptemplateExample},
+ "/api/vdc/00000000-0000-0000-0000-000000000000/action/composeVApp": testutil.Response{200, nil, instantiatedvappExample},
+ "/api/vApp/vapp-00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vappExample},
+ "/api/vApp/vm-00000000-0000-0000-0000-000000000000/virtualHardwareSection/cpu": testutil.Response{200, nil, taskExample},
+ })
+
+ // Get the Org populated
+ org, err := s.vdc.GetVDCOrg()
+ c.Assert(err, IsNil)
+
+ // Populate OrgVDCNetwork
+ net, err := s.vdc.FindVDCNetwork("networkName")
+ c.Assert(err, IsNil)
+
+ // Populate Catalog
+ cat, err := org.FindCatalog("Public Catalog")
+ c.Assert(err, IsNil)
+
+ // Populate Catalog Item
+ catitem, err := cat.FindCatalogItem("CentOS64-32bit")
+ c.Assert(err, IsNil)
+
+ // Get VAppTemplate
+ vapptemplate, err := catitem.GetVAppTemplate()
+ c.Assert(err, IsNil)
+
+ // Compose VApp
+ task, err := s.vapp.ComposeVApp(net, vapptemplate, "name", "description")
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.OperationName, Equals, "vdcInstantiateVapp")
+ c.Assert(s.vapp.VApp.HREF, Equals, "http://localhost:4444/api/vApp/vapp-00000000-0000-0000-0000-000000000000")
+
+ task, err = s.vapp.ChangeCPUcount(2)
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+ _ = testServer.WaitRequests(8)
+
+}
+
+func (s *S) Test_ChangeMemorySize(c *C) {
+
+ testServer.ResponseMap(8, testutil.ResponseMap{
+ "/api/org/11111111-1111-1111-1111-111111111111": testutil.Response{200, nil, orgExample},
+ "/api/network/44444444-4444-4444-4444-4444444444444": testutil.Response{200, nil, orgvdcnetExample},
+ "/api/catalog/e8a20fdf-8a78-440c-ac71-0420db59f854": testutil.Response{200, nil, catalogExample},
+ "/api/catalogItem/1176e485-8858-4e15-94e5-ae4face605ae": testutil.Response{200, nil, catalogitemExample},
+ "/api/vAppTemplate/vappTemplate-40cb9721-5f1a-44f9-b5c3-98c5f518c4f5": testutil.Response{200, nil, vapptemplateExample},
+ "/api/vdc/00000000-0000-0000-0000-000000000000/action/composeVApp": testutil.Response{200, nil, instantiatedvappExample},
+ "/api/vApp/vapp-00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vappExample},
+ "/api/vApp/vm-00000000-0000-0000-0000-000000000000/virtualHardwareSection/memory": testutil.Response{200, nil, taskExample},
+ })
+
+ // Get the Org populated
+ org, err := s.vdc.GetVDCOrg()
+ c.Assert(err, IsNil)
+
+ // Populate OrgVDCNetwork
+ net, err := s.vdc.FindVDCNetwork("networkName")
+ c.Assert(err, IsNil)
+
+ // Populate Catalog
+ cat, err := org.FindCatalog("Public Catalog")
+ c.Assert(err, IsNil)
+
+ // Populate Catalog Item
+ catitem, err := cat.FindCatalogItem("CentOS64-32bit")
+ c.Assert(err, IsNil)
+
+ // Get VAppTemplate
+ vapptemplate, err := catitem.GetVAppTemplate()
+ c.Assert(err, IsNil)
+
+ // Compose VApp
+ task, err := s.vapp.ComposeVApp(net, vapptemplate, "name", "description")
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.OperationName, Equals, "vdcInstantiateVapp")
+ c.Assert(s.vapp.VApp.HREF, Equals, "http://localhost:4444/api/vApp/vapp-00000000-0000-0000-0000-000000000000")
+
+ task, err = s.vapp.ChangeMemorySize(4096)
+
+ c.Assert(err, IsNil)
+ c.Assert(task.Task.Status, Equals, "success")
+
+ _ = testServer.WaitRequests(8)
+
+}
+
+var instantiatedvappExample = `
+
+
+
+
+
+
+
+
+
+
+
+
+ My vApp to be deployed
+
+
+
+
+
+
+
+
+
+
+ 2014-10-24T15:26:59.067Z
+
+
+
+ false
+
+ `
+
+var vappExample = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Test API GO4444!
+
+ Lease settings section
+
+ 0
+ 0
+
+
+ VApp startup section
+
+
+
+
+ The list of logical networks
+
+ This isolated network was created with Create VDC.
+
+
+ This is a special place-holder used for disconnected network interfaces.
+
+
+
+ The configuration parameters for logical networks
+
+
+
+ This isolated network was created with Create VDC.
+
+
+
+ true
+ 192.168.99.1
+ 255.255.255.0
+ true
+
+
+ 192.168.99.2
+ 192.168.99.100
+
+
+
+
+
+ bridged
+ false
+
+ false
+
+
+ This is a special place-holder used for disconnected network interfaces.
+
+
+
+ false
+ 196.254.254.254
+ 255.255.0.0
+ 196.254.254.254
+
+
+ isolated
+
+ false
+
+
+
+ Snapshot information section
+
+ 2014-11-06T22:24:43.913Z
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id: cts-6.4-32bit
+
+ Virtual hardware requirements
+
+ Virtual Hardware Family
+ 0
+ CentOS64-32bit
+ vmx-09
+
+
+ 00:50:56:02:0b:36
+ 0
+ false
+ none
+ E1000 ethernet adapter on "none"
+ Network adapter 0
+ 1
+ E1000
+ 10
+
+
+ 0
+ SCSI Controller
+ SCSI Controller 0
+ 2
+ lsilogic
+ 6
+
+
+ 0
+ Hard disk
+ Hard disk 1
+
+ 2000
+ 2
+ 17
+
+
+ 1
+ IDE Controller
+ IDE Controller 1
+ 3
+ 5
+
+
+ 0
+ false
+ CD/DVD Drive
+ CD/DVD Drive 1
+
+ 3002
+ 3
+ 15
+
+
+ 0
+ false
+ Floppy Drive
+ Floppy Drive 1
+
+ 8000
+ 14
+
+
+ hertz * 10^6
+ Number of Virtual CPUs
+ 1 virtual CPU(s)
+ 4
+ 0
+ 3
+ 1
+ 0
+ 1
+
+
+
+ byte * 2^20
+ Memory Size
+ 1024 MB of memory
+ 5
+ 0
+ 4
+ 1024
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the operating system installed
+ CentOS 4/5/6 (32-bit)
+
+
+
+ Specifies the available VM network connections
+ 0
+
+ 0
+ false
+ 00:50:56:02:0b:36
+ NONE
+
+
+
+
+ Specifies Guest OS Customization Settings
+ true
+ false
+ 00000000-0000-0000-0000-000000000000
+ false
+ false
+ true
+ true
+ false
+ 0
+ true
+ cts-6.4-32bit
+
+
+
+ Specifies Runtime info
+
+
+
+ Snapshot information section
+
+ CentOS64-32bit
+
+
+ false
+ false
+
+
+
+
+
+ `
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/vapptemplate.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/vapptemplate.go
new file mode 100644
index 0000000000..8c4867fdec
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/vapptemplate.go
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type VAppTemplate struct {
+ VAppTemplate *types.VAppTemplate
+ c *Client
+}
+
+func NewVAppTemplate(c *Client) *VAppTemplate {
+ return &VAppTemplate{
+ VAppTemplate: new(types.VAppTemplate),
+ c: c,
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/vapptemplate_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/vapptemplate_test.go
new file mode 100644
index 0000000000..cddb143ef0
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/vapptemplate_test.go
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+var vapptemplateExample = `
+
+
+
+
+
+
+
+
+
+
+ id: cts-6.4-32bit
+
+
+
+
+
+
+
+
+
+ id: cts-6.4-32bit
+
+ Specifies the available VM network connections
+ 0
+
+ 0
+ false
+ 00:50:56:02:00:39
+ NONE
+
+
+
+ Specifies Guest OS Customization Settings
+ true
+ false
+ 3a3934d2-1f3f-4782-a911-f143da27e88c
+ false
+ false
+ true
+ true
+ false
+ 0
+ true
+ cts-6.4-32bit
+
+
+ Virtual hardware requirements
+
+ Virtual Hardware Family
+ 0
+ CentOS64-32bit
+ vmx-09
+
+
+ 00:50:56:02:00:39
+ 0
+ false
+ none
+ E1000 ethernet adapter on "none"
+ Network adapter 0
+ 1
+ E1000
+ 10
+
+
+ 0
+ SCSI Controller
+ SCSI Controller 0
+ 2
+ lsilogic
+ 6
+
+
+ 0
+ Hard disk
+ Hard disk 1
+
+ 2000
+ 2
+ 17
+
+
+ 1
+ IDE Controller
+ IDE Controller 1
+ 3
+ 5
+
+
+ 0
+ false
+ CD/DVD Drive
+ CD/DVD Drive 1
+
+ 3002
+ 3
+ 15
+
+
+ 0
+ false
+ Floppy Drive
+ Floppy Drive 1
+
+ 8000
+ 14
+
+
+ hertz * 10^6
+ Number of Virtual CPUs
+ 1 virtual CPU(s)
+ 4
+ 0
+ 3
+ 1
+ 0
+ 1
+
+
+ byte * 2^20
+ Memory Size
+ 1024 MB of memory
+ 5
+ 0
+ 4
+ 1024
+ 0
+
+
+
+
+
+
+
+
+ CentOS64-32bit
+ 2014-06-04T21:06:43.547Z
+
+
+
+ The list of logical networks
+
+ This is a special place-holder used for disconnected network interfaces.
+
+
+
+ The configuration parameters for logical networks
+
+ This is a special place-holder used for disconnected network interfaces.
+
+
+
+ false
+ 196.254.254.254
+ 255.255.0.0
+ 196.254.254.254
+
+
+ isolated
+
+ false
+
+
+
+ Lease settings section
+
+ 0
+
+
+ VApp template customization section
+ true
+
+ 2014-06-04T21:06:43.547Z
+
+
+ `
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/vdc.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/vdc.go
new file mode 100644
index 0000000000..f233455b4f
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/vdc.go
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "fmt"
+ "net/url"
+ "strings"
+
+ types "github.com/vmware/govcloudair/types/v56"
+)
+
+type Vdc struct {
+ Vdc *types.Vdc
+ c *Client
+}
+
+func NewVdc(c *Client) *Vdc {
+ return &Vdc{
+ Vdc: new(types.Vdc),
+ c: c,
+ }
+}
+
+func (c *Client) retrieveVDC() (Vdc, error) {
+
+ req := c.NewRequest(map[string]string{}, "GET", c.VCDVDCHREF, nil)
+
+ resp, err := checkResp(c.Http.Do(req))
+ if err != nil {
+ return Vdc{}, fmt.Errorf("error retreiving vdc: %s", err)
+ }
+
+ vdc := NewVdc(c)
+
+ if err = decodeBody(resp, vdc.Vdc); err != nil {
+ return Vdc{}, fmt.Errorf("error decoding vdc response: %s", err)
+ }
+
+ // The request was successful
+ return *vdc, nil
+}
+
+func (v *Vdc) Refresh() error {
+
+ if v.Vdc.HREF == "" {
+ return fmt.Errorf("cannot refresh, Object is empty")
+ }
+
+ u, _ := url.ParseRequestURI(v.Vdc.HREF)
+
+ req := v.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return fmt.Errorf("error retreiving Edge Gateway: %s", err)
+ }
+
+ // Empty struct before a new unmarshal, otherwise we end up with duplicate
+ // elements in slices.
+ v.Vdc = &types.Vdc{}
+
+ if err = decodeBody(resp, v.Vdc); err != nil {
+ return fmt.Errorf("error decoding Edge Gateway response: %s", err)
+ }
+
+ // The request was successful
+ return nil
+}
+
+func (v *Vdc) FindVDCNetwork(network string) (OrgVDCNetwork, error) {
+
+ for _, an := range v.Vdc.AvailableNetworks {
+ for _, n := range an.Network {
+ if n.Name == network {
+ u, err := url.ParseRequestURI(n.HREF)
+ if err != nil {
+ return OrgVDCNetwork{}, fmt.Errorf("error decoding vdc response: %s", err)
+ }
+
+ req := v.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return OrgVDCNetwork{}, fmt.Errorf("error retreiving orgvdcnetwork: %s", err)
+ }
+
+ orgnet := NewOrgVDCNetwork(v.c)
+
+ if err = decodeBody(resp, orgnet.OrgVDCNetwork); err != nil {
+ return OrgVDCNetwork{}, fmt.Errorf("error decoding orgvdcnetwork response: %s", err)
+ }
+
+ // The request was successful
+ return *orgnet, nil
+
+ }
+ }
+ }
+
+ return OrgVDCNetwork{}, fmt.Errorf("can't find VDC Network: %s", network)
+}
+
+func (v *Vdc) GetVDCOrg() (Org, error) {
+
+ for _, av := range v.Vdc.Link {
+ if av.Rel == "up" && av.Type == "application/vnd.vmware.vcloud.org+xml" {
+ u, err := url.ParseRequestURI(av.HREF)
+
+ if err != nil {
+ return Org{}, fmt.Errorf("error decoding vdc response: %s", err)
+ }
+
+ req := v.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return Org{}, fmt.Errorf("error retreiving org: %s", err)
+ }
+
+ org := NewOrg(v.c)
+
+ if err = decodeBody(resp, org.Org); err != nil {
+ return Org{}, fmt.Errorf("error decoding org response: %s", err)
+ }
+
+ // The request was successful
+ return *org, nil
+
+ }
+ }
+ return Org{}, fmt.Errorf("can't find VDC Org")
+}
+
+func (v *Vdc) FindEdgeGateway(edgegateway string) (EdgeGateway, error) {
+
+ for _, av := range v.Vdc.Link {
+ if av.Rel == "edgeGateways" && av.Type == "application/vnd.vmware.vcloud.query.records+xml" {
+ u, err := url.ParseRequestURI(av.HREF)
+
+ if err != nil {
+ return EdgeGateway{}, fmt.Errorf("error decoding vdc response: %s", err)
+ }
+
+ // Querying the Result list
+ req := v.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err := checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return EdgeGateway{}, fmt.Errorf("error retrieving edge gateway records: %s", err)
+ }
+
+ query := new(types.QueryResultEdgeGatewayRecordsType)
+
+ if err = decodeBody(resp, query); err != nil {
+ return EdgeGateway{}, fmt.Errorf("error decoding edge gateway query response: %s", err)
+ }
+
+ u, err = url.ParseRequestURI(query.EdgeGatewayRecord.HREF)
+ if err != nil {
+ return EdgeGateway{}, fmt.Errorf("error decoding edge gateway query response: %s", err)
+ }
+
+ // Querying the Result list
+ req = v.c.NewRequest(map[string]string{}, "GET", *u, nil)
+
+ resp, err = checkResp(v.c.Http.Do(req))
+ if err != nil {
+ return EdgeGateway{}, fmt.Errorf("error retrieving edge gateway: %s", err)
+ }
+
+ edge := NewEdgeGateway(v.c)
+
+ if err = decodeBody(resp, edge.EdgeGateway); err != nil {
+ return EdgeGateway{}, fmt.Errorf("error decoding edge gateway response: %s", err)
+ }
+
+ return *edge, nil
+
+ }
+ }
+ return EdgeGateway{}, fmt.Errorf("can't find Edge Gateway")
+
+}
+
+func (v *Vdc) FindVAppByName(vapp string) (VApp, error) {
+
+ err := v.Refresh()
+ if err != nil {
+ return VApp{}, fmt.Errorf("error refreshing vdc: %s", err)
+ }
+
+ for _, resents := range v.Vdc.ResourceEntities {
+ for _, resent := range resents.ResourceEntity {
+
+ if resent.Name == vapp && resent.Type == "application/vnd.vmware.vcloud.vApp+xml" {
+
+ u, err := url.ParseRequestURI(resent.HREF)
+
+ if err != nil {
+ return VApp{}, 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 VApp{}, fmt.Errorf("error retrieving vApp: %s", err)
+ }
+
+ newvapp := NewVApp(v.c)
+
+ if err = decodeBody(resp, newvapp.VApp); err != nil {
+ return VApp{}, fmt.Errorf("error decoding vApp response: %s", err)
+ }
+
+ return *newvapp, nil
+
+ }
+ }
+ }
+ return VApp{}, fmt.Errorf("can't find vApp: %s", vapp)
+}
+
+func (v *Vdc) FindVAppByID(vappid string) (VApp, error) {
+
+ // Horrible hack to fetch a vapp with its id.
+ // urn:vcloud:vapp:00000000-0000-0000-0000-000000000000
+
+ err := v.Refresh()
+ if err != nil {
+ return VApp{}, fmt.Errorf("error refreshing vdc: %s", err)
+ }
+
+ urnslice := strings.SplitAfter(vappid, ":")
+ urnid := urnslice[len(urnslice)-1]
+
+ for _, resents := range v.Vdc.ResourceEntities {
+ for _, resent := range resents.ResourceEntity {
+
+ hrefslice := strings.SplitAfter(resent.HREF, "/")
+ hrefslice = strings.SplitAfter(hrefslice[len(hrefslice)-1], "-")
+ res := strings.Join(hrefslice[1:], "")
+
+ if res == urnid && resent.Type == "application/vnd.vmware.vcloud.vApp+xml" {
+
+ u, err := url.ParseRequestURI(resent.HREF)
+
+ if err != nil {
+ return VApp{}, 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 VApp{}, fmt.Errorf("error retrieving vApp: %s", err)
+ }
+
+ newvapp := NewVApp(v.c)
+
+ if err = decodeBody(resp, newvapp.VApp); err != nil {
+ return VApp{}, fmt.Errorf("error decoding vApp response: %s", err)
+ }
+
+ return *newvapp, nil
+
+ }
+ }
+ }
+ return VApp{}, fmt.Errorf("can't find vApp")
+
+}
diff --git a/Godeps/_workspace/src/github.com/vmware/govcloudair/vdc_test.go b/Godeps/_workspace/src/github.com/vmware/govcloudair/vdc_test.go
new file mode 100644
index 0000000000..5fb44a7c82
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/vmware/govcloudair/vdc_test.go
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
+ */
+
+package govcloudair
+
+import (
+ "github.com/vmware/govcloudair/testutil"
+
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) Test_FindVDCNetwork(c *C) {
+
+ testServer.Response(200, nil, orgvdcnetExample)
+
+ net, err := s.vdc.FindVDCNetwork("networkName")
+
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(net, NotNil)
+ c.Assert(net.OrgVDCNetwork.HREF, Equals, "http://localhost:4444/api/network/cb0f4c9e-1a46-49d4-9fcb-d228000a6bc1")
+
+ // find Invalid Network
+ net, err = s.vdc.FindVDCNetwork("INVALID")
+ c.Assert(err, NotNil)
+}
+
+func (s *S) Test_GetVDCOrg(c *C) {
+
+ testServer.Response(200, nil, orgExample)
+
+ org, err := s.vdc.GetVDCOrg()
+
+ _ = testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(org, NotNil)
+ c.Assert(org.Org.HREF, Equals, "http://localhost:4444/api/org/23bd2339-c55f-403c-baf3-13109e8c8d57")
+}
+
+func (s *S) Test_NewVdc(c *C) {
+
+ testServer.Response(200, nil, vdcExample)
+ err := s.vdc.Refresh()
+ _ = testServer.WaitRequest()
+ c.Assert(err, IsNil)
+
+ c.Assert(s.vdc.Vdc.Link[0].Rel, Equals, "up")
+ c.Assert(s.vdc.Vdc.Link[0].Type, Equals, "application/vnd.vmware.vcloud.org+xml")
+ c.Assert(s.vdc.Vdc.Link[0].HREF, Equals, "http://localhost:4444/api/org/11111111-1111-1111-1111-111111111111")
+
+ c.Assert(s.vdc.Vdc.AllocationModel, Equals, "AllocationPool")
+
+ for _, v := range s.vdc.Vdc.ComputeCapacity {
+ c.Assert(v.CPU.Units, Equals, "MHz")
+ c.Assert(v.CPU.Allocated, Equals, int64(30000))
+ c.Assert(v.CPU.Limit, Equals, int64(30000))
+ c.Assert(v.CPU.Reserved, Equals, int64(15000))
+ c.Assert(v.CPU.Used, Equals, int64(0))
+ c.Assert(v.CPU.Overhead, Equals, int64(0))
+ c.Assert(v.Memory.Units, Equals, "MB")
+ c.Assert(v.Memory.Allocated, Equals, int64(61440))
+ c.Assert(v.Memory.Limit, Equals, int64(61440))
+ c.Assert(v.Memory.Reserved, Equals, int64(61440))
+ c.Assert(v.Memory.Used, Equals, int64(6144))
+ c.Assert(v.Memory.Overhead, Equals, int64(95))
+ }
+
+ c.Assert(s.vdc.Vdc.ResourceEntities[0].ResourceEntity[0].Name, Equals, "vAppTemplate")
+ c.Assert(s.vdc.Vdc.ResourceEntities[0].ResourceEntity[0].Type, Equals, "application/vnd.vmware.vcloud.vAppTemplate+xml")
+ c.Assert(s.vdc.Vdc.ResourceEntities[0].ResourceEntity[0].HREF, Equals, "http://localhost:4444/api/vAppTemplate/vappTemplate-22222222-2222-2222-2222-222222222222")
+
+ for _, v := range s.vdc.Vdc.AvailableNetworks {
+ for _, v2 := range v.Network {
+ c.Assert(v2.Name, Equals, "networkName")
+ c.Assert(v2.Type, Equals, "application/vnd.vmware.vcloud.network+xml")
+ c.Assert(v2.HREF, Equals, "http://localhost:4444/api/network/44444444-4444-4444-4444-4444444444444")
+ }
+ }
+
+ c.Assert(s.vdc.Vdc.NicQuota, Equals, 0)
+ c.Assert(s.vdc.Vdc.NetworkQuota, Equals, 20)
+ c.Assert(s.vdc.Vdc.UsedNetworkCount, Equals, 0)
+ c.Assert(s.vdc.Vdc.VMQuota, Equals, 0)
+ c.Assert(s.vdc.Vdc.IsEnabled, Equals, true)
+
+ for _, v := range s.vdc.Vdc.VdcStorageProfiles {
+ for _, v2 := range v.VdcStorageProfile {
+ c.Assert(v2.Name, Equals, "storageProfile")
+ c.Assert(v2.Type, Equals, "application/vnd.vmware.vcloud.vdcStorageProfile+xml")
+ c.Assert(v2.HREF, Equals, "http://localhost:4444/api/vdcStorageProfile/88888888-8888-8888-8888-888888888888")
+ }
+ }
+
+}
+
+func (s *S) Test_FindVApp(c *C) {
+
+ // testServer.Response(200, nil, vappExample)
+
+ // vapp, err := s.vdc.FindVAppByID("")
+
+ // _ = testServer.WaitRequest()
+ // testServer.Flush()
+ // c.Assert(err, IsNil)
+
+ testServer.ResponseMap(2, testutil.ResponseMap{
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ "/api/vApp/vapp-00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vappExample},
+ })
+
+ _, err := s.vdc.FindVAppByName("myVApp")
+
+ _ = testServer.WaitRequests(2)
+
+ c.Assert(err, IsNil)
+
+ testServer.ResponseMap(2, testutil.ResponseMap{
+ "/api/vdc/00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vdcExample},
+ "/api/vApp/vapp-00000000-0000-0000-0000-000000000000": testutil.Response{200, nil, vappExample},
+ })
+
+ _, err = s.vdc.FindVAppByID("urn:vcloud:vapp:00000000-0000-0000-0000-000000000000")
+
+ _ = testServer.WaitRequests(2)
+
+ c.Assert(err, IsNil)
+
+}
+
+var vdcExample = `
+
+
+
+
+ AllocationPool
+
+
+ MHz
+ 30000
+ 30000
+ 15000
+ 0
+ 0
+
+
+ MB
+ 61440
+ 61440
+ 61440
+ 6144
+ 95
+
+
+
+
+
+
+
+
+
+
+
+ vmx-10
+
+
+ 0
+ 20
+ 0
+ 0
+ true
+
+
+
+
+ `
diff --git a/commands.go b/commands.go
index 933d65c743..135aa502d7 100644
--- a/commands.go
+++ b/commands.go
@@ -19,6 +19,9 @@ import (
_ "github.com/docker/machine/drivers/google"
_ "github.com/docker/machine/drivers/none"
_ "github.com/docker/machine/drivers/virtualbox"
+ _ "github.com/docker/machine/drivers/vmwarefusion"
+ _ "github.com/docker/machine/drivers/vmwarevcloudair"
+ _ "github.com/docker/machine/drivers/vmwarevsphere"
"github.com/docker/machine/state"
)