Merge pull request #67722 from dougm/vcp-zones

Automatic merge from submit-queue (batch tested with PRs 66973, 67704, 67722, 67723, 63512). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

godeps: update vmware/govmomi

**What this PR does / why we need it**:

Update required to continue work on #64021

- The govmomi tag API changed

- Pulling in the new vapi/simulator package for testing the VCP Zones impl

**Release note**:

```release-note
NONE
```
This commit is contained in:
Kubernetes Submit Queue 2018-08-22 18:20:27 -07:00 committed by GitHub
commit 0198e3a311
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1859 additions and 936 deletions

135
Godeps/Godeps.json generated
View File

@ -2977,153 +2977,168 @@
},
{
"ImportPath": "github.com/vmware/govmomi",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/find",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/list",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/lookup",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/lookup/methods",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/lookup/simulator",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/lookup/types",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/nfc",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/object",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/pbm",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/pbm/methods",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/pbm/types",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/property",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/session",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/simulator",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/simulator/esx",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/simulator/vpx",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/sts",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/sts/internal",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/sts/simulator",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/task",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vapi/internal",
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vapi/rest",
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vapi/simulator",
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vapi/tags",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/debug",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/methods",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/mo",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/progress",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/soap",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/types",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/xml",
"Comment": "v0.18.0-40-gbbd9953",
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
"Comment": "v0.18.0-48-g22f7465",
"Rev": "22f74650cf39ba4649fba45e770df0f44df6f758"
},
{
"ImportPath": "github.com/vmware/photon-controller-go-sdk/SSPI",

630
Godeps/LICENSES generated
View File

@ -90411,6 +90411,636 @@ SOFTWARE.
================================================================================
================================================================================
= vendor/github.com/vmware/govmomi/vapi/internal licensed under: =
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 [yyyy] [name of copyright owner]
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.
= vendor/github.com/vmware/govmomi/LICENSE.txt 3b83ef96387f14655fc854ddc3c6bd57
================================================================================
================================================================================
= vendor/github.com/vmware/govmomi/vapi/rest licensed under: =
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 [yyyy] [name of copyright owner]
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.
= vendor/github.com/vmware/govmomi/LICENSE.txt 3b83ef96387f14655fc854ddc3c6bd57
================================================================================
================================================================================
= vendor/github.com/vmware/govmomi/vapi/simulator licensed under: =
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 [yyyy] [name of copyright owner]
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.
= vendor/github.com/vmware/govmomi/LICENSE.txt 3b83ef96387f14655fc854ddc3c6bd57
================================================================================
================================================================================
= vendor/github.com/vmware/govmomi/vapi/tags licensed under: =

View File

@ -29,6 +29,7 @@ go_library(
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/vmware/govmomi/vapi/rest:go_default_library",
"//vendor/github.com/vmware/govmomi/vapi/tags:go_default_library",
"//vendor/github.com/vmware/govmomi/vim25:go_default_library",
"//vendor/github.com/vmware/govmomi/vim25/mo:go_default_library",
@ -59,6 +60,7 @@ go_test(
"//vendor/github.com/vmware/govmomi/simulator:go_default_library",
"//vendor/github.com/vmware/govmomi/simulator/vpx:go_default_library",
"//vendor/github.com/vmware/govmomi/sts/simulator:go_default_library",
"//vendor/github.com/vmware/govmomi/vapi/simulator:go_default_library",
],
)

View File

@ -34,6 +34,7 @@ import (
"gopkg.in/gcfg.v1"
"github.com/golang/glog"
"github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vapi/tags"
"k8s.io/api/core/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
@ -1318,11 +1319,10 @@ func (vs *VSphere) NodeManager() (nodeManager *NodeManager) {
return vs.nodeManager
}
func withTagsClient(ctx context.Context, connection *vclib.VSphereConnection, f func(c *tags.RestClient) error) error {
vsURL := connection.Client.URL()
vsURL.User = url.UserPassword(connection.Username, connection.Password)
c := tags.NewClient(vsURL, connection.Insecure, "")
if err := c.Login(ctx); err != nil {
func withTagsClient(ctx context.Context, connection *vclib.VSphereConnection, f func(c *rest.Client) error) error {
c := rest.NewClient(connection.Client)
user := url.UserPassword(connection.Username, connection.Password)
if err := c.Login(ctx, user); err != nil {
return err
}
defer c.Logout(ctx)
@ -1353,7 +1353,8 @@ func (vs *VSphere) GetZone(ctx context.Context) (cloudprovider.Zone, error) {
return cloudprovider.Zone{}, err
}
client := vsi.conn
err = withTagsClient(ctx, client, func(client *tags.RestClient) error {
err = withTagsClient(ctx, client, func(c *rest.Client) error {
client := tags.NewManager(c)
tags, err := client.ListAttachedTags(ctx, vmHost)
if err != nil {
glog.Errorf("Cannot list attached tags. Get zone for node %s error", nodeName)

View File

@ -31,6 +31,7 @@ import (
"github.com/vmware/govmomi/simulator"
"github.com/vmware/govmomi/simulator/vpx"
sts "github.com/vmware/govmomi/sts/simulator"
_ "github.com/vmware/govmomi/vapi/simulator"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/rand"
"k8s.io/kubernetes/pkg/cloudprovider"

View File

@ -37,6 +37,9 @@ filegroup(
"//vendor/github.com/vmware/govmomi/simulator:all-srcs",
"//vendor/github.com/vmware/govmomi/sts:all-srcs",
"//vendor/github.com/vmware/govmomi/task:all-srcs",
"//vendor/github.com/vmware/govmomi/vapi/internal:all-srcs",
"//vendor/github.com/vmware/govmomi/vapi/rest:all-srcs",
"//vendor/github.com/vmware/govmomi/vapi/simulator:all-srcs",
"//vendor/github.com/vmware/govmomi/vapi/tags:all-srcs",
"//vendor/github.com/vmware/govmomi/vim25:all-srcs",
],

View File

@ -83,4 +83,4 @@ Refer to the [CHANGELOG](CHANGELOG.md) for version to version changes.
## License
govmomi is available under the [Apache 2 license](LICENSE).
govmomi is available under the [Apache 2 license](LICENSE.txt).

View File

@ -137,8 +137,12 @@ func (s *SessionManager) LoginByToken(ctx *Context, req *types.LoginByToken) soa
func (s *SessionManager) Logout(ctx *Context, _ *types.Logout) soap.HasFault {
session := ctx.Session
delete(s.sessions, session.Key)
pc := Map.content().PropertyCollector
for ref, obj := range ctx.Session.Registry.objects {
if ref == pc {
continue // don't unregister the PropertyCollector singleton
}
if _, ok := obj.(RegisterObject); ok {
ctx.Map.Remove(ref) // Remove RegisterObject handlers
}

27
vendor/github.com/vmware/govmomi/vapi/internal/BUILD generated vendored Normal file
View File

@ -0,0 +1,27 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["internal.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/vmware/govmomi/vapi/internal",
importpath = "github.com/vmware/govmomi/vapi/internal",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/vmware/govmomi/vim25/mo:go_default_library",
"//vendor/github.com/vmware/govmomi/vim25/types:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,126 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
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.
*/
package internal
import (
"bytes"
"encoding/json"
"io"
"net/http"
"net/url"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
const (
Path = "/rest/com/vmware"
SessionPath = "/cis/session"
CategoryPath = "/cis/tagging/category"
TagPath = "/cis/tagging/tag"
AssociationPath = "/cis/tagging/tag-association"
SessionCookieName = "vmware-api-session-id"
)
// AssociatedObject is the same structure as types.ManagedObjectReference,
// just with a different field name (ID instead of Value).
// In the API we use mo.Reference, this type is only used for wire transfer.
type AssociatedObject struct {
Type string `json:"type"`
Value string `json:"id"`
}
// Reference implements mo.Reference
func (o AssociatedObject) Reference() types.ManagedObjectReference {
return types.ManagedObjectReference(o)
}
// Association for tag-association requests.
type Association struct {
TagID string `json:"tag_id,omitempty"`
ObjectID *AssociatedObject `json:"object_id,omitempty"`
}
// NewAssociation returns an Association, converting ref to an AssociatedObject.
func NewAssociation(tagID string, ref mo.Reference) Association {
obj := AssociatedObject(ref.Reference())
return Association{
TagID: tagID,
ObjectID: &obj,
}
}
type CloneURL interface {
URL() *url.URL
}
// Resource wraps url.URL with helpers
type Resource struct {
u *url.URL
}
func URL(c CloneURL, path string) *Resource {
r := &Resource{u: c.URL()}
r.u.Path = Path + path
return r
}
// WithID appends id to the URL.Path
func (r *Resource) WithID(id string) *Resource {
r.u.Path += "/id:" + id
return r
}
// WithAction sets adds action to the URL.RawQuery
func (r *Resource) WithAction(action string) *Resource {
r.u.RawQuery = url.Values{
"~action": []string{action},
}.Encode()
return r
}
// Request returns a new http.Request for the given method.
// An optional body can be provided for POST and PATCH methods.
func (r *Resource) Request(method string, body ...interface{}) *http.Request {
rdr := io.MultiReader() // empty body by default
if len(body) != 0 {
rdr = encode(body[0])
}
req, err := http.NewRequest(method, r.u.String(), rdr)
if err != nil {
panic(err)
}
return req
}
type errorReader struct {
e error
}
func (e errorReader) Read([]byte) (int, error) {
return -1, e.e
}
// encode body as JSON, deferring any errors until io.Reader is used.
func encode(body interface{}) io.Reader {
var b bytes.Buffer
err := json.NewEncoder(&b).Encode(body)
if err != nil {
return errorReader{err}
}
return &b
}

28
vendor/github.com/vmware/govmomi/vapi/rest/BUILD generated vendored Normal file
View File

@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["client.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/vmware/govmomi/vapi/rest",
importpath = "github.com/vmware/govmomi/vapi/rest",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/vmware/govmomi/vapi/internal:go_default_library",
"//vendor/github.com/vmware/govmomi/vim25:go_default_library",
"//vendor/github.com/vmware/govmomi/vim25/soap:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

105
vendor/github.com/vmware/govmomi/vapi/rest/client.go generated vendored Normal file
View File

@ -0,0 +1,105 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
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.
*/
package rest
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
)
// Client extends soap.Client to support JSON encoding, while inheriting security features, debug tracing and session persistence.
type Client struct {
*soap.Client
}
// NewClient creates a new Client instance.
func NewClient(c *vim25.Client) *Client {
sc := c.Client.NewServiceClient(internal.Path, "")
return &Client{sc}
}
// Do sends the http.Request, decoding resBody if provided.
func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{}) error {
switch req.Method {
case http.MethodPost, http.MethodPatch:
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
return c.Client.Do(ctx, req, func(res *http.Response) error {
switch res.StatusCode {
case http.StatusOK:
case http.StatusBadRequest:
// TODO: structured error types
detail, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
return fmt.Errorf("%s: %s", res.Status, bytes.TrimSpace(detail))
default:
return fmt.Errorf("%s %s: %s", req.Method, req.URL, res.Status)
}
if resBody == nil {
return nil
}
switch b := resBody.(type) {
case io.Writer:
_, err := io.Copy(b, res.Body)
return err
default:
val := struct {
Value interface{} `json:"value,omitempty"`
}{
resBody,
}
return json.NewDecoder(res.Body).Decode(&val)
}
})
}
// Login creates a new session via Basic Authentication with the given url.Userinfo.
func (c *Client) Login(ctx context.Context, user *url.Userinfo) error {
req := internal.URL(c, internal.SessionPath).Request(http.MethodPost)
if user != nil {
if password, ok := user.Password(); ok {
req.SetBasicAuth(user.Username(), password)
}
}
return c.Do(ctx, req, nil)
}
// Logout deletes the current session.
func (c *Client) Logout(ctx context.Context) error {
req := internal.URL(c, internal.SessionPath).Request(http.MethodDelete)
return c.Do(ctx, req, nil)
}

29
vendor/github.com/vmware/govmomi/vapi/simulator/BUILD generated vendored Normal file
View File

@ -0,0 +1,29 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["simulator.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/vmware/govmomi/vapi/simulator",
importpath = "github.com/vmware/govmomi/vapi/simulator",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/google/uuid:go_default_library",
"//vendor/github.com/vmware/govmomi/vapi/internal:go_default_library",
"//vendor/github.com/vmware/govmomi/vapi/tags:go_default_library",
"//vendor/github.com/vmware/govmomi/vim25/types:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,354 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
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.
*/
package simulator
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"path"
"reflect"
"strings"
"sync"
"github.com/google/uuid"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vapi/tags"
vim "github.com/vmware/govmomi/vim25/types"
)
type handler struct {
*http.ServeMux
sync.Mutex
Category map[string]*tags.Category
Tag map[string]*tags.Tag
Association map[string]map[internal.AssociatedObject]bool
}
// New creates a vAPI simulator.
func New(u *url.URL, settings []vim.BaseOptionValue) (string, http.Handler) {
s := &handler{
ServeMux: http.NewServeMux(),
Category: make(map[string]*tags.Category),
Tag: make(map[string]*tags.Tag),
Association: make(map[string]map[internal.AssociatedObject]bool),
}
handlers := []struct {
p string
m http.HandlerFunc
}{
{internal.SessionPath, s.session},
{internal.CategoryPath, s.category},
{internal.CategoryPath + "/", s.categoryID},
{internal.TagPath, s.tag},
{internal.TagPath + "/", s.tagID},
{internal.AssociationPath, s.association},
}
for i := range handlers {
h := handlers[i]
s.HandleFunc(internal.Path+h.p, func(w http.ResponseWriter, r *http.Request) {
s.Lock()
defer s.Unlock()
h.m(w, r)
})
}
return internal.Path + "/", s
}
// ok responds with http.StatusOK and json encodes val if given.
func (s *handler) ok(w http.ResponseWriter, val ...interface{}) {
w.WriteHeader(http.StatusOK)
if len(val) == 0 {
return
}
err := json.NewEncoder(w).Encode(struct {
Value interface{} `json:"value,omitempty"`
}{
val[0],
})
if err != nil {
log.Panic(err)
}
}
func (s *handler) fail(w http.ResponseWriter, kind string) {
w.WriteHeader(http.StatusBadRequest)
err := json.NewEncoder(w).Encode(struct {
Type string `json:"type"`
Value struct {
Messages []string `json:"messages,omitempty"`
} `json:"value,omitempty"`
}{
Type: kind,
})
if err != nil {
log.Panic(err)
}
}
// ServeHTTP handles vAPI requests.
func (s *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost, http.MethodDelete, http.MethodGet, http.MethodPatch:
default:
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
h, _ := s.Handler(r)
h.ServeHTTP(w, r)
}
func (s *handler) decode(r *http.Request, w http.ResponseWriter, val interface{}) bool {
defer r.Body.Close()
err := json.NewDecoder(r.Body).Decode(val)
if err != nil {
log.Printf("%s %s: %s", r.Method, r.RequestURI, err)
w.WriteHeader(http.StatusBadRequest)
return false
}
return true
}
func (s *handler) session(w http.ResponseWriter, r *http.Request) {
var id string
switch r.Method {
case http.MethodPost:
id = uuid.New().String()
// TODO: save session
http.SetCookie(w, &http.Cookie{
Name: internal.SessionCookieName,
Value: id,
})
s.ok(w)
case http.MethodDelete:
// TODO: delete session
s.ok(w)
case http.MethodGet:
// TODO: test is session is valid
s.ok(w, id)
}
}
func (s *handler) action(r *http.Request) string {
return r.URL.Query().Get("~action")
}
func (s *handler) id(r *http.Request) string {
id := path.Base(r.URL.Path)
return strings.TrimPrefix(id, "id:")
}
func newID(kind string) string {
return fmt.Sprintf("urn:vmomi:InventoryService%s:%s:GLOBAL", kind, uuid.New().String())
}
func (s *handler) category(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
var spec struct {
Category tags.Category `json:"create_spec"`
}
if s.decode(r, w, &spec) {
for _, category := range s.Category {
if category.Name == spec.Category.Name {
s.fail(w, "com.vmware.vapi.std.errors.already_exists")
return
}
}
id := newID("Category")
spec.Category.ID = id
s.Category[id] = &spec.Category
s.ok(w, id)
}
case http.MethodGet:
var ids []string
for id := range s.Category {
ids = append(ids, id)
}
s.ok(w, ids)
}
}
func (s *handler) categoryID(w http.ResponseWriter, r *http.Request) {
id := s.id(r)
o, ok := s.Category[id]
if !ok {
http.NotFound(w, r)
return
}
switch r.Method {
case http.MethodDelete:
delete(s.Category, id)
for ix, tag := range s.Tag {
if tag.CategoryID == id {
delete(s.Tag, ix)
delete(s.Association, ix)
}
}
s.ok(w)
case http.MethodPatch:
var spec struct {
Category tags.Category `json:"update_spec"`
}
if s.decode(r, w, &spec) {
ntypes := len(spec.Category.AssociableTypes)
if ntypes != 0 {
// Validate that AssociableTypes is only appended to.
etypes := len(o.AssociableTypes)
fail := ntypes < etypes
if !fail {
fail = !reflect.DeepEqual(o.AssociableTypes, spec.Category.AssociableTypes[:etypes])
}
if fail {
s.fail(w, "com.vmware.vapi.std.errors.invalid_argument")
return
}
}
o.Patch(&spec.Category)
s.ok(w)
}
case http.MethodGet:
s.ok(w, o)
}
}
func (s *handler) tag(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
var spec struct {
Tag tags.Tag `json:"create_spec"`
}
if s.decode(r, w, &spec) {
for _, tag := range s.Tag {
if tag.Name == spec.Tag.Name {
s.fail(w, "com.vmware.vapi.std.errors.already_exists")
return
}
}
id := newID("Tag")
spec.Tag.ID = id
s.Tag[id] = &spec.Tag
s.Association[id] = make(map[internal.AssociatedObject]bool)
s.ok(w, id)
}
case http.MethodGet:
var ids []string
for id := range s.Tag {
ids = append(ids, id)
}
s.ok(w, ids)
}
}
func (s *handler) tagID(w http.ResponseWriter, r *http.Request) {
id := s.id(r)
switch s.action(r) {
case "list-tags-for-category":
var ids []string
for _, tag := range s.Tag {
if tag.CategoryID == id {
ids = append(ids, tag.ID)
}
}
s.ok(w, ids)
return
}
o, ok := s.Tag[id]
if !ok {
log.Printf("tag not found: %s", id)
http.NotFound(w, r)
return
}
switch r.Method {
case http.MethodDelete:
delete(s.Tag, id)
delete(s.Association, id)
s.ok(w)
case http.MethodPatch:
var spec struct {
Tag tags.Tag `json:"update_spec"`
}
if s.decode(r, w, &spec) {
o.Patch(&spec.Tag)
s.ok(w)
}
case http.MethodGet:
s.ok(w, o)
}
}
func (s *handler) association(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
var spec internal.Association
if !s.decode(r, w, &spec) {
return
}
if spec.TagID != "" {
if _, exists := s.Association[spec.TagID]; !exists {
log.Printf("association tag not found: %s", spec.TagID)
http.NotFound(w, r)
return
}
}
switch s.action(r) {
case "attach":
s.Association[spec.TagID][*spec.ObjectID] = true
s.ok(w)
case "detach":
delete(s.Association[spec.TagID], *spec.ObjectID)
s.ok(w)
case "list-attached-tags":
var ids []string
for id, objs := range s.Association {
if objs[*spec.ObjectID] {
ids = append(ids, id)
}
}
s.ok(w, ids)
case "list-attached-objects":
var ids []internal.AssociatedObject
for id := range s.Association[spec.TagID] {
ids = append(ids, id)
}
s.ok(w, ids)
}
}

View File

@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
srcs = [
"categories.go",
"rest_client.go",
"tag_association.go",
"tags.go",
],
@ -12,8 +11,9 @@ go_library(
importpath = "github.com/vmware/govmomi/vapi/tags",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/vmware/govmomi/vim25/soap:go_default_library",
"//vendor/github.com/vmware/govmomi/vim25/types:go_default_library",
"//vendor/github.com/vmware/govmomi/vapi/internal:go_default_library",
"//vendor/github.com/vmware/govmomi/vapi/rest:go_default_library",
"//vendor/github.com/vmware/govmomi/vim25/mo:go_default_library",
],
)

View File

@ -1,226 +1,162 @@
// Copyright 2017 VMware, Inc. All Rights Reserved.
//
// 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.
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
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.
*/
package tags
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/vmware/govmomi/vapi/internal"
)
const (
CategoryURL = "/com/vmware/cis/tagging/category"
ErrAlreadyExists = "already_exists"
)
type CategoryCreateSpec struct {
CreateSpec CategoryCreate `json:"create_spec"`
}
type CategoryUpdateSpec struct {
UpdateSpec CategoryUpdate `json:"update_spec,omitempty"`
}
type CategoryCreate struct {
AssociableTypes []string `json:"associable_types"`
Cardinality string `json:"cardinality"`
Description string `json:"description"`
Name string `json:"name"`
}
type CategoryUpdate struct {
AssociableTypes []string `json:"associable_types,omitempty"`
Cardinality string `json:"cardinality,omitempty"`
Description string `json:"description,omitempty"`
Name string `json:"name,omitempty"`
}
// Category provides methods to create, read, update, delete, and enumerate categories.
type Category struct {
ID string `json:"id"`
Description string `json:"description"`
Name string `json:"name"`
Cardinality string `json:"cardinality"`
AssociableTypes []string `json:"associable_types"`
UsedBy []string `json:"used_by"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Cardinality string `json:"cardinality,omitempty"`
AssociableTypes []string `json:"associable_types,omitempty"`
UsedBy []string `json:"used_by,omitempty"`
}
type CategoryInfo struct {
Name string
CategoryID string
}
func (c *RestClient) CreateCategoryIfNotExist(ctx context.Context, name string, description string, categoryType string, multiValue bool) (*string, error) {
categories, err := c.GetCategoriesByName(ctx, name)
if err != nil {
return nil, err
}
if categories == nil {
var multiValueStr string
if multiValue {
multiValueStr = "MULTIPLE"
} else {
multiValueStr = "SINGLE"
func (c *Category) hasType(kind string) bool {
for _, k := range c.AssociableTypes {
if kind == k {
return true
}
categoryCreate := CategoryCreate{[]string{categoryType}, multiValueStr, description, name}
spec := CategoryCreateSpec{categoryCreate}
id, err := c.CreateCategory(ctx, &spec)
}
return false
}
// Patch merges Category changes from the given src.
// AssociableTypes can only be appended to and cannot shrink.
func (c *Category) Patch(src *Category) {
if src.Name != "" {
c.Name = src.Name
}
if src.Description != "" {
c.Description = src.Description
}
if src.Cardinality != "" {
c.Cardinality = src.Cardinality
}
// Note that in order to append to AssociableTypes any existing types must be included in their original order.
for _, kind := range src.AssociableTypes {
if !c.hasType(kind) {
c.AssociableTypes = append(c.AssociableTypes, kind)
}
}
}
// CreateCategory creates a new category and returns the category ID.
func (c *Manager) CreateCategory(ctx context.Context, category *Category) (string, error) {
// create avoids the annoyance of CreateTag requiring field keys to be included in the request,
// even though the field value can be empty.
type create struct {
Name string `json:"name"`
Description string `json:"description"`
Cardinality string `json:"cardinality"`
AssociableTypes []string `json:"associable_types"`
}
spec := struct {
Category create `json:"create_spec"`
}{
Category: create{
Name: category.Name,
Description: category.Description,
Cardinality: category.Cardinality,
AssociableTypes: category.AssociableTypes,
},
}
if spec.Category.AssociableTypes == nil {
// otherwise create fails with invalid_argument
spec.Category.AssociableTypes = []string{}
}
url := internal.URL(c, internal.CategoryPath)
var res string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// UpdateCategory can update one or more of the AssociableTypes, Cardinality, Description and Name fields.
func (c *Manager) UpdateCategory(ctx context.Context, category *Category) error {
spec := struct {
Category Category `json:"update_spec"`
}{
Category: Category{
AssociableTypes: category.AssociableTypes,
Cardinality: category.Cardinality,
Description: category.Description,
Name: category.Name,
},
}
url := internal.URL(c, internal.CategoryPath).WithID(category.ID)
return c.Do(ctx, url.Request(http.MethodPatch, spec), nil)
}
// DeleteCategory deletes an existing category.
func (c *Manager) DeleteCategory(ctx context.Context, category *Category) error {
url := internal.URL(c, internal.CategoryPath).WithID(category.ID)
return c.Do(ctx, url.Request(http.MethodDelete), nil)
}
// GetCategory fetches the category information for the given identifier.
// The id parameter can be a Category ID or Category Name.
func (c *Manager) GetCategory(ctx context.Context, id string) (*Category, error) {
if isName(id) {
cat, err := c.GetCategories(ctx)
if err != nil {
// in case there are two docker daemon try to create inventory category, query the category once again
if strings.Contains(err.Error(), "ErrAlreadyExists") {
if categories, err = c.GetCategoriesByName(ctx, name); err != nil {
return nil, fmt.Errorf("failed to get inventory category for %s", err)
}
} else {
return nil, fmt.Errorf("failed to create inventory category for %s", err)
return nil, err
}
for i := range cat {
if cat[i].Name == id {
return &cat[i], nil
}
} else {
return id, nil
}
}
if categories != nil {
return &categories[0].ID, nil
}
// should not happen
return nil, fmt.Errorf("failed to create inventory for it's existed, but could not query back. Please check system")
url := internal.URL(c, internal.CategoryPath).WithID(id)
var res Category
return &res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
func (c *RestClient) CreateCategory(ctx context.Context, spec *CategoryCreateSpec) (*string, error) {
stream, _, status, err := c.call(ctx, http.MethodPost, CategoryURL, spec, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("create category failed with status code: %d, error message: %s", status, err)
}
type RespValue struct {
Value string
}
var pID RespValue
if err := json.NewDecoder(stream).Decode(&pID); err != nil {
return nil, fmt.Errorf("decode response body failed for: %s", err)
}
return &(pID.Value), nil
// ListCategories returns all category IDs in the system.
func (c *Manager) ListCategories(ctx context.Context) ([]string, error) {
url := internal.URL(c, internal.CategoryPath)
var res []string
return res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
func (c *RestClient) GetCategory(ctx context.Context, id string) (*Category, error) {
stream, _, status, err := c.call(ctx, http.MethodGet, fmt.Sprintf("%s/id:%s", CategoryURL, id), nil, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("get category failed with status code: %d, error message: %s", status, err)
}
type RespValue struct {
Value Category
}
var pCategory RespValue
if err := json.NewDecoder(stream).Decode(&pCategory); err != nil {
return nil, fmt.Errorf("decode response body failed for: %s", err)
}
return &(pCategory.Value), nil
}
func (c *RestClient) UpdateCategory(ctx context.Context, id string, spec *CategoryUpdateSpec) error {
_, _, status, err := c.call(ctx, http.MethodPatch, fmt.Sprintf("%s/id:%s", CategoryURL, id), spec, nil)
if status != http.StatusOK || err != nil {
return fmt.Errorf("update category failed with status code: %d, error message: %s", status, err)
}
return nil
}
func (c *RestClient) DeleteCategory(ctx context.Context, id string) error {
_, _, status, err := c.call(ctx, http.MethodDelete, fmt.Sprintf("%s/id:%s", CategoryURL, id), nil, nil)
if status != http.StatusOK || err != nil {
return fmt.Errorf("delete category failed with status code: %d, error message: %s", status, err)
}
return nil
}
func (c *RestClient) ListCategories(ctx context.Context) ([]string, error) {
stream, _, status, err := c.call(ctx, http.MethodGet, CategoryURL, nil, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("get categories failed with status code: %d, error message: %s", status, err)
}
type Categories struct {
Value []string
}
var pCategories Categories
if err := json.NewDecoder(stream).Decode(&pCategories); err != nil {
return nil, fmt.Errorf("decode response body failed for: %s", err)
}
return pCategories.Value, nil
}
func (c *RestClient) ListCategoriesByName(ctx context.Context) ([]CategoryInfo, error) {
categoryIds, err := c.ListCategories(ctx)
// GetCategories fetches an array of category information in the system.
func (c *Manager) GetCategories(ctx context.Context) ([]Category, error) {
ids, err := c.ListCategories(ctx)
if err != nil {
return nil, fmt.Errorf("get category failed for: %s", err)
}
var categoryInfoSlice []CategoryInfo
for _, cID := range categoryIds {
category, err := c.GetCategory(ctx, cID)
if err != nil {
return nil, fmt.Errorf("get category %s failed for %s", cID, err)
}
categoryCreate := &CategoryInfo{Name: category.Name, CategoryID: category.ID}
categoryInfoSlice = append(categoryInfoSlice, *categoryCreate)
}
return categoryInfoSlice, nil
}
func (c *RestClient) GetCategoriesByName(ctx context.Context, name string) ([]Category, error) {
categoryIds, err := c.ListCategories(ctx)
if err != nil {
return nil, fmt.Errorf("get category failed for: %s", err)
return nil, fmt.Errorf("list categories: %s", err)
}
var categories []Category
for _, cID := range categoryIds {
category, err := c.GetCategory(ctx, cID)
for _, id := range ids {
category, err := c.GetCategory(ctx, id)
if err != nil {
return nil, fmt.Errorf("get category %s failed for %s", cID, err)
}
if category.Name == name {
categories = append(categories, *category)
return nil, fmt.Errorf("get category %s: %s", id, err)
}
categories = append(categories, *category)
}
return categories, nil
}

View File

@ -1,272 +0,0 @@
// Copyright 2017 VMware, Inc. All Rights Reserved.
//
// 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.
package tags
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"sync"
"github.com/vmware/govmomi/vim25/soap"
)
const (
RestPrefix = "/rest"
loginURL = "/com/vmware/cis/session"
sessionIDCookieName = "vmware-api-session-id"
)
type RestClient struct {
mu sync.Mutex
host string
scheme string
endpoint *url.URL
user *url.Userinfo
HTTP *http.Client
cookies []*http.Cookie
}
func NewClient(u *url.URL, insecure bool, thumbprint string) *RestClient {
endpoint := &url.URL{}
*endpoint = *u
endpoint.Path = RestPrefix
// Ignore "#" anchor
endpoint.Fragment = ""
sc := soap.NewClient(endpoint, insecure)
if thumbprint != "" {
sc.SetThumbprint(endpoint.Host, thumbprint)
}
user := endpoint.User
endpoint.User = nil
return &RestClient{
endpoint: endpoint,
user: user,
host: endpoint.Host,
scheme: endpoint.Scheme,
HTTP: &sc.Client,
}
}
// NewClientWithSessionID creates a new REST client with a supplied session ID
// to re-connect to existing sessions.
//
// Note that the session is not checked for validity - to check for a valid
// session after creating the client, use the Valid method. If the session is
// no longer valid and the session needs to be re-saved, Login should be called
// again before calling SessionID to extract the new session ID. Clients
// created with this function function work in the exact same way as clients
// created with NewClient, including supporting re-login on invalid sessions on
// all SDK calls.
func NewClientWithSessionID(u *url.URL, insecure bool, thumbprint string, sessionID string) *RestClient {
c := NewClient(u, insecure, thumbprint)
c.SetSessionID(sessionID)
return c
}
func (c *RestClient) encodeData(data interface{}) (*bytes.Buffer, error) {
params := bytes.NewBuffer(nil)
if data != nil {
if err := json.NewEncoder(params).Encode(data); err != nil {
return nil, err
}
}
return params, nil
}
func (c *RestClient) call(ctx context.Context, method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
// Logger.Debugf("%s: %s, headers: %+v", method, path, headers)
params, err := c.encodeData(data)
if err != nil {
return nil, nil, -1, err
}
if data != nil {
if headers == nil {
headers = make(map[string][]string)
}
headers["Content-Type"] = []string{"application/json"}
}
body, hdr, statusCode, err := c.clientRequest(ctx, method, path, params, headers)
if statusCode == http.StatusUnauthorized && strings.Contains(err.Error(), "This method requires authentication") {
c.Login(ctx)
return c.clientRequest(ctx, method, path, params, headers)
}
return body, hdr, statusCode, err
}
func (c *RestClient) clientRequest(ctx context.Context, method, path string, in io.Reader, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
expectedPayload := (method == http.MethodPost || method == http.MethodPut)
if expectedPayload && in == nil {
in = bytes.NewReader([]byte{})
}
req, err := c.newRequest(method, path, in)
if err != nil {
return nil, nil, -1, err
}
req = req.WithContext(ctx)
c.mu.Lock()
if c.cookies != nil {
req.AddCookie(c.cookies[0])
}
c.mu.Unlock()
if headers != nil {
for k, v := range headers {
req.Header[k] = v
}
}
if expectedPayload && req.Header.Get("Content-Type") == "" {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
resp, err := c.HTTP.Do(req)
return c.handleResponse(resp, err)
}
func (c *RestClient) handleResponse(resp *http.Response, err error) (io.ReadCloser, http.Header, int, error) {
statusCode := -1
if resp != nil {
statusCode = resp.StatusCode
}
if err != nil {
if strings.Contains(err.Error(), "connection refused") {
return nil, nil, statusCode, err
}
return nil, nil, statusCode, err
}
if statusCode < http.StatusOK || statusCode >= http.StatusBadRequest {
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, nil, statusCode, err
}
if len(body) == 0 {
return nil, nil, statusCode, err
}
return nil, nil, statusCode, fmt.Errorf("error response: %s", bytes.TrimSpace(body))
}
return resp.Body, resp.Header, statusCode, nil
}
func (c *RestClient) Login(ctx context.Context) error {
request, err := c.newRequest(http.MethodPost, loginURL, nil)
if err != nil {
return err
}
if c.user != nil {
password, _ := c.user.Password()
request.SetBasicAuth(c.user.Username(), password)
}
resp, err := c.HTTP.Do(request)
if err != nil {
return err
}
if resp == nil {
return err
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
return err
}
c.cookies = resp.Cookies()
return nil
}
func (c *RestClient) Logout(ctx context.Context) error {
_, _, status, err := c.call(ctx, http.MethodDelete, loginURL, nil, nil)
if status != http.StatusOK || err != nil {
return err
}
c.SetSessionID("")
return nil
}
func (c *RestClient) newRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
return http.NewRequest(method, c.endpoint.String()+urlStr, body)
}
// SessionID returns the current session ID of the REST client. An empty string
// means there was no session cookie currently loaded.
func (c *RestClient) SessionID() string {
for _, cookie := range c.cookies {
if cookie.Name == sessionIDCookieName {
return cookie.Value
}
}
return ""
}
// SetSessionID sets the session cookie with the supplied session ID.
//
// This does not necessarily mean the session is valid. The session should be
// checked with Valid before proceeding, and logged back in if it has expired.
//
// This function will overwrite any existing session.
func (c *RestClient) SetSessionID(sessionID string) {
idx := -1
for i, cookie := range c.cookies {
if cookie.Name == sessionIDCookieName {
idx = i
}
}
sessionCookie := &http.Cookie{
Name: sessionIDCookieName,
Value: sessionID,
Path: RestPrefix,
}
if idx > -1 {
c.cookies[idx] = sessionCookie
} else {
c.cookies = append(c.cookies, sessionCookie)
}
}
// Valid checks to see if the session cookies in a REST client are still valid.
// This should be used when restoring a session to determine if a new login is
// necessary.
func (c *RestClient) Valid(ctx context.Context) bool {
_, _, statusCode, err := c.clientRequest(ctx, http.MethodPost, loginURL+"?~action=get", nil, nil)
if err != nil {
return false
}
if statusCode == http.StatusOK {
return true
}
return false
}

View File

@ -1,139 +1,108 @@
// Copyright 2017 VMware, Inc. All Rights Reserved.
//
// 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.
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
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
vUnless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package tags
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vim25/mo"
)
const (
TagAssociationURL = "/com/vmware/cis/tagging/tag-association"
)
type AssociatedObject struct {
ID string `json:"id"`
Type string `json:"type"`
}
type TagAssociationSpec struct {
ObjectID *AssociatedObject `json:"object_id,omitempty"`
TagID *string `json:"tag_id,omitempty"`
}
type AttachedTagsInfo struct {
Name string
TagID string
}
func (c *RestClient) getAssociatedObject(ref *types.ManagedObjectReference) *AssociatedObject {
if ref == nil {
return nil
}
object := AssociatedObject{
ID: ref.Value,
Type: ref.Type,
}
return &object
}
func (c *RestClient) getAssociationSpec(tagID *string, ref *types.ManagedObjectReference) *TagAssociationSpec {
object := c.getAssociatedObject(ref)
spec := TagAssociationSpec{
TagID: tagID,
ObjectID: object,
}
return &spec
}
func (c *RestClient) AttachTagToObject(ctx context.Context, tagID string, ref *types.ManagedObjectReference) error {
spec := c.getAssociationSpec(&tagID, ref)
_, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s?~action=attach", TagAssociationURL), *spec, nil)
if status != http.StatusOK || err != nil {
return fmt.Errorf("attach tag failed with status code: %d, error message: %s", status, err)
}
return nil
}
func (c *RestClient) DetachTagFromObject(ctx context.Context, tagID string, ref *types.ManagedObjectReference) error {
spec := c.getAssociationSpec(&tagID, ref)
_, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s?~action=detach", TagAssociationURL), *spec, nil)
if status != http.StatusOK || err != nil {
return fmt.Errorf("detach tag failed with status code: %d, error message: %s", status, err)
}
return nil
}
func (c *RestClient) ListAttachedTags(ctx context.Context, ref *types.ManagedObjectReference) ([]string, error) {
spec := c.getAssociationSpec(nil, ref)
stream, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s?~action=list-attached-tags", TagAssociationURL), *spec, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("detach tag failed with status code: %d, error message: %s", status, err)
}
type RespValue struct {
Value []string
}
var pTag RespValue
if err := json.NewDecoder(stream).Decode(&pTag); err != nil {
return nil, fmt.Errorf("decode response body failed for: %s", err)
}
return pTag.Value, nil
}
func (c *RestClient) ListAttachedTagsByName(ctx context.Context, ref *types.ManagedObjectReference) ([]AttachedTagsInfo, error) {
tagIds, err := c.ListAttachedTags(ctx, ref)
if err != nil {
return nil, fmt.Errorf("get attached tag failed for: %s", err)
}
var attachedTagsInfoSlice []AttachedTagsInfo
for _, cID := range tagIds {
tag, err := c.GetTag(ctx, cID)
func (c *Manager) tagID(ctx context.Context, id string) (string, error) {
if isName(id) {
tag, err := c.GetTag(ctx, id)
if err != nil {
return nil, fmt.Errorf("get tag %s failed for %s", cID, err)
return "", err
}
attachedTagsCreate := &AttachedTagsInfo{Name: tag.Name, TagID: tag.ID}
attachedTagsInfoSlice = append(attachedTagsInfoSlice, *attachedTagsCreate)
return tag.ID, nil
}
return attachedTagsInfoSlice, nil
return id, nil
}
func (c *RestClient) ListAttachedObjects(ctx context.Context, tagID string) ([]AssociatedObject, error) {
spec := c.getAssociationSpec(&tagID, nil)
stream, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s?~action=list-attached-objects", TagAssociationURL), *spec, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("list object failed with status code: %d, error message: %s", status, err)
// AttachTag attaches a tag ID to a managed object.
func (c *Manager) AttachTag(ctx context.Context, tagID string, ref mo.Reference) error {
id, err := c.tagID(ctx, tagID)
if err != nil {
return err
}
type RespValue struct {
Value []AssociatedObject
}
var pTag RespValue
if err := json.NewDecoder(stream).Decode(&pTag); err != nil {
return nil, fmt.Errorf("decode response body failed for: %s", err)
}
return pTag.Value, nil
spec := internal.NewAssociation(id, ref)
url := internal.URL(c, internal.AssociationPath).WithAction("attach")
return c.Do(ctx, url.Request(http.MethodPost, spec), nil)
}
// DetachTag detaches a tag ID from a managed object.
// If the tag is already removed from the object, then this operation is a no-op and an error will not be thrown.
func (c *Manager) DetachTag(ctx context.Context, tagID string, ref mo.Reference) error {
id, err := c.tagID(ctx, tagID)
if err != nil {
return err
}
spec := internal.NewAssociation(id, ref)
url := internal.URL(c, internal.AssociationPath).WithAction("detach")
return c.Do(ctx, url.Request(http.MethodPost, spec), nil)
}
// ListAttachedTags fetches the array of tag IDs attached to the given object.
func (c *Manager) ListAttachedTags(ctx context.Context, ref mo.Reference) ([]string, error) {
spec := internal.NewAssociation("", ref)
url := internal.URL(c, internal.AssociationPath).WithAction("list-attached-tags")
var res []string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// GetAttachedTags fetches the array of tags attached to the given object.
func (c *Manager) GetAttachedTags(ctx context.Context, ref mo.Reference) ([]Tag, error) {
ids, err := c.ListAttachedTags(ctx, ref)
if err != nil {
return nil, fmt.Errorf("get attached tags %s: %s", ref, err)
}
var info []Tag
for _, id := range ids {
tag, err := c.GetTag(ctx, id)
if err != nil {
return nil, fmt.Errorf("get tag %s: %s", id, err)
}
info = append(info, *tag)
}
return info, nil
}
// ListAttachedObjects fetches the array of attached objects for the given tag ID.
func (c *Manager) ListAttachedObjects(ctx context.Context, tagID string) ([]mo.Reference, error) {
id, err := c.tagID(ctx, tagID)
if err != nil {
return nil, err
}
spec := internal.Association{
TagID: id,
}
url := internal.URL(c, internal.AssociationPath).WithAction("list-attached-objects")
var res []internal.AssociatedObject
if err := c.Do(ctx, url.Request(http.MethodPost, spec), &res); err != nil {
return nil, err
}
refs := make([]mo.Reference, len(res))
for i := range res {
refs[i] = res[i]
}
return refs, nil
}

View File

@ -1,252 +1,202 @@
// Copyright 2017 VMware, Inc. All Rights Reserved.
//
// 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.
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
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.
*/
package tags
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/vmware/govmomi/vapi/internal"
"github.com/vmware/govmomi/vapi/rest"
)
const (
TagURL = "/com/vmware/cis/tagging/tag"
)
type TagCreateSpec struct {
CreateSpec TagCreate `json:"create_spec"`
// Manager extends rest.Client, adding tag related methods.
type Manager struct {
*rest.Client
}
type TagCreate struct {
CategoryID string `json:"category_id"`
Description string `json:"description"`
Name string `json:"name"`
}
type TagUpdateSpec struct {
UpdateSpec TagUpdate `json:"update_spec,omitempty"`
}
type TagUpdate struct {
Description string `json:"description,omitempty"`
Name string `json:"name,omitempty"`
}
type Tag struct {
ID string `json:"id"`
Description string `json:"description"`
Name string `json:"name"`
CategoryID string `json:"category_id"`
UsedBy []string `json:"used_by"`
}
func (c *RestClient) CreateTagIfNotExist(ctx context.Context, name string, description string, categoryID string) (*string, error) {
tagCreate := TagCreate{categoryID, description, name}
spec := TagCreateSpec{tagCreate}
id, err := c.CreateTag(ctx, &spec)
if err == nil {
return id, nil
// NewManager creates a new Manager instance with the given client.
func NewManager(client *rest.Client) *Manager {
return &Manager{
Client: client,
}
// if already exists, query back
if strings.Contains(err.Error(), ErrAlreadyExists) {
tagObjs, err := c.GetTagByNameForCategory(ctx, name, categoryID)
}
// isName returns true if the id is not a urn.
func isName(id string) bool {
return !strings.HasPrefix(id, "urn:")
}
// Tag provides methods to create, read, update, delete, and enumerate tags.
type Tag struct {
ID string `json:"id,omitempty"`
Description string `json:"description,omitempty"`
Name string `json:"name,omitempty"`
CategoryID string `json:"category_id,omitempty"`
UsedBy []string `json:"used_by,omitempty"`
}
// Patch merges updates from the given src.
func (t *Tag) Patch(src *Tag) {
if src.Name != "" {
t.Name = src.Name
}
if src.Description != "" {
t.Description = src.Description
}
if src.CategoryID != "" {
t.CategoryID = src.CategoryID
}
}
// CreateTag creates a new tag with the given Name, Description and CategoryID.
func (c *Manager) CreateTag(ctx context.Context, tag *Tag) (string, error) {
// create avoids the annoyance of CreateTag requiring a "description" key to be included in the request,
// even though the field value can be empty.
type create struct {
Name string `json:"name"`
Description string `json:"description"`
CategoryID string `json:"category_id"`
}
spec := struct {
Tag create `json:"create_spec"`
}{
Tag: create{
Name: tag.Name,
Description: tag.Description,
CategoryID: tag.CategoryID,
},
}
if isName(tag.CategoryID) {
cat, err := c.GetCategory(ctx, tag.CategoryID)
if err != nil {
return "", err
}
spec.Tag.CategoryID = cat.ID
}
url := internal.URL(c, internal.TagPath)
var res string
return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
}
// UpdateTag can update one or both of the tag Description and Name fields.
func (c *Manager) UpdateTag(ctx context.Context, tag *Tag) error {
spec := struct {
Tag Tag `json:"update_spec"`
}{
Tag: Tag{
Name: tag.Name,
Description: tag.Description,
},
}
url := internal.URL(c, internal.TagPath).WithID(tag.ID)
return c.Do(ctx, url.Request(http.MethodPatch, spec), nil)
}
// DeleteTag deletes an existing tag.
func (c *Manager) DeleteTag(ctx context.Context, tag *Tag) error {
url := internal.URL(c, internal.TagPath).WithID(tag.ID)
return c.Do(ctx, url.Request(http.MethodDelete), nil)
}
// GetTag fetches the tag information for the given identifier.
// The id parameter can be a Tag ID or Tag Name.
func (c *Manager) GetTag(ctx context.Context, id string) (*Tag, error) {
if isName(id) {
tags, err := c.GetTags(ctx)
if err != nil {
return nil, err
}
if tagObjs != nil {
return &tagObjs[0].ID, nil
for i := range tags {
if tags[i].Name == id {
return &tags[i], nil
}
}
// should not happen
return nil, fmt.Errorf("failed to create tag for it's existed, but could not query back. Please check system")
}
return nil, fmt.Errorf("created tag failed for %s", err)
url := internal.URL(c, internal.TagPath).WithID(id)
var res Tag
return &res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
func (c *RestClient) DeleteTagIfNoObjectAttached(ctx context.Context, id string) error {
objs, err := c.ListAttachedObjects(ctx, id)
if err != nil {
return err
}
if len(objs) > 0 {
return fmt.Errorf("tag %s related objects is not empty, do not delete it", id)
}
return c.DeleteTag(ctx, id)
// ListTags returns all tag IDs in the system.
func (c *Manager) ListTags(ctx context.Context) ([]string, error) {
url := internal.URL(c, internal.TagPath)
var res []string
return res, c.Do(ctx, url.Request(http.MethodGet), &res)
}
func (c *RestClient) CreateTag(ctx context.Context, spec *TagCreateSpec) (*string, error) {
stream, _, status, err := c.call(ctx, http.MethodPost, TagURL, spec, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("create tag failed with status code: %d, error message: %s", status, err)
}
type RespValue struct {
Value string
}
var pID RespValue
if err := json.NewDecoder(stream).Decode(&pID); err != nil {
return nil, fmt.Errorf("decode response body failed for: %s", err)
}
return &pID.Value, nil
}
func (c *RestClient) GetTag(ctx context.Context, id string) (*Tag, error) {
stream, _, status, err := c.call(ctx, http.MethodGet, fmt.Sprintf("%s/id:%s", TagURL, id), nil, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("get tag failed with status code: %d, error message: %s", status, err)
}
type RespValue struct {
Value Tag
}
var pTag RespValue
if err := json.NewDecoder(stream).Decode(&pTag); err != nil {
return nil, fmt.Errorf("decode response body failed for: %s", err)
}
return &(pTag.Value), nil
}
func (c *RestClient) UpdateTag(ctx context.Context, id string, spec *TagUpdateSpec) error {
_, _, status, err := c.call(ctx, http.MethodPatch, fmt.Sprintf("%s/id:%s", TagURL, id), spec, nil)
if status != http.StatusOK || err != nil {
return fmt.Errorf("update tag failed with status code: %d, error message: %s", status, err)
}
return nil
}
func (c *RestClient) DeleteTag(ctx context.Context, id string) error {
_, _, status, err := c.call(ctx, http.MethodDelete, fmt.Sprintf("%s/id:%s", TagURL, id), nil, nil)
if status != http.StatusOK || err != nil {
return fmt.Errorf("delete tag failed with status code: %d, error message: %s", status, err)
}
return nil
}
func (c *RestClient) ListTags(ctx context.Context) ([]string, error) {
stream, _, status, err := c.call(ctx, http.MethodGet, TagURL, nil, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("get tags failed with status code: %d, error message: %s", status, err)
}
return c.handleTagIDList(stream)
}
type TagsInfo struct {
Name string
TagID string
}
func (c *RestClient) ListTagsByName(ctx context.Context) ([]TagsInfo, error) {
tagIds, err := c.ListTags(ctx)
// GetTags fetches an array of tag information in the system.
func (c *Manager) GetTags(ctx context.Context) ([]Tag, error) {
ids, err := c.ListTags(ctx)
if err != nil {
return nil, fmt.Errorf("get tags failed for: %s", err)
}
var tagsInfoSlice []TagsInfo
for _, cID := range tagIds {
tag, err := c.GetTag(ctx, cID)
if err != nil {
return nil, fmt.Errorf("get category %s failed for %s", cID, err)
}
tagsCreate := &TagsInfo{Name: tag.Name, TagID: tag.ID}
tagsInfoSlice = append(tagsInfoSlice, *tagsCreate)
}
return tagsInfoSlice, nil
}
func (c *RestClient) ListTagsForCategory(ctx context.Context, id string) ([]string, error) {
type PostCategory struct {
ID string `json:"category_id"`
}
spec := PostCategory{id}
stream, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s/id:%s?~action=list-tags-for-category", TagURL, id), spec, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("list tags for category failed with status code: %d, error message: %s", status, err)
}
return c.handleTagIDList(stream)
}
func (c *RestClient) ListTagsInfoForCategory(ctx context.Context, id string) ([]TagsInfo, error) {
type PostCategory struct {
ID string `json:"category_id"`
}
spec := PostCategory{id}
stream, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s/id:%s?~action=list-tags-for-category", TagURL, id), spec, nil)
if status != http.StatusOK || err != nil {
return nil, fmt.Errorf("list tags for category failed with status code: %d, error message: %s", status, err)
}
var tagsInfoSlice []TagsInfo
tmp, err := c.handleTagIDList(stream)
for _, item := range tmp {
tag, err := c.GetTag(ctx, item)
if err != nil {
return nil, fmt.Errorf("get category %s failed for %s", item, err)
}
tagsCreate := &TagsInfo{Name: tag.Name, TagID: tag.ID}
tagsInfoSlice = append(tagsInfoSlice, *tagsCreate)
}
return tagsInfoSlice, nil
}
func (c *RestClient) handleTagIDList(stream io.ReadCloser) ([]string, error) {
type Tags struct {
Value []string
}
var pTags Tags
if err := json.NewDecoder(stream).Decode(&pTags); err != nil {
return nil, fmt.Errorf("decode response body failed for: %s", err)
}
return pTags.Value, nil
}
// Get tag through tag name and category id
func (c *RestClient) GetTagByNameForCategory(ctx context.Context, name string, id string) ([]Tag, error) {
tagIds, err := c.ListTagsForCategory(ctx, id)
if err != nil {
return nil, fmt.Errorf("get tag failed for %s", err)
}
var tags []Tag
for _, tID := range tagIds {
tag, err := c.GetTag(ctx, tID)
for _, id := range ids {
tag, err := c.GetTag(ctx, id)
if err != nil {
return nil, fmt.Errorf("get tag %s failed for %s", tID, err)
}
if tag.Name == name {
tags = append(tags, *tag)
return nil, fmt.Errorf("get category %s failed for %s", id, err)
}
tags = append(tags, *tag)
}
return tags, nil
}
// The id parameter can be a Category ID or Category Name.
func (c *Manager) ListTagsForCategory(ctx context.Context, id string) ([]string, error) {
if isName(id) {
cat, err := c.GetCategory(ctx, id)
if err != nil {
return nil, err
}
id = cat.ID
}
body := struct {
ID string `json:"category_id"`
}{id}
url := internal.URL(c, internal.TagPath).WithID(id).WithAction("list-tags-for-category")
var res []string
return res, c.Do(ctx, url.Request(http.MethodPost, body), &res)
}
// The id parameter can be a Category ID or Category Name.
func (c *Manager) GetTagsForCategory(ctx context.Context, id string) ([]Tag, error) {
ids, err := c.ListTagsForCategory(ctx, id)
if err != nil {
return nil, err
}
var tags []Tag
for _, id := range ids {
tag, err := c.GetTag(ctx, id)
if err != nil {
return nil, fmt.Errorf("get tag %s: %s", id, err)
}
tags = append(tags, *tag)
}
return tags, nil
}

View File

@ -449,12 +449,51 @@ func (c *Client) UnmarshalJSON(b []byte) error {
return nil
}
func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) {
if nil == ctx || nil == ctx.Done() { // ctx.Done() is for ctx
return c.Client.Do(req)
type kindContext struct{}
func (c *Client) Do(ctx context.Context, req *http.Request, f func(*http.Response) error) error {
if ctx == nil {
ctx = context.Background()
}
// Create debugging context for this round trip
d := c.d.newRoundTrip()
if d.enabled() {
defer d.done()
}
return c.Client.Do(req.WithContext(ctx))
if c.UserAgent != "" {
req.Header.Set(`User-Agent`, c.UserAgent)
}
if d.enabled() {
d.debugRequest(req)
}
tstart := time.Now()
res, err := c.Client.Do(req.WithContext(ctx))
tstop := time.Now()
if d.enabled() {
var name string
if kind, ok := ctx.Value(kindContext{}).(HasFault); ok {
name = fmt.Sprintf("%T", kind)
} else {
name = fmt.Sprintf("%s %s", req.Method, req.URL)
}
d.logf("%6dms (%s)", tstop.Sub(tstart)/time.Millisecond, name)
}
if err != nil {
return err
}
defer res.Body.Close()
if d.enabled() {
d.debugResponse(res)
}
return f(res)
}
// Signer can be implemented by soap.Header.Security to sign requests.
@ -493,12 +532,6 @@ func (c *Client) RoundTrip(ctx context.Context, reqBody, resBody HasFault) error
reqEnv.Header = &h // XML marshal header only if a field is set
}
// Create debugging context for this round trip
d := c.d.newRoundTrip()
if d.enabled() {
defer d.done()
}
if signer, ok := h.Security.(Signer); ok {
b, err = signer.Sign(reqEnv)
if err != nil {
@ -517,8 +550,6 @@ func (c *Client) RoundTrip(ctx context.Context, reqBody, resBody HasFault) error
panic(err)
}
req = req.WithContext(ctx)
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
action := h.Action
@ -527,54 +558,29 @@ func (c *Client) RoundTrip(ctx context.Context, reqBody, resBody HasFault) error
}
req.Header.Set(`SOAPAction`, action)
if c.UserAgent != "" {
req.Header.Set(`User-Agent`, c.UserAgent)
}
return c.Do(context.WithValue(ctx, kindContext{}, resBody), req, func(res *http.Response) error {
switch res.StatusCode {
case http.StatusOK:
// OK
case http.StatusInternalServerError:
// Error, but typically includes a body explaining the error
default:
return errors.New(res.Status)
}
if d.enabled() {
d.debugRequest(req)
}
dec := xml.NewDecoder(res.Body)
dec.TypeFunc = types.TypeFunc()
err = dec.Decode(&resEnv)
if err != nil {
return err
}
tstart := time.Now()
res, err := c.do(ctx, req)
tstop := time.Now()
if f := resBody.Fault(); f != nil {
return WrapSoapFault(f)
}
if d.enabled() {
d.logf("%6dms (%T)", tstop.Sub(tstart)/time.Millisecond, resBody)
}
if err != nil {
return err
}
if d.enabled() {
d.debugResponse(res)
}
// Close response regardless of what happens next
defer res.Body.Close()
switch res.StatusCode {
case http.StatusOK:
// OK
case http.StatusInternalServerError:
// Error, but typically includes a body explaining the error
default:
return errors.New(res.Status)
}
dec := xml.NewDecoder(res.Body)
dec.TypeFunc = types.TypeFunc()
err = dec.Decode(&resEnv)
if err != nil {
return err
}
if f := resBody.Fault(); f != nil {
return WrapSoapFault(f)
}
return err
})
}
func (c *Client) CloseIdleConnections() {

View File

@ -21,6 +21,7 @@ import (
"io"
"net/http"
"net/http/httputil"
"strings"
"sync/atomic"
"time"
@ -69,6 +70,14 @@ func (d *debugRoundTrip) newFile(suffix string) io.WriteCloser {
return debug.NewFile(fmt.Sprintf("%d-%04d.%s", d.cn, d.rn, suffix))
}
func (d *debugRoundTrip) ext(h http.Header) string {
ext := "xml"
if strings.Contains(h.Get("Content-Type"), "/json") {
ext = "json"
}
return ext
}
func (d *debugRoundTrip) debugRequest(req *http.Request) {
if d == nil {
return
@ -83,7 +92,7 @@ func (d *debugRoundTrip) debugRequest(req *http.Request) {
wc.Close()
// Capture body
wc = d.newFile("req.xml")
wc = d.newFile("req." + d.ext(req.Header))
req.Body = newTeeReader(req.Body, wc)
// Delay closing until marked done
@ -104,7 +113,7 @@ func (d *debugRoundTrip) debugResponse(res *http.Response) {
wc.Close()
// Capture body
wc = d.newFile("res.xml")
wc = d.newFile("res." + d.ext(res.Header))
res.Body = newTeeReader(res.Body, wc)
// Delay closing until marked done