mirror of https://github.com/k3s-io/k3s
Merge pull request #66795 from jiatongw/zones_vendor
Automatic merge from submit-queue (batch tested with PRs 67052, 67094, 66795). 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>. Add zones support for vSphere cloud provider(in-tree) **What this PR does / why we need it**: This PR added zones(built-in node labels) support for vSphere cloud provider(in-tree). More details can be found in the issue as below. **Which issue(s) this PR fixes** : Partially fixes phase 1 of issue #64021 **Special notes for your reviewer**: **Release note**: ```release-note NONE ```pull/8/head
commit
9d260ff163
|
@ -1036,162 +1036,162 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/distribution/digestset",
|
||||
"Comment": "v2.6.0-rc.1-209-gedc3ab2",
|
||||
"Comment": "v2.6.0-rc.1-209-gedc3ab29",
|
||||
"Rev": "edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/distribution/reference",
|
||||
"Comment": "v2.6.0-rc.1-209-gedc3ab2",
|
||||
"Comment": "v2.6.0-rc.1-209-gedc3ab29",
|
||||
"Rev": "edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/blkiodev",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/container",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/events",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/filters",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/image",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/mount",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/network",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/registry",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/strslice",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/swarm",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/swarm/runtime",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/time",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/versions",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/volume",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/client",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/ioutils",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/jsonlog",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/jsonmessage",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/longpath",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/mount",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/parsers",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/parsers/operatingsystem",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/stdcopy",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/sysinfo",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/system",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/term",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/term/windows",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/tlsconfig",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616f",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-7401-g4f3616fb1",
|
||||
"Rev": "4f3616fb1c112e206b88cb7a9922bf49067a7756"
|
||||
},
|
||||
{
|
||||
|
@ -1216,7 +1216,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/libnetwork/ipvs",
|
||||
"Comment": "v0.8.0-dev.2-910-gba46b92",
|
||||
"Comment": "v0.8.0-dev.2-910-gba46b928",
|
||||
"Rev": "ba46b928444931e6865d8618dc03622cac79aa6f"
|
||||
},
|
||||
{
|
||||
|
@ -1334,132 +1334,132 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/gogoproto",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/compare",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/defaultcheck",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/description",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/embedcheck",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/enumstringer",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/equal",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/face",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/gostring",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/marshalto",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/oneofcheck",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/populate",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/size",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/stringer",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/testgen",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/union",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/unmarshal",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/proto",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/descriptor",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/generator",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/grpc",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/plugin",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/sortkeys",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/types",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/vanity",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/vanity/command",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
|
@ -2358,82 +2358,82 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/apparmor",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/fs",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/systemd",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/configs",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/configs/validate",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/criurpc",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/intelrdt",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/keys",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/mount",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/seccomp",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/stacktrace",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/system",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/user",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/utils",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
|
@ -2673,148 +2673,153 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/find",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/list",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/lookup",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/lookup/methods",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/lookup/simulator",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/lookup/types",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/nfc",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/object",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/pbm",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/pbm/methods",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/pbm/types",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/property",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/session",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/simulator",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/simulator/esx",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/simulator/vpx",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/sts",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/sts/internal",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/sts/simulator",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/task",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vapi/tags",
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vim25",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vim25/debug",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vim25/methods",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vim25/mo",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vim25/progress",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vim25/soap",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vim25/types",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/govmomi/vim25/xml",
|
||||
"Comment": "v0.17.1-46-ge70dd44",
|
||||
"Rev": "e70dd44f80baf671099254d675eb278529038234"
|
||||
"Comment": "v0.18.0-40-gbbd9953",
|
||||
"Rev": "bbd99532a768d2fe369079ceda730e30726ae1a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vmware/photon-controller-go-sdk/SSPI",
|
||||
|
|
|
@ -88165,6 +88165,216 @@ SOFTWARE.
|
|||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/vmware/govmomi/vapi/tags 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/vim25 licensed under: =
|
||||
|
||||
|
|
|
@ -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/tags:go_default_library",
|
||||
"//vendor/github.com/vmware/govmomi/vim25:go_default_library",
|
||||
"//vendor/github.com/vmware/govmomi/vim25/mo:go_default_library",
|
||||
"//vendor/gopkg.in/gcfg.v1:go_default_library",
|
||||
|
|
|
@ -82,6 +82,21 @@ func (dc *Datacenter) GetVMByUUID(ctx context.Context, vmUUID string) (*VirtualM
|
|||
return &virtualMachine, nil
|
||||
}
|
||||
|
||||
// GetHostByVMUUID gets the host object from the given vmUUID
|
||||
func (dc *Datacenter) GetHostByVMUUID(ctx context.Context, vmUUID string) (*types.ManagedObjectReference, error) {
|
||||
virtualMachine, err := dc.GetVMByUUID(ctx, vmUUID)
|
||||
var vmMo mo.VirtualMachine
|
||||
pc := property.DefaultCollector(virtualMachine.Client())
|
||||
err = pc.RetrieveOne(ctx, virtualMachine.Reference(), []string{"summary.runtime.host"}, &vmMo)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to retrive VM runtime host, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
host := vmMo.Summary.Runtime.Host
|
||||
glog.Infof("%s host is %s", virtualMachine.Reference(), host)
|
||||
return host, nil
|
||||
}
|
||||
|
||||
// GetVMByPath gets the VM object from the given vmPath
|
||||
// vmPath should be the full path to VM and not just the name
|
||||
func (dc *Datacenter) GetVMByPath(ctx context.Context, vmPath string) (*VirtualMachine, error) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -33,6 +34,7 @@ import (
|
|||
"gopkg.in/gcfg.v1"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/vmware/govmomi/vapi/tags"
|
||||
"k8s.io/api/core/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/informers"
|
||||
|
@ -177,6 +179,12 @@ type VSphereConfig struct {
|
|||
DefaultDatastore string `gcfg:"default-datastore"`
|
||||
ResourcePoolPath string `gcfg:"resourcepool-path"`
|
||||
}
|
||||
|
||||
// Tag categories and tags which correspond to "built-in node labels: zones and region"
|
||||
Labels struct {
|
||||
Zone string `gcfg:"zone"`
|
||||
Region string `gcfg:"region"`
|
||||
}
|
||||
}
|
||||
|
||||
type Volumes interface {
|
||||
|
@ -808,8 +816,11 @@ func (vs *VSphere) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
|
|||
|
||||
// Zones returns an implementation of Zones for vSphere.
|
||||
func (vs *VSphere) Zones() (cloudprovider.Zones, bool) {
|
||||
glog.V(1).Info("The vSphere cloud provider does not support zones")
|
||||
return nil, false
|
||||
if vs.cfg == nil {
|
||||
glog.V(1).Info("The vSphere cloud provider does not support zones")
|
||||
return nil, false
|
||||
}
|
||||
return vs, true
|
||||
}
|
||||
|
||||
// Routes returns a false since the interface is not supported for vSphere.
|
||||
|
@ -1306,3 +1317,99 @@ 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 {
|
||||
return err
|
||||
}
|
||||
defer c.Logout(ctx)
|
||||
return f(c)
|
||||
}
|
||||
|
||||
// GetZone implements Zones.GetZone
|
||||
func (vs *VSphere) GetZone(ctx context.Context) (cloudprovider.Zone, error) {
|
||||
nodeName, err := vs.CurrentNodeName(ctx, vs.hostName)
|
||||
if err != nil {
|
||||
glog.Errorf("Cannot get node name.")
|
||||
return cloudprovider.Zone{}, err
|
||||
}
|
||||
zone := cloudprovider.Zone{}
|
||||
vsi, err := vs.getVSphereInstanceForServer(vs.cfg.Workspace.VCenterIP, ctx)
|
||||
if err != nil {
|
||||
glog.Errorf("Cannot connent to vsphere. Get zone for node %s error", nodeName)
|
||||
return cloudprovider.Zone{}, err
|
||||
}
|
||||
dc, err := vclib.GetDatacenter(ctx, vsi.conn, vs.cfg.Workspace.Datacenter)
|
||||
if err != nil {
|
||||
glog.Errorf("Cannot connent to datacenter. Get zone for node %s error", nodeName)
|
||||
return cloudprovider.Zone{}, err
|
||||
}
|
||||
vmHost, err := dc.GetHostByVMUUID(ctx, vs.vmUUID)
|
||||
if err != nil {
|
||||
glog.Errorf("Cannot find VM runtime host. Get zone for node %s error", nodeName)
|
||||
return cloudprovider.Zone{}, err
|
||||
}
|
||||
client := vsi.conn
|
||||
err = withTagsClient(ctx, client, func(client *tags.RestClient) error {
|
||||
tags, err := client.ListAttachedTags(ctx, vmHost)
|
||||
if err != nil {
|
||||
glog.Errorf("Cannot list attached tags. Get zone for node %s error", nodeName)
|
||||
return err
|
||||
}
|
||||
for _, value := range tags {
|
||||
tag, err := client.GetTag(ctx, value)
|
||||
if err != nil {
|
||||
glog.Errorf("Get tag %s error", value)
|
||||
return err
|
||||
}
|
||||
category, err := client.GetCategory(ctx, tag.CategoryID)
|
||||
if err != nil {
|
||||
glog.Errorf("Get category %s error", value)
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
|
||||
case category.Name == vs.cfg.Labels.Zone:
|
||||
zone.FailureDomain = tag.Name
|
||||
|
||||
case category.Name == vs.cfg.Labels.Region:
|
||||
zone.Region = tag.Name
|
||||
|
||||
default:
|
||||
zone.FailureDomain = ""
|
||||
zone.Region = ""
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case zone.Region == "":
|
||||
if vs.cfg.Labels.Zone != "" {
|
||||
return fmt.Errorf("The zone in vSphere configuration file not match for node %s ", nodeName)
|
||||
}
|
||||
glog.Infof("No zones support for node %s error", nodeName)
|
||||
return nil
|
||||
case zone.FailureDomain == "":
|
||||
if vs.cfg.Labels.Region != "" {
|
||||
return fmt.Errorf("The zone in vSphere configuration file not match for node %s ", nodeName)
|
||||
}
|
||||
glog.Infof("No zones support for node %s error", nodeName)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
glog.Errorf("Get zone for node %s error", nodeName)
|
||||
return cloudprovider.Zone{}, err
|
||||
}
|
||||
return zone, nil
|
||||
}
|
||||
|
||||
func (vs *VSphere) GetZoneByNodeName(ctx context.Context, nodeName k8stypes.NodeName) (cloudprovider.Zone, error) {
|
||||
return cloudprovider.Zone{}, cloudprovider.NotImplemented
|
||||
}
|
||||
|
||||
func (vs *VSphere) GetZoneByProviderID(ctx context.Context, providerID string) (cloudprovider.Zone, error) {
|
||||
return cloudprovider.Zone{}, cloudprovider.NotImplemented
|
||||
}
|
||||
|
|
|
@ -315,17 +315,21 @@ func TestVSphereLoginWithCaCert(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestZones(t *testing.T) {
|
||||
cfg := VSphereConfig{}
|
||||
cfg.Global.Datacenter = "myDatacenter"
|
||||
|
||||
// Create vSphere configuration object
|
||||
cfg, ok := configFromEnv()
|
||||
vs := VSphere{
|
||||
cfg: &cfg,
|
||||
}
|
||||
|
||||
_, ok := vs.Zones()
|
||||
if ok {
|
||||
t.Fatalf("Zones() returned true")
|
||||
if !ok {
|
||||
t.Skipf("No config found in environment")
|
||||
}
|
||||
_, err := vs.GetZone(context.TODO())
|
||||
if err != nil {
|
||||
t.Fatalf("GetZone() failed: %s", err)
|
||||
}
|
||||
_, ok = vs.Zones()
|
||||
if !ok {
|
||||
t.Fatalf("Zones() returned false")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ Cédric Blomart <cblomart@gmail.com> cedric <cblomart@gmail.com>
|
|||
David Stark <dave@davidstark.name> <david.stark@bskyb.com>
|
||||
Eric Gray <egray@vmware.com> <ericgray@users.noreply.github.com>
|
||||
Eric Yutao <eric.yutao@gmail.com> eric <eric.yutao@gmail.com>
|
||||
Fabio Rapposelli <fabio@vmware.com> <fabio@rapposelli.org>
|
||||
Henrik Hodne <henrik@travis-ci.com> <henrik@hodne.io>
|
||||
Jeremy Canady <jcanady@jackhenry.com> <jcanady@gmail.com>
|
||||
Pieter Noordhuis <pnoordhuis@vmware.com> <pcnoordhuis@gmail.com>
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
sudo: false
|
||||
sudo: required
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- '1.10'
|
||||
go_import_path: github.com/vmware/govmomi
|
||||
|
||||
|
@ -27,4 +25,4 @@ deploy:
|
|||
on:
|
||||
tags: true
|
||||
condition: $TRAVIS_OS_NAME = linux
|
||||
go: '1.10'
|
||||
go: '1.10'
|
||||
|
|
|
@ -37,6 +37,7 @@ 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/tags:all-srcs",
|
||||
"//vendor/github.com/vmware/govmomi/vim25:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
|
|
|
@ -1,5 +1,31 @@
|
|||
# changelog
|
||||
|
||||
### unreleased
|
||||
|
||||
* SetRootCAs on the soap.Client returns an error for invalid certificates
|
||||
|
||||
* Add ClusterComputeResource.MoveInto method
|
||||
|
||||
### 0.18.0 (2018-05-24)
|
||||
|
||||
* Add VirtualDiskManager wrapper to set UUID
|
||||
|
||||
* Add vmxnet2, pcnet32 and sriov to VirtualDeviceList.EthernetCardTypes
|
||||
|
||||
* Add new vSphere 6.7 APIs
|
||||
|
||||
* Decrease LoginExtensionByCertificate tunnel usage
|
||||
|
||||
* SAML token authentication support via SessionManager.LoginByToken
|
||||
|
||||
* New SSO admin client for managing users
|
||||
|
||||
* New STS client for issuing and renewing SAML tokens
|
||||
|
||||
* New Lookup Service client for discovering endpoints such as STS and ssoadmin
|
||||
|
||||
* Switch from gvt to go dep for managing dependencies
|
||||
|
||||
### 0.17.1 (2018-03-19)
|
||||
|
||||
* vcsim: add Destroy method for Folder and Datacenter types
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
Abhijeet Kasurde <akasurde@redhat.com>
|
||||
abrarshivani <abrarshivani@users.noreply.github.com>
|
||||
Adam Shannon <adamkshannon@gmail.com>
|
||||
akutz <sakutz@gmail.com>
|
||||
Alessandro Cortiana <alessandro.cortiana@gmail.com>
|
||||
Alex Bozhenko <alexbozhenko@fb.com>
|
||||
Alvaro Miranda <kikitux@gmail.com>
|
||||
amandahla <amanda.andrade@serpro.gov.br>
|
||||
Amanda H. L. de Andrade <amanda.andrade@serpro.gov.br>
|
||||
Amit Bathla <abathla@.vmware.com>
|
||||
amit bezalel <amit.bezalel@hpe.com>
|
||||
|
@ -23,14 +25,15 @@ bastienbc <bastien.barbe.creuly@gmail.com>
|
|||
Bob Killen <killen.bob@gmail.com>
|
||||
Brad Fitzpatrick <bradfitz@golang.org>
|
||||
Bruce Downs <bruceadowns@gmail.com>
|
||||
Cédric Blomart <cblomart@gmail.com>
|
||||
Chris Marchesi <chrism@vancluevertech.com>
|
||||
Christian Höltje <docwhat@gerf.org>
|
||||
Clint Greenwood <cgreenwood@vmware.com>
|
||||
Cédric Blomart <cblomart@gmail.com>
|
||||
Danny Lockard <danny.lockard@banno.com>
|
||||
Dave Tucker <dave@dtucker.co.uk>
|
||||
David Stark <dave@davidstark.name>
|
||||
Davide Agnello <dagnello@hp.com>
|
||||
David Stark <dave@davidstark.name>
|
||||
Deric Crago <deric.crago@gmail.com>
|
||||
Doug MacEachern <dougm@vmware.com>
|
||||
Eloy Coto <eloy.coto@gmail.com>
|
||||
Eric Gray <egray@vmware.com>
|
||||
|
@ -52,11 +55,14 @@ Jason Kincl <jkincl@gmail.com>
|
|||
Jeremy Canady <jcanady@jackhenry.com>
|
||||
jeremy-clerc <jeremy@clerc.io>
|
||||
João Pereira <joaodrp@gmail.com>
|
||||
Jorge Sevilla <jorge.sevilla@rstor.io>
|
||||
leslie-qiwa <leslie.qiwa@gmail.com>
|
||||
Louie Jiang <jiangl@vmware.com>
|
||||
Marc Carmier <mcarmier@gmail.com>
|
||||
Matthew Cosgrove <matthew.cosgrove@dell.com>
|
||||
Mevan Samaratunga <mevansam@gmail.com>
|
||||
Nicolas Lamirault <nicolas.lamirault@gmail.com>
|
||||
Omar Kohl <omarkohl@gmail.com>
|
||||
Parham Alvani <parham.alvani@gmail.com>
|
||||
Pieter Noordhuis <pnoordhuis@vmware.com>
|
||||
runner.mei <runner.mei@gmail.com>
|
||||
|
|
|
@ -18,7 +18,7 @@ install:
|
|||
go install -v github.com/vmware/govmomi/vcsim
|
||||
|
||||
go-test:
|
||||
go test -race -v $(TEST_OPTS) ./...
|
||||
GORACE=history_size=5 go test -timeout 5m -count 1 -race -v $(TEST_OPTS) ./...
|
||||
|
||||
govc-test: install
|
||||
(cd govc/test && ./vendor/github.com/sstephenson/bats/libexec/bats -t .)
|
||||
|
|
|
@ -15,9 +15,9 @@ In addition to the vSphere API client, this repository includes:
|
|||
|
||||
## Compatibility
|
||||
|
||||
This library is built for and tested against ESXi and vCenter 6.0 and 6.5.
|
||||
This library is built for and tested against ESXi and vCenter 6.0, 6.5 and 6.7.
|
||||
|
||||
It should work with versions 5.5 and 5.1, but neither are officially supported.
|
||||
It may work with versions 5.5 and 5.1, but neither are officially supported.
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
|
@ -68,3 +68,22 @@ func (c ClusterComputeResource) AddHost(ctx context.Context, spec types.HostConn
|
|||
|
||||
return NewTask(c.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
func (c ClusterComputeResource) MoveInto(ctx context.Context, hosts ...*HostSystem) (*Task, error) {
|
||||
req := types.MoveInto_Task{
|
||||
This: c.Reference(),
|
||||
}
|
||||
|
||||
hostReferences := make([]types.ManagedObjectReference, len(hosts))
|
||||
for i, host := range hosts {
|
||||
hostReferences[i] = host.Reference()
|
||||
}
|
||||
req.Host = hostReferences
|
||||
|
||||
res, err := methods.MoveInto_Task(ctx, c.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTask(c.c, res.Returnval), nil
|
||||
}
|
||||
|
|
|
@ -209,3 +209,19 @@ func (m VirtualDiskManager) QueryVirtualDiskUuid(ctx context.Context, name strin
|
|||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
func (m VirtualDiskManager) SetVirtualDiskUuid(ctx context.Context, name string, dc *Datacenter, uuid string) error {
|
||||
req := types.SetVirtualDiskUuid{
|
||||
This: m.Reference(),
|
||||
Name: name,
|
||||
Uuid: uuid,
|
||||
}
|
||||
|
||||
if dc != nil {
|
||||
ref := dc.Reference()
|
||||
req.Datacenter = &ref
|
||||
}
|
||||
|
||||
_, err := methods.SetVirtualDiskUuid(ctx, m.c, &req)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -799,3 +799,16 @@ func (v VirtualMachine) UpgradeVM(ctx context.Context, version string) (*Task, e
|
|||
|
||||
return NewTask(v.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
// UUID is a helper to get the UUID of the VirtualMachine managed object.
|
||||
// This method returns an empty string if an error occurs when retrieving UUID from the VirtualMachine object.
|
||||
func (v VirtualMachine) UUID(ctx context.Context) string {
|
||||
var o mo.VirtualMachine
|
||||
|
||||
err := v.Properties(ctx, v.Reference(), []string{"config.uuid"}, &o)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return o.Config.Uuid
|
||||
}
|
||||
|
|
|
@ -111,6 +111,12 @@ func (p *Collector) WaitForUpdates(ctx context.Context, v string) (*types.Update
|
|||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
func (p *Collector) CancelWaitForUpdates(ctx context.Context) error {
|
||||
req := &types.CancelWaitForUpdates{This: p.Reference()}
|
||||
_, err := methods.CancelWaitForUpdates(ctx, p.roundTripper, req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Collector) RetrieveProperties(ctx context.Context, req types.RetrieveProperties) (*types.RetrievePropertiesResponse, error) {
|
||||
req.This = p.Reference()
|
||||
return methods.RetrieveProperties(ctx, p.roundTripper, &req)
|
||||
|
|
|
@ -19,12 +19,14 @@ package property
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// WaitFilter provides helpers to construct a types.CreateFilter for use with property.Wait
|
||||
type WaitFilter struct {
|
||||
types.CreateFilter
|
||||
Options *types.WaitOptions
|
||||
}
|
||||
|
||||
// Add a new ObjectSpec and PropertySpec to the WaitFilter
|
||||
|
@ -75,6 +77,7 @@ func Wait(ctx context.Context, c *Collector, obj types.ManagedObjectReference, p
|
|||
// creates a new property collector and calls CreateFilter. A new property
|
||||
// collector is required because filters can only be added, not removed.
|
||||
//
|
||||
// If the Context is canceled, a call to CancelWaitForUpdates() is made and its error value is returned.
|
||||
// The newly created collector is destroyed before this function returns (both
|
||||
// in case of success or error).
|
||||
//
|
||||
|
@ -85,7 +88,7 @@ func WaitForUpdates(ctx context.Context, c *Collector, filter *WaitFilter, f fun
|
|||
}
|
||||
|
||||
// Attempt to destroy the collector using the background context, as the
|
||||
// specified context may have timed out or have been cancelled.
|
||||
// specified context may have timed out or have been canceled.
|
||||
defer p.Destroy(context.Background())
|
||||
|
||||
err = p.CreateFilter(ctx, filter.CreateFilter)
|
||||
|
@ -93,20 +96,33 @@ func WaitForUpdates(ctx context.Context, c *Collector, filter *WaitFilter, f fun
|
|||
return err
|
||||
}
|
||||
|
||||
for version := ""; ; {
|
||||
res, err := p.WaitForUpdates(ctx, version)
|
||||
req := types.WaitForUpdatesEx{
|
||||
This: p.Reference(),
|
||||
Options: filter.Options,
|
||||
}
|
||||
|
||||
for {
|
||||
res, err := methods.WaitForUpdatesEx(ctx, p.roundTripper, &req)
|
||||
if err != nil {
|
||||
if ctx.Err() == context.Canceled {
|
||||
werr := p.CancelWaitForUpdates(context.Background())
|
||||
return werr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Retry if the result came back empty
|
||||
if res == nil {
|
||||
set := res.Returnval
|
||||
if set == nil {
|
||||
if req.Options != nil && req.Options.MaxWaitSeconds != nil {
|
||||
return nil // WaitOptions.MaxWaitSeconds exceeded
|
||||
}
|
||||
// Retry if the result came back empty
|
||||
continue
|
||||
}
|
||||
|
||||
version = res.Version
|
||||
req.Version = set.Version
|
||||
|
||||
for _, fs := range res.FilterSet {
|
||||
for _, fs := range set.FilterSet {
|
||||
if f(fs.ObjectSet) {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -106,11 +106,10 @@ func (s *DistributedVirtualSwitch) ReconfigureDvsTask(req *types.ReconfigureDvs_
|
|||
|
||||
switch types.ConfigSpecOperation(member.Operation) {
|
||||
case types.ConfigSpecOperationAdd:
|
||||
if FindReference(host.Network, s.Self) != nil {
|
||||
if FindReference(s.Summary.HostMember, member.Host) != nil {
|
||||
return nil, &types.AlreadyExists{Name: host.Name}
|
||||
}
|
||||
|
||||
Map.AppendReference(host, &host.Network, s.Self)
|
||||
Map.AppendReference(host, &host.Network, s.Portgroup...)
|
||||
s.Summary.HostMember = append(s.Summary.HostMember, member.Host)
|
||||
|
||||
|
@ -129,8 +128,7 @@ func (s *DistributedVirtualSwitch) ReconfigureDvsTask(req *types.ReconfigureDvs_
|
|||
}
|
||||
}
|
||||
|
||||
Map.RemoveReference(host, &host.Network, s.Self)
|
||||
RemoveReference(&s.Summary.HostMember, s.Self)
|
||||
RemoveReference(&s.Summary.HostMember, member.Host)
|
||||
case types.ConfigSpecOperationEdit:
|
||||
return nil, &types.NotSupported{}
|
||||
}
|
||||
|
|
|
@ -161,6 +161,12 @@ var EventInfo = []types.EventDescriptionEventDetail{
|
|||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}} is starting",
|
||||
},
|
||||
{
|
||||
Key: "VmStoppingEvent",
|
||||
Description: "VM stopping",
|
||||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}} is stopping",
|
||||
},
|
||||
{
|
||||
Key: "VmSuspendingEvent",
|
||||
Description: "VM being suspended",
|
||||
|
|
|
@ -157,15 +157,18 @@ func (m *EventManager) PostEvent(ctx *Context, req *types.PostEvent) soap.HasFau
|
|||
event.CreatedTime = time.Now()
|
||||
event.UserName = ctx.Session.UserName
|
||||
|
||||
m.page = m.page.Next()
|
||||
m.page = m.page.Prev()
|
||||
m.page.Value = req.EventToPost
|
||||
m.formatMessage(req.EventToPost)
|
||||
|
||||
for _, c := range m.collectors {
|
||||
if c.eventMatches(req.EventToPost) {
|
||||
c.page = c.page.Next()
|
||||
c.page.Value = event
|
||||
}
|
||||
ctx.WithLock(c, func() {
|
||||
if c.eventMatches(req.EventToPost) {
|
||||
c.page = c.page.Prev()
|
||||
c.page.Value = req.EventToPost
|
||||
Map.Update(c, []types.PropertyChange{{Name: "latestPage", Val: c.GetLatestPage()}})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return &methods.PostEventBody{
|
||||
|
|
|
@ -29,12 +29,10 @@ func (ds *Datastore) stat() error {
|
|||
return err
|
||||
}
|
||||
|
||||
bsize := uint64(stat.Bsize) / 512
|
||||
|
||||
info.FreeSpace = int64(stat.Bfree*bsize) >> 1
|
||||
info.FreeSpace = int64(stat.Bfree * uint64(stat.Bsize))
|
||||
|
||||
ds.Summary.FreeSpace = info.FreeSpace
|
||||
ds.Summary.Capacity = int64(stat.Blocks*bsize) >> 1
|
||||
ds.Summary.Capacity = int64(stat.Blocks * uint64(stat.Bsize))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,11 +17,14 @@ limitations under the License.
|
|||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
|
@ -32,6 +35,11 @@ import (
|
|||
|
||||
type PropertyCollector struct {
|
||||
mo.PropertyCollector
|
||||
|
||||
nopLocker
|
||||
updates []types.ObjectUpdate
|
||||
mu sync.Mutex
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewPropertyCollector(ref types.ManagedObjectReference) object.Reference {
|
||||
|
@ -72,6 +80,10 @@ func getObject(ctx *Context, ref types.ManagedObjectReference) (reflect.Value, b
|
|||
obj = o.Get()
|
||||
}
|
||||
|
||||
return getManagedObject(obj), true
|
||||
}
|
||||
|
||||
func getManagedObject(obj mo.Reference) reflect.Value {
|
||||
rval := reflect.ValueOf(obj).Elem()
|
||||
rtype := rval.Type()
|
||||
|
||||
|
@ -82,26 +94,21 @@ func getObject(ctx *Context, ref types.ManagedObjectReference) (reflect.Value, b
|
|||
// for the case where the type has a field of the same name, for example:
|
||||
// mo.ResourcePool.ResourcePool
|
||||
for {
|
||||
if path.Base(rtype.PkgPath()) != "mo" {
|
||||
if rtype.Kind() != reflect.Struct || rtype.NumField() == 0 {
|
||||
log.Printf("%#v does not have an embedded mo type", ref)
|
||||
return reflect.Value{}, false
|
||||
}
|
||||
rval = rval.Field(0)
|
||||
rtype = rval.Type()
|
||||
} else {
|
||||
if path.Base(rtype.PkgPath()) == "mo" {
|
||||
break
|
||||
}
|
||||
if rtype.Kind() != reflect.Struct || rtype.NumField() == 0 {
|
||||
log.Panicf("%#v does not have an embedded mo type", obj.Reference())
|
||||
}
|
||||
rval = rval.Field(0)
|
||||
rtype = rval.Type()
|
||||
}
|
||||
|
||||
return rval, true
|
||||
return rval
|
||||
}
|
||||
|
||||
func fieldValueInterface(f reflect.StructField, rval reflect.Value) interface{} {
|
||||
if rval.Kind() == reflect.Ptr {
|
||||
rval = rval.Elem()
|
||||
}
|
||||
|
||||
// wrapValue converts slice types to the appropriate ArrayOf type used in property collector responses.
|
||||
func wrapValue(rval reflect.Value, rtype reflect.Type) interface{} {
|
||||
pval := rval.Interface()
|
||||
|
||||
if rval.Kind() == reflect.Slice {
|
||||
|
@ -128,7 +135,7 @@ func fieldValueInterface(f reflect.StructField, rval reflect.Value) interface{}
|
|||
Long: v,
|
||||
}
|
||||
default:
|
||||
kind := f.Type.Elem().Name()
|
||||
kind := rtype.Elem().Name()
|
||||
// Remove govmomi interface prefix name
|
||||
if strings.HasPrefix(kind, "Base") {
|
||||
kind = kind[4:]
|
||||
|
@ -143,6 +150,14 @@ func fieldValueInterface(f reflect.StructField, rval reflect.Value) interface{}
|
|||
return pval
|
||||
}
|
||||
|
||||
func fieldValueInterface(f reflect.StructField, rval reflect.Value) interface{} {
|
||||
if rval.Kind() == reflect.Ptr {
|
||||
rval = rval.Elem()
|
||||
}
|
||||
|
||||
return wrapValue(rval, f.Type)
|
||||
}
|
||||
|
||||
func fieldValue(rval reflect.Value, p string) (interface{}, error) {
|
||||
var value interface{}
|
||||
fields := strings.Split(p, ".")
|
||||
|
@ -401,7 +416,9 @@ func (pc *PropertyCollector) collect(ctx *Context, r *types.RetrievePropertiesEx
|
|||
// Select object references
|
||||
for _, spec := range r.SpecSet {
|
||||
for _, o := range spec.ObjectSet {
|
||||
rval, ok := getObject(ctx, o.Obj)
|
||||
var rval reflect.Value
|
||||
ok := false
|
||||
ctx.WithLock(o.Obj, func() { rval, ok = getObject(ctx, o.Obj) })
|
||||
if !ok {
|
||||
if isFalse(spec.ReportMissingObjectsInResults) {
|
||||
return nil, &types.ManagedObjectNotFound{Obj: o.Obj}
|
||||
|
@ -420,7 +437,7 @@ func (pc *PropertyCollector) collect(ctx *Context, r *types.RetrievePropertiesEx
|
|||
}
|
||||
|
||||
for _, ref := range refs {
|
||||
rr.collect(ctx, ref)
|
||||
ctx.WithLock(ref, func() { rr.collect(ctx, ref) })
|
||||
}
|
||||
|
||||
return rr.RetrieveResult, nil
|
||||
|
@ -429,7 +446,10 @@ func (pc *PropertyCollector) collect(ctx *Context, r *types.RetrievePropertiesEx
|
|||
func (pc *PropertyCollector) CreateFilter(ctx *Context, c *types.CreateFilter) soap.HasFault {
|
||||
body := &methods.CreateFilterBody{}
|
||||
|
||||
filter := &PropertyFilter{pc: pc}
|
||||
filter := &PropertyFilter{
|
||||
pc: pc,
|
||||
refs: make(map[types.ManagedObjectReference]struct{}),
|
||||
}
|
||||
filter.PartialUpdates = c.PartialUpdates
|
||||
filter.Spec = c.Spec
|
||||
|
||||
|
@ -455,14 +475,17 @@ func (pc *PropertyCollector) CreatePropertyCollector(ctx *Context, c *types.Crea
|
|||
}
|
||||
|
||||
func (pc *PropertyCollector) DestroyPropertyCollector(ctx *Context, c *types.DestroyPropertyCollector) soap.HasFault {
|
||||
pc.CancelWaitForUpdates(&types.CancelWaitForUpdates{This: c.This})
|
||||
|
||||
body := &methods.DestroyPropertyCollectorBody{}
|
||||
|
||||
for _, ref := range pc.Filter {
|
||||
filter := ctx.Session.Get(ref).(*PropertyFilter)
|
||||
filter.DestroyPropertyFilter(&types.DestroyPropertyFilter{This: ref})
|
||||
filter.DestroyPropertyFilter(ctx, &types.DestroyPropertyFilter{This: ref})
|
||||
}
|
||||
|
||||
ctx.Session.Remove(c.This)
|
||||
ctx.Map.Remove(c.This)
|
||||
|
||||
body.Res = &types.DestroyPropertyCollectorResponse{}
|
||||
|
||||
|
@ -519,24 +542,46 @@ func (pc *PropertyCollector) RetrieveProperties(ctx *Context, r *types.RetrieveP
|
|||
}
|
||||
|
||||
func (pc *PropertyCollector) CancelWaitForUpdates(r *types.CancelWaitForUpdates) soap.HasFault {
|
||||
pc.mu.Lock()
|
||||
if pc.cancel != nil {
|
||||
pc.cancel()
|
||||
}
|
||||
pc.mu.Unlock()
|
||||
|
||||
return &methods.CancelWaitForUpdatesBody{Res: new(types.CancelWaitForUpdatesResponse)}
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) WaitForUpdatesEx(ctx *Context, r *types.WaitForUpdatesEx) soap.HasFault {
|
||||
body := &methods.WaitForUpdatesExBody{}
|
||||
func (pc *PropertyCollector) update(u types.ObjectUpdate) {
|
||||
pc.mu.Lock()
|
||||
pc.updates = append(pc.updates, u)
|
||||
pc.mu.Unlock()
|
||||
}
|
||||
|
||||
// At the moment we need to support Task completion. Handlers can simply set the Task
|
||||
// state before returning and the non-incremental update is enough for the client.
|
||||
// We can wait for incremental updates to simulate timeouts, etc.
|
||||
if r.Version != "" {
|
||||
body.Fault_ = Fault("incremental updates not supported yet", &types.NotSupported{})
|
||||
return body
|
||||
}
|
||||
func (pc *PropertyCollector) PutObject(o mo.Reference) {
|
||||
pc.update(types.ObjectUpdate{
|
||||
Obj: o.Reference(),
|
||||
Kind: types.ObjectUpdateKindEnter,
|
||||
ChangeSet: nil,
|
||||
})
|
||||
}
|
||||
|
||||
update := &types.UpdateSet{
|
||||
Version: "-",
|
||||
}
|
||||
func (pc *PropertyCollector) UpdateObject(o mo.Reference, changes []types.PropertyChange) {
|
||||
pc.update(types.ObjectUpdate{
|
||||
Obj: o.Reference(),
|
||||
Kind: types.ObjectUpdateKindModify,
|
||||
ChangeSet: changes,
|
||||
})
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) RemoveObject(ref types.ManagedObjectReference) {
|
||||
pc.update(types.ObjectUpdate{
|
||||
Obj: ref,
|
||||
Kind: types.ObjectUpdateKindLeave,
|
||||
ChangeSet: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) apply(ctx *Context, update *types.UpdateSet) types.BaseMethodFault {
|
||||
for _, ref := range pc.Filter {
|
||||
filter := ctx.Session.Get(ref).(*PropertyFilter)
|
||||
|
||||
|
@ -545,8 +590,7 @@ func (pc *PropertyCollector) WaitForUpdatesEx(ctx *Context, r *types.WaitForUpda
|
|||
|
||||
res, fault := pc.collect(ctx, r)
|
||||
if fault != nil {
|
||||
body.Fault_ = Fault("", fault)
|
||||
return body
|
||||
return fault
|
||||
}
|
||||
|
||||
fu := types.PropertyFilterUpdate{
|
||||
|
@ -554,6 +598,10 @@ func (pc *PropertyCollector) WaitForUpdatesEx(ctx *Context, r *types.WaitForUpda
|
|||
}
|
||||
|
||||
for _, o := range res.Objects {
|
||||
if _, ok := filter.refs[o.Obj]; ok {
|
||||
continue
|
||||
}
|
||||
filter.refs[o.Obj] = struct{}{}
|
||||
ou := types.ObjectUpdate{
|
||||
Obj: o.Obj,
|
||||
Kind: types.ObjectUpdateKindEnter,
|
||||
|
@ -570,14 +618,122 @@ func (pc *PropertyCollector) WaitForUpdatesEx(ctx *Context, r *types.WaitForUpda
|
|||
fu.ObjectSet = append(fu.ObjectSet, ou)
|
||||
}
|
||||
|
||||
update.FilterSet = append(update.FilterSet, fu)
|
||||
if len(fu.ObjectSet) != 0 {
|
||||
update.FilterSet = append(update.FilterSet, fu)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) WaitForUpdatesEx(ctx *Context, r *types.WaitForUpdatesEx) soap.HasFault {
|
||||
wait, cancel := context.WithCancel(context.Background())
|
||||
if r.Options != nil {
|
||||
if max := r.Options.MaxWaitSeconds; max != nil {
|
||||
wait, cancel = context.WithTimeout(context.Background(), time.Second*time.Duration(*max))
|
||||
}
|
||||
}
|
||||
pc.mu.Lock()
|
||||
pc.cancel = cancel
|
||||
pc.mu.Unlock()
|
||||
|
||||
body := &methods.WaitForUpdatesExBody{}
|
||||
|
||||
set := &types.UpdateSet{
|
||||
Version: r.Version,
|
||||
}
|
||||
|
||||
body.Res = &types.WaitForUpdatesExResponse{
|
||||
Returnval: update,
|
||||
Returnval: set,
|
||||
}
|
||||
|
||||
return body
|
||||
apply := func() bool {
|
||||
if fault := pc.apply(ctx, set); fault != nil {
|
||||
body.Fault_ = Fault("", fault)
|
||||
body.Res = nil
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if r.Version == "" {
|
||||
apply() // Collect current state
|
||||
set.Version = "-" // Next request with Version set will wait via loop below
|
||||
ctx.Map.AddHandler(pc) // Listen for create, update, delete of managed objects
|
||||
return body
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(250 * time.Millisecond) // allow for updates to accumulate
|
||||
defer ticker.Stop()
|
||||
// Start the wait loop, returning on one of:
|
||||
// - Client calls CancelWaitForUpdates
|
||||
// - MaxWaitSeconds was specified and has been exceeded
|
||||
// - We have updates to send to the client
|
||||
for {
|
||||
select {
|
||||
case <-wait.Done():
|
||||
body.Res.Returnval = nil
|
||||
switch wait.Err() {
|
||||
case context.Canceled:
|
||||
log.Printf("%s: WaitForUpdates canceled", pc.Self)
|
||||
body.Fault_ = Fault("", new(types.RequestCanceled)) // CancelWaitForUpdates was called
|
||||
body.Res = nil
|
||||
case context.DeadlineExceeded:
|
||||
log.Printf("%s: WaitForUpdates MaxWaitSeconds exceeded", pc.Self)
|
||||
}
|
||||
|
||||
return body
|
||||
case <-ticker.C:
|
||||
pc.mu.Lock()
|
||||
updates := pc.updates
|
||||
pc.updates = nil // clear updates collected by the managed object CRUD listeners
|
||||
pc.mu.Unlock()
|
||||
if len(updates) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("%s: applying %d updates to %d filters", pc.Self, len(updates), len(pc.Filter))
|
||||
|
||||
for _, f := range pc.Filter {
|
||||
filter := ctx.Session.Get(f).(*PropertyFilter)
|
||||
fu := types.PropertyFilterUpdate{Filter: f}
|
||||
|
||||
for _, update := range updates {
|
||||
switch update.Kind {
|
||||
case types.ObjectUpdateKindEnter: // Create
|
||||
if !apply() {
|
||||
return body
|
||||
}
|
||||
case types.ObjectUpdateKindModify: // Update
|
||||
log.Printf("%s has %d changes", update.Obj, len(update.ChangeSet))
|
||||
if !apply() { // An update may apply to collector traversal specs
|
||||
return body
|
||||
}
|
||||
if _, ok := filter.refs[update.Obj]; ok {
|
||||
// This object has already been applied by the filter,
|
||||
// now check if the property spec applies for this update.
|
||||
update = filter.apply(ctx, update)
|
||||
if len(update.ChangeSet) != 0 {
|
||||
fu.ObjectSet = append(fu.ObjectSet, update)
|
||||
}
|
||||
}
|
||||
case types.ObjectUpdateKindLeave: // Delete
|
||||
if _, ok := filter.refs[update.Obj]; !ok {
|
||||
continue
|
||||
}
|
||||
delete(filter.refs, update.Obj)
|
||||
fu.ObjectSet = append(fu.ObjectSet, update)
|
||||
}
|
||||
}
|
||||
|
||||
if len(fu.ObjectSet) != 0 {
|
||||
set.FilterSet = append(set.FilterSet, fu)
|
||||
}
|
||||
}
|
||||
if len(set.FilterSet) != 0 {
|
||||
return body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForUpdates is deprecated, but pyvmomi is still using it at the moment.
|
||||
|
|
|
@ -17,6 +17,9 @@ limitations under the License.
|
|||
package simulator
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
|
@ -26,17 +29,71 @@ import (
|
|||
type PropertyFilter struct {
|
||||
mo.PropertyFilter
|
||||
|
||||
pc *PropertyCollector
|
||||
pc *PropertyCollector
|
||||
refs map[types.ManagedObjectReference]struct{}
|
||||
}
|
||||
|
||||
func (f *PropertyFilter) DestroyPropertyFilter(c *types.DestroyPropertyFilter) soap.HasFault {
|
||||
func (f *PropertyFilter) DestroyPropertyFilter(ctx *Context, c *types.DestroyPropertyFilter) soap.HasFault {
|
||||
body := &methods.DestroyPropertyFilterBody{}
|
||||
|
||||
RemoveReference(&f.pc.Filter, c.This)
|
||||
|
||||
Map.Remove(c.This)
|
||||
ctx.Session.Remove(c.This)
|
||||
|
||||
body.Res = &types.DestroyPropertyFilterResponse{}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
// matches returns true if the change matches one of the filter Spec.PropSet
|
||||
func (f *PropertyFilter) matches(ctx *Context, ref types.ManagedObjectReference, change *types.PropertyChange) bool {
|
||||
for _, p := range f.Spec.PropSet {
|
||||
if p.Type != ref.Type {
|
||||
continue
|
||||
}
|
||||
|
||||
if isTrue(p.All) {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, name := range p.PathSet {
|
||||
if name == change.Name {
|
||||
return true
|
||||
}
|
||||
|
||||
// strings.HasPrefix("runtime.powerState", "runtime") == parent field matches
|
||||
if strings.HasPrefix(change.Name, name) {
|
||||
if obj := ctx.Map.Get(ref); obj != nil { // object may have since been deleted
|
||||
change.Name = name
|
||||
change.Val, _ = fieldValue(reflect.ValueOf(obj), name)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// apply the PropertyFilter.Spec to the given ObjectUpdate
|
||||
func (f *PropertyFilter) apply(ctx *Context, change types.ObjectUpdate) types.ObjectUpdate {
|
||||
parents := make(map[string]bool)
|
||||
set := change.ChangeSet
|
||||
change.ChangeSet = nil
|
||||
|
||||
for i, p := range set {
|
||||
if f.matches(ctx, change.Obj, &p) {
|
||||
if p.Name != set[i].Name {
|
||||
// update matches a parent field from the spec.
|
||||
if parents[p.Name] {
|
||||
continue // only return 1 instance of the parent
|
||||
}
|
||||
parents[p.Name] = true
|
||||
}
|
||||
change.ChangeSet = append(change.ChangeSet, p)
|
||||
}
|
||||
}
|
||||
|
||||
return change
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
|
@ -46,10 +47,11 @@ var refValueMap = map[string]string{
|
|||
// Map is the default Registry instance.
|
||||
var Map = NewRegistry()
|
||||
|
||||
// RegisterObject interface supports callbacks when objects are added and removed from the Registry
|
||||
// RegisterObject interface supports callbacks when objects are created, updated and deleted from the Registry
|
||||
type RegisterObject interface {
|
||||
mo.Reference
|
||||
PutObject(mo.Reference)
|
||||
UpdateObject(mo.Reference, []types.PropertyChange)
|
||||
RemoveObject(types.ManagedObjectReference)
|
||||
}
|
||||
|
||||
|
@ -59,7 +61,7 @@ type Registry struct {
|
|||
objects map[types.ManagedObjectReference]mo.Reference
|
||||
handlers map[types.ManagedObjectReference]RegisterObject
|
||||
locks map[types.ManagedObjectReference]sync.Locker
|
||||
counter int
|
||||
counter int64
|
||||
|
||||
Namespace string
|
||||
Path string
|
||||
|
@ -112,8 +114,8 @@ func (r *Registry) newReference(item mo.Reference) types.ManagedObjectReference
|
|||
}
|
||||
|
||||
if ref.Value == "" {
|
||||
r.counter++
|
||||
ref.Value = fmt.Sprintf("%s-%d", valuePrefix(ref.Type), r.counter)
|
||||
n := atomic.AddInt64(&r.counter, 1)
|
||||
ref.Value = fmt.Sprintf("%s-%d", valuePrefix(ref.Type), n)
|
||||
}
|
||||
|
||||
return ref
|
||||
|
@ -126,7 +128,9 @@ func (r *Registry) setReference(item mo.Reference, ref types.ManagedObjectRefere
|
|||
|
||||
// AddHandler adds a RegisterObject handler to the Registry.
|
||||
func (r *Registry) AddHandler(h RegisterObject) {
|
||||
r.m.Lock()
|
||||
r.handlers[h.Reference()] = h
|
||||
r.m.Unlock()
|
||||
}
|
||||
|
||||
// NewEntity sets Entity().Self with a new, unique Value.
|
||||
|
@ -173,10 +177,23 @@ func (r *Registry) Any(kind string) mo.Entity {
|
|||
return nil
|
||||
}
|
||||
|
||||
// applyHandlers calls the given func for each r.handlers
|
||||
func (r *Registry) applyHandlers(f func(o RegisterObject)) {
|
||||
r.m.Lock()
|
||||
handlers := make([]RegisterObject, 0, len(r.handlers))
|
||||
for _, handler := range r.handlers {
|
||||
handlers = append(handlers, handler)
|
||||
}
|
||||
r.m.Unlock()
|
||||
|
||||
for i := range handlers {
|
||||
f(handlers[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Put adds a new object to Registry, generating a ManagedObjectReference if not already set.
|
||||
func (r *Registry) Put(item mo.Reference) mo.Reference {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
ref := item.Reference()
|
||||
if ref.Type == "" || ref.Value == "" {
|
||||
|
@ -192,25 +209,50 @@ func (r *Registry) Put(item mo.Reference) mo.Reference {
|
|||
|
||||
r.objects[ref] = item
|
||||
|
||||
for _, h := range r.handlers {
|
||||
h.PutObject(item)
|
||||
}
|
||||
r.m.Unlock()
|
||||
|
||||
r.applyHandlers(func(o RegisterObject) {
|
||||
o.PutObject(item)
|
||||
})
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
// Remove removes an object from the Registry.
|
||||
func (r *Registry) Remove(item types.ManagedObjectReference) {
|
||||
r.applyHandlers(func(o RegisterObject) {
|
||||
o.RemoveObject(item)
|
||||
})
|
||||
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
for _, h := range r.handlers {
|
||||
h.RemoveObject(item)
|
||||
}
|
||||
|
||||
delete(r.objects, item)
|
||||
delete(r.handlers, item)
|
||||
delete(r.locks, item)
|
||||
r.m.Unlock()
|
||||
}
|
||||
|
||||
// Update dispatches object property changes to RegisterObject handlers,
|
||||
// such as any PropertyCollector instances with in-progress WaitForUpdates calls.
|
||||
// The changes are also applied to the given object via mo.ApplyPropertyChange,
|
||||
// so there is no need to set object fields directly.
|
||||
func (r *Registry) Update(obj mo.Reference, changes []types.PropertyChange) {
|
||||
for i := range changes {
|
||||
if changes[i].Op == "" {
|
||||
changes[i].Op = types.PropertyChangeOpAssign
|
||||
}
|
||||
if changes[i].Val != nil {
|
||||
rval := reflect.ValueOf(changes[i].Val)
|
||||
changes[i].Val = wrapValue(rval, rval.Type())
|
||||
}
|
||||
}
|
||||
|
||||
val := getManagedObject(obj).Addr().Interface().(mo.Reference)
|
||||
|
||||
mo.ApplyPropertyChange(val, changes)
|
||||
|
||||
r.applyHandlers(func(o RegisterObject) {
|
||||
o.UpdateObject(val, changes)
|
||||
})
|
||||
}
|
||||
|
||||
// getEntityParent traverses up the inventory and returns the first object of type kind.
|
||||
|
@ -417,11 +459,23 @@ func (r *Registry) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (r *Registry) locker(obj mo.Reference) sync.Locker {
|
||||
var ref types.ManagedObjectReference
|
||||
|
||||
switch x := obj.(type) {
|
||||
case types.ManagedObjectReference:
|
||||
ref = x
|
||||
obj = r.Get(ref) // to check for sync.Locker
|
||||
case *types.ManagedObjectReference:
|
||||
ref = *x
|
||||
obj = r.Get(ref) // to check for sync.Locker
|
||||
default:
|
||||
ref = obj.Reference()
|
||||
}
|
||||
|
||||
if mu, ok := obj.(sync.Locker); ok {
|
||||
return mu
|
||||
}
|
||||
|
||||
ref := obj.Reference()
|
||||
r.m.Lock()
|
||||
mu, ok := r.locks[ref]
|
||||
if !ok {
|
||||
|
@ -444,3 +498,9 @@ func (r *Registry) WithLock(obj mo.Reference, f func()) {
|
|||
}
|
||||
f()
|
||||
}
|
||||
|
||||
// nopLocker can be embedded to opt-out of auto-locking (see Registry.WithLock)
|
||||
type nopLocker struct{}
|
||||
|
||||
func (*nopLocker) Lock() {}
|
||||
func (*nopLocker) Unlock() {}
|
||||
|
|
|
@ -57,15 +57,18 @@ func (s *SearchIndex) FindByDatastorePath(r *types.FindByDatastorePath) soap.Has
|
|||
func (s *SearchIndex) FindByInventoryPath(req *types.FindByInventoryPath) soap.HasFault {
|
||||
body := &methods.FindByInventoryPathBody{Res: new(types.FindByInventoryPathResponse)}
|
||||
|
||||
path := strings.Split(req.InventoryPath, "/")
|
||||
if len(path) <= 1 {
|
||||
split := func(c rune) bool {
|
||||
return c == '/'
|
||||
}
|
||||
path := strings.FieldsFunc(req.InventoryPath, split)
|
||||
if len(path) < 1 {
|
||||
return body
|
||||
}
|
||||
|
||||
root := Map.content().RootFolder
|
||||
o := &root
|
||||
|
||||
for _, name := range path[1:] {
|
||||
for _, name := range path {
|
||||
f := s.FindChild(&types.FindChild{Entity: *o, Name: name})
|
||||
|
||||
o = f.(*methods.FindChildBody).Res.Returnval
|
||||
|
@ -132,9 +135,16 @@ func (s *SearchIndex) FindByUuid(req *types.FindByUuid) soap.HasFault {
|
|||
if !ok {
|
||||
continue
|
||||
}
|
||||
if vm.Config.Uuid == req.Uuid {
|
||||
body.Res.Returnval = &ref
|
||||
break
|
||||
if req.InstanceUuid != nil && *req.InstanceUuid {
|
||||
if vm.Config.InstanceUuid == req.Uuid {
|
||||
body.Res.Returnval = &ref
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if vm.Config.Uuid == req.Uuid {
|
||||
body.Res.Returnval = &ref
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -138,6 +138,12 @@ func (s *SessionManager) Logout(ctx *Context, _ *types.Logout) soap.HasFault {
|
|||
session := ctx.Session
|
||||
delete(s.sessions, session.Key)
|
||||
|
||||
for ref, obj := range ctx.Session.Registry.objects {
|
||||
if _, ok := obj.(RegisterObject); ok {
|
||||
ctx.Map.Remove(ref) // Remove RegisterObject handlers
|
||||
}
|
||||
}
|
||||
|
||||
ctx.postEvent(&types.UserLogoutSessionEvent{
|
||||
IpAddress: session.IpAddress,
|
||||
UserAgent: session.UserAgent,
|
||||
|
|
|
@ -390,7 +390,7 @@ func (s *Service) findDatastore(query url.Values) (*Datastore, error) {
|
|||
ctx := context.Background()
|
||||
|
||||
finder := find.NewFinder(s.client, false)
|
||||
dc, err := finder.DatacenterOrDefault(ctx, query.Get("dcName"))
|
||||
dc, err := finder.DatacenterOrDefault(ctx, query.Get("dcPath"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -55,18 +55,19 @@ func CreateTask(e mo.Reference, name string, run func(*Task) (types.AnyType, typ
|
|||
Execute: run,
|
||||
}
|
||||
|
||||
Map.Put(task)
|
||||
|
||||
task.Self = Map.newReference(task)
|
||||
task.Info.Key = task.Self.Value
|
||||
task.Info.Task = task.Self
|
||||
task.Info.Name = ucFirst(name)
|
||||
task.Info.DescriptionId = fmt.Sprintf("%s.%s", ref.Type, id)
|
||||
task.Info.Entity = &ref
|
||||
task.Info.EntityName = ref.Value
|
||||
|
||||
task.Info.Reason = &types.TaskReasonUser{UserName: "vcsim"} // TODO: Context.Session.User
|
||||
task.Info.QueueTime = time.Now()
|
||||
task.Info.State = types.TaskInfoStateQueued
|
||||
|
||||
Map.Put(task)
|
||||
|
||||
return task
|
||||
}
|
||||
|
||||
|
@ -78,25 +79,31 @@ type TaskRunner interface {
|
|||
|
||||
func (t *Task) Run() types.ManagedObjectReference {
|
||||
now := time.Now()
|
||||
t.Info.StartTime = &now
|
||||
|
||||
t.Info.State = types.TaskInfoStateRunning
|
||||
Map.Update(t, []types.PropertyChange{
|
||||
{Name: "info.startTime", Val: now},
|
||||
{Name: "info.state", Val: types.TaskInfoStateRunning},
|
||||
})
|
||||
|
||||
res, err := t.Execute(t)
|
||||
|
||||
now = time.Now()
|
||||
t.Info.CompleteTime = &now
|
||||
|
||||
state := types.TaskInfoStateSuccess
|
||||
var fault interface{}
|
||||
if err != nil {
|
||||
t.Info.State = types.TaskInfoStateError
|
||||
t.Info.Error = &types.LocalizedMethodFault{
|
||||
state = types.TaskInfoStateError
|
||||
fault = types.LocalizedMethodFault{
|
||||
Fault: err,
|
||||
LocalizedMessage: fmt.Sprintf("%T", err),
|
||||
}
|
||||
} else {
|
||||
t.Info.Result = res
|
||||
t.Info.State = types.TaskInfoStateSuccess
|
||||
}
|
||||
|
||||
now = time.Now()
|
||||
|
||||
Map.Update(t, []types.PropertyChange{
|
||||
{Name: "info.completeTime", Val: now},
|
||||
{Name: "info.state", Val: state},
|
||||
{Name: "info.result", Val: res},
|
||||
{Name: "info.error", Val: fault},
|
||||
})
|
||||
|
||||
return t.Self
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||
package simulator
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
|
@ -26,6 +28,7 @@ var recentTaskMax = 200 // the VC limit
|
|||
|
||||
type TaskManager struct {
|
||||
mo.TaskManager
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func NewTaskManager(ref types.ManagedObjectReference) object.Reference {
|
||||
|
@ -41,12 +44,16 @@ func (m *TaskManager) PutObject(obj mo.Reference) {
|
|||
return
|
||||
}
|
||||
|
||||
m.RecentTask = append(m.RecentTask, ref)
|
||||
|
||||
if len(m.RecentTask) > recentTaskMax {
|
||||
m.RecentTask = m.RecentTask[1:]
|
||||
m.Lock()
|
||||
recent := append(m.RecentTask, ref)
|
||||
if len(recent) > recentTaskMax {
|
||||
recent = recent[1:]
|
||||
}
|
||||
|
||||
Map.Update(m, []types.PropertyChange{{Name: "recentTask", Val: recent}})
|
||||
m.Unlock()
|
||||
}
|
||||
|
||||
func (m *TaskManager) RemoveObject(_ types.ManagedObjectReference) {
|
||||
}
|
||||
func (*TaskManager) RemoveObject(types.ManagedObjectReference) {}
|
||||
|
||||
func (*TaskManager) UpdateObject(mo.Reference, []types.PropertyChange) {}
|
||||
|
|
|
@ -137,7 +137,8 @@ type ContainerView struct {
|
|||
types map[string]bool
|
||||
}
|
||||
|
||||
func (v *ContainerView) DestroyView(c *types.DestroyView) soap.HasFault {
|
||||
func (v *ContainerView) DestroyView(ctx *Context, c *types.DestroyView) soap.HasFault {
|
||||
ctx.Session.Remove(c.This)
|
||||
return destroyView(c.This)
|
||||
}
|
||||
|
||||
|
@ -192,3 +193,83 @@ func (v *ContainerView) add(root mo.Reference, seen map[types.ManagedObjectRefer
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m *ViewManager) CreateListView(ctx *Context, req *types.CreateListView) soap.HasFault {
|
||||
body := new(methods.CreateListViewBody)
|
||||
list := new(ListView)
|
||||
|
||||
if err := list.add(req.Obj); err != nil {
|
||||
body.Fault_ = Fault("", err)
|
||||
return body
|
||||
}
|
||||
|
||||
ctx.Session.Put(list)
|
||||
|
||||
body.Res = &types.CreateListViewResponse{
|
||||
Returnval: list.Self,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
type ListView struct {
|
||||
mo.ListView
|
||||
}
|
||||
|
||||
func (v *ListView) update() {
|
||||
Map.Update(v, []types.PropertyChange{{Name: "view", Val: v.View}})
|
||||
}
|
||||
|
||||
func (v *ListView) add(refs []types.ManagedObjectReference) *types.ManagedObjectNotFound {
|
||||
for _, ref := range refs {
|
||||
obj := Map.Get(ref)
|
||||
if obj == nil {
|
||||
return &types.ManagedObjectNotFound{Obj: ref}
|
||||
}
|
||||
v.View = append(v.View, ref)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ListView) DestroyView(ctx *Context, c *types.DestroyView) soap.HasFault {
|
||||
ctx.Session.Remove(c.This)
|
||||
return destroyView(c.This)
|
||||
}
|
||||
|
||||
func (v *ListView) ModifyListView(req *types.ModifyListView) soap.HasFault {
|
||||
body := new(methods.ModifyListViewBody)
|
||||
|
||||
for _, ref := range req.Remove {
|
||||
RemoveReference(&v.View, ref)
|
||||
}
|
||||
|
||||
if err := v.add(req.Add); err != nil {
|
||||
body.Fault_ = Fault("", err)
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = new(types.ModifyListViewResponse)
|
||||
|
||||
if len(req.Remove) != 0 || len(req.Add) != 0 {
|
||||
v.update()
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (v *ListView) ResetListView(req *types.ResetListView) soap.HasFault {
|
||||
body := new(methods.ResetListViewBody)
|
||||
|
||||
v.View = nil
|
||||
|
||||
if err := v.add(req.Obj); err != nil {
|
||||
body.Fault_ = Fault("", err)
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = new(types.ResetListViewResponse)
|
||||
|
||||
v.update()
|
||||
|
||||
return body
|
||||
}
|
||||
|
|
|
@ -210,3 +210,10 @@ func (m *VirtualDiskManager) QueryVirtualDiskUuid(req *types.QueryVirtualDiskUui
|
|||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *VirtualDiskManager) SetVirtualDiskUuid(req *types.SetVirtualDiskUuid) soap.HasFault {
|
||||
body := new(methods.SetVirtualDiskUuidBody)
|
||||
// TODO: validate uuid format and persist
|
||||
body.Res = new(types.SetVirtualDiskUuidResponse)
|
||||
return body
|
||||
}
|
||||
|
|
|
@ -444,6 +444,13 @@ func numberToString(n int64, sep rune) string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
func getDiskSize(disk *types.VirtualDisk) int64 {
|
||||
if disk.CapacityInBytes == 0 {
|
||||
return disk.CapacityInKB * 1024
|
||||
}
|
||||
return disk.CapacityInBytes
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, spec *types.VirtualDeviceConfigSpec) types.BaseMethodFault {
|
||||
device := spec.Device
|
||||
d := device.GetVirtualDevice()
|
||||
|
@ -518,9 +525,16 @@ func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, spec
|
|||
p, _ := parseDatastorePath(info.FileName)
|
||||
|
||||
host := Map.Get(*vm.Runtime.Host).(*HostSystem)
|
||||
ds := Map.FindByName(p.Datastore, host.Datastore).Reference()
|
||||
|
||||
info.Datastore = &ds
|
||||
entity := Map.FindByName(p.Datastore, host.Datastore)
|
||||
ref := entity.Reference()
|
||||
info.Datastore = &ref
|
||||
|
||||
ds := entity.(*Datastore)
|
||||
|
||||
// XXX: compare disk size and free space until windows stat is supported
|
||||
ds.Summary.FreeSpace -= getDiskSize(x)
|
||||
ds.Info.GetDatastoreInfo().FreeSpace = ds.Summary.FreeSpace
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,6 +570,15 @@ func (vm *VirtualMachine) removeDevice(devices object.VirtualDeviceList, spec *t
|
|||
switch b := device.Backing.(type) {
|
||||
case types.BaseVirtualDeviceFileBackingInfo:
|
||||
file = b.GetVirtualDeviceFileBackingInfo().FileName
|
||||
|
||||
p, _ := parseDatastorePath(file)
|
||||
|
||||
host := Map.Get(*vm.Runtime.Host).(*HostSystem)
|
||||
|
||||
ds := Map.FindByName(p.Datastore, host.Datastore).(*Datastore)
|
||||
|
||||
ds.Summary.FreeSpace += getDiskSize(device)
|
||||
ds.Info.GetDatastoreInfo().FreeSpace = ds.Summary.FreeSpace
|
||||
}
|
||||
|
||||
if file != "" {
|
||||
|
@ -686,15 +709,9 @@ func (c *powerVMTask) Run(task *Task) (types.AnyType, types.BaseMethodFault) {
|
|||
}
|
||||
}
|
||||
|
||||
c.VirtualMachine.Runtime.PowerState = c.state
|
||||
c.VirtualMachine.Summary.Runtime.PowerState = c.state
|
||||
|
||||
bt := &c.VirtualMachine.Summary.Runtime.BootTime
|
||||
var boot types.AnyType
|
||||
if c.state == types.VirtualMachinePowerStatePoweredOn {
|
||||
now := time.Now()
|
||||
*bt = &now
|
||||
} else {
|
||||
*bt = nil
|
||||
boot = time.Now()
|
||||
}
|
||||
|
||||
event := c.event()
|
||||
|
@ -705,9 +722,23 @@ func (c *powerVMTask) Run(task *Task) (types.AnyType, types.BaseMethodFault) {
|
|||
&types.VmPoweredOnEvent{VmEvent: event},
|
||||
)
|
||||
case types.VirtualMachinePowerStatePoweredOff:
|
||||
c.ctx.postEvent(&types.VmPoweredOffEvent{VmEvent: event})
|
||||
c.ctx.postEvent(
|
||||
&types.VmStoppingEvent{VmEvent: event},
|
||||
&types.VmPoweredOffEvent{VmEvent: event},
|
||||
)
|
||||
case types.VirtualMachinePowerStateSuspended:
|
||||
c.ctx.postEvent(
|
||||
&types.VmSuspendingEvent{VmEvent: event},
|
||||
&types.VmSuspendedEvent{VmEvent: event},
|
||||
)
|
||||
}
|
||||
|
||||
Map.Update(c.VirtualMachine, []types.PropertyChange{
|
||||
{Name: "runtime.powerState", Val: c.state},
|
||||
{Name: "summary.runtime.powerState", Val: c.state},
|
||||
{Name: "summary.runtime.bootTime", Val: boot},
|
||||
})
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
@ -739,6 +770,37 @@ func (vm *VirtualMachine) PowerOffVMTask(ctx *Context, c *types.PowerOffVM_Task)
|
|||
}
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) SuspendVMTask(ctx *Context, req *types.SuspendVM_Task) soap.HasFault {
|
||||
runner := &powerVMTask{vm, types.VirtualMachinePowerStateSuspended, ctx}
|
||||
task := CreateTask(runner.Reference(), "suspend", runner.Run)
|
||||
|
||||
return &methods.SuspendVM_TaskBody{
|
||||
Res: &types.SuspendVM_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) ResetVMTask(ctx *Context, req *types.ResetVM_Task) soap.HasFault {
|
||||
task := CreateTask(vm, "reset", func(task *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
res := vm.PowerOffVMTask(ctx, &types.PowerOffVM_Task{This: vm.Self})
|
||||
ctask := Map.Get(res.(*methods.PowerOffVM_TaskBody).Res.Returnval).(*Task)
|
||||
if ctask.Info.Error != nil {
|
||||
return nil, ctask.Info.Error.Fault
|
||||
}
|
||||
|
||||
_ = vm.PowerOnVMTask(ctx, &types.PowerOnVM_Task{This: vm.Self})
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.ResetVM_TaskBody{
|
||||
Res: &types.ResetVM_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) ReconfigVMTask(ctx *Context, req *types.ReconfigVM_Task) soap.HasFault {
|
||||
task := CreateTask(vm, "reconfigVm", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
err := vm.configure(&req.Spec)
|
||||
|
@ -771,6 +833,11 @@ func (vm *VirtualMachine) DestroyTask(ctx *Context, req *types.Destroy_Task) soa
|
|||
return nil, r.Fault().VimFault().(types.BaseMethodFault)
|
||||
}
|
||||
|
||||
// Remove all devices
|
||||
devices := object.VirtualDeviceList(vm.Config.Hardware.Device)
|
||||
spec, _ := devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationRemove)
|
||||
vm.configureDevices(&types.VirtualMachineConfigSpec{DeviceChange: spec})
|
||||
|
||||
// Delete VM files from the datastore (ignoring result for now)
|
||||
m := Map.FileManager()
|
||||
dc := Map.getEntityDatacenter(vm).Reference()
|
||||
|
@ -907,29 +974,36 @@ func (vm *VirtualMachine) CloneVMTask(ctx *Context, req *types.CloneVM_Task) soa
|
|||
|
||||
func (vm *VirtualMachine) RelocateVMTask(req *types.RelocateVM_Task) soap.HasFault {
|
||||
task := CreateTask(vm, "relocateVm", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
var changes []types.PropertyChange
|
||||
|
||||
if ref := req.Spec.Datastore; ref != nil {
|
||||
ds := Map.Get(*ref).(*Datastore)
|
||||
Map.RemoveReference(ds, &ds.Vm, *ref)
|
||||
|
||||
vm.Datastore = []types.ManagedObjectReference{*ref}
|
||||
|
||||
// TODO: migrate vm.Config.Files (and vm.Summary.Config.VmPathName)
|
||||
|
||||
changes = append(changes, types.PropertyChange{Name: "datastore", Val: []types.ManagedObjectReference{*ref}})
|
||||
}
|
||||
|
||||
if ref := req.Spec.Pool; ref != nil {
|
||||
pool := Map.Get(*ref).(*ResourcePool)
|
||||
Map.RemoveReference(pool, &pool.Vm, *ref)
|
||||
|
||||
vm.ResourcePool = ref
|
||||
changes = append(changes, types.PropertyChange{Name: "resourcePool", Val: *ref})
|
||||
}
|
||||
|
||||
if ref := req.Spec.Host; ref != nil {
|
||||
host := Map.Get(*ref).(*HostSystem)
|
||||
Map.RemoveReference(host, &host.Vm, *ref)
|
||||
|
||||
vm.Runtime.Host = ref
|
||||
changes = append(changes,
|
||||
types.PropertyChange{Name: "runtime.host", Val: *ref},
|
||||
types.PropertyChange{Name: "summary.runtime.host", Val: *ref},
|
||||
)
|
||||
}
|
||||
|
||||
Map.Update(vm, changes)
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
|
@ -1032,7 +1106,7 @@ func (vm *VirtualMachine) RemoveAllSnapshotsTask(req *types.RemoveAllSnapshots_T
|
|||
}
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) ShutdownGuest(c *types.ShutdownGuest) soap.HasFault {
|
||||
func (vm *VirtualMachine) ShutdownGuest(ctx *Context, c *types.ShutdownGuest) soap.HasFault {
|
||||
r := &methods.ShutdownGuestBody{}
|
||||
// should be poweron
|
||||
if vm.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOff {
|
||||
|
@ -1047,6 +1121,17 @@ func (vm *VirtualMachine) ShutdownGuest(c *types.ShutdownGuest) soap.HasFault {
|
|||
vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff
|
||||
vm.Summary.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff
|
||||
|
||||
event := vm.event()
|
||||
ctx.postEvent(
|
||||
&types.VmGuestShutdownEvent{VmEvent: event},
|
||||
&types.VmPoweredOffEvent{VmEvent: event},
|
||||
)
|
||||
|
||||
Map.Update(vm, []types.PropertyChange{
|
||||
{Name: "runtime.powerState", Val: types.VirtualMachinePowerStatePoweredOff},
|
||||
{Name: "summary.runtime.powerState", Val: types.VirtualMachinePowerStatePoweredOff},
|
||||
})
|
||||
|
||||
r.Res = new(types.ShutdownGuestResponse)
|
||||
|
||||
return r
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"categories.go",
|
||||
"rest_client.go",
|
||||
"tag_association.go",
|
||||
"tags.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/vmware/govmomi/vapi/tags",
|
||||
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",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,226 @@
|
|||
// 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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
categoryCreate := CategoryCreate{[]string{categoryType}, multiValueStr, description, name}
|
||||
spec := CategoryCreateSpec{categoryCreate}
|
||||
id, err := c.CreateCategory(ctx, &spec)
|
||||
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)
|
||||
|
||||
}
|
||||
} 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")
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
var categories []Category
|
||||
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)
|
||||
}
|
||||
if category.Name == name {
|
||||
categories = append(categories, *category)
|
||||
}
|
||||
}
|
||||
return categories, nil
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
// 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
|
||||
}
|
139
vendor/github.com/vmware/govmomi/vapi/tags/tag_association.go
generated
vendored
Executable file
139
vendor/github.com/vmware/govmomi/vapi/tags/tag_association.go
generated
vendored
Executable file
|
@ -0,0 +1,139 @@
|
|||
// 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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get tag %s failed for %s", cID, err)
|
||||
}
|
||||
attachedTagsCreate := &AttachedTagsInfo{Name: tag.Name, TagID: tag.ID}
|
||||
attachedTagsInfoSlice = append(attachedTagsInfoSlice, *attachedTagsCreate)
|
||||
}
|
||||
return attachedTagsInfoSlice, 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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
// 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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
TagURL = "/com/vmware/cis/tagging/tag"
|
||||
)
|
||||
|
||||
type TagCreateSpec struct {
|
||||
CreateSpec TagCreate `json:"create_spec"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
// if already exists, query back
|
||||
if strings.Contains(err.Error(), ErrAlreadyExists) {
|
||||
tagObjs, err := c.GetTagByNameForCategory(ctx, name, categoryID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tagObjs != nil {
|
||||
return &tagObjs[0].ID, 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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get tag %s failed for %s", tID, err)
|
||||
}
|
||||
if tag.Name == name {
|
||||
tags = append(tags, *tag)
|
||||
}
|
||||
}
|
||||
return tags, nil
|
||||
}
|
|
@ -28,7 +28,7 @@ import (
|
|||
|
||||
const (
|
||||
Namespace = "vim25"
|
||||
Version = "6.5"
|
||||
Version = "6.7"
|
||||
Path = "/sdk"
|
||||
)
|
||||
|
||||
|
|
|
@ -65,6 +65,22 @@ func ObjectContentToType(o types.ObjectContent) (interface{}, error) {
|
|||
return v.Elem().Interface(), nil
|
||||
}
|
||||
|
||||
// ApplyPropertyChange converts the response of a call to WaitForUpdates
|
||||
// and applies it to the given managed object.
|
||||
func ApplyPropertyChange(obj Reference, changes []types.PropertyChange) {
|
||||
t := typeInfoForType(obj.Reference().Type)
|
||||
v := reflect.ValueOf(obj)
|
||||
|
||||
for _, p := range changes {
|
||||
rv, ok := t.props[p.Name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
assignValue(v, rv, reflect.ValueOf(p.Val))
|
||||
}
|
||||
}
|
||||
|
||||
// LoadRetrievePropertiesResponse converts the response of a call to
|
||||
// RetrieveProperties to one or more managed objects.
|
||||
func LoadRetrievePropertiesResponse(res *types.RetrievePropertiesResponse, dst interface{}) error {
|
||||
|
|
|
@ -155,6 +155,8 @@ func (t *typeInfo) build(typ reflect.Type, fn string, fi []int) {
|
|||
}
|
||||
}
|
||||
|
||||
var nilValue reflect.Value
|
||||
|
||||
// assignValue assignes a value 'pv' to the struct pointed to by 'val', given a
|
||||
// slice of field indices. It recurses into the struct until it finds the field
|
||||
// specified by the indices. It creates new values for pointer types where
|
||||
|
@ -172,6 +174,11 @@ func assignValue(val reflect.Value, fi []int, pv reflect.Value) {
|
|||
rv := val.Field(fi[0])
|
||||
fi = fi[1:]
|
||||
if len(fi) == 0 {
|
||||
if pv == nilValue {
|
||||
pv = reflect.Zero(rv.Type())
|
||||
rv.Set(pv)
|
||||
return
|
||||
}
|
||||
rt := rv.Type()
|
||||
pt := pv.Type()
|
||||
|
||||
|
@ -182,6 +189,24 @@ func assignValue(val reflect.Value, fi []int, pv reflect.Value) {
|
|||
rt = rv.Type()
|
||||
}
|
||||
|
||||
// If the target type is a slice, but the source is not, deference any ArrayOfXYZ type
|
||||
if rt.Kind() == reflect.Slice && pt.Kind() != reflect.Slice {
|
||||
if pt.Kind() == reflect.Ptr {
|
||||
pv = pv.Elem()
|
||||
pt = pt.Elem()
|
||||
}
|
||||
|
||||
m := arrayOfRegexp.FindStringSubmatch(pt.Name())
|
||||
if len(m) > 0 {
|
||||
pv = pv.FieldByName(m[1]) // ArrayOfXYZ type has single field named XYZ
|
||||
pt = pv.Type()
|
||||
|
||||
if !pv.IsValid() {
|
||||
panic(fmt.Sprintf("expected %s type to have field %s", m[0], m[1]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If type is an interface, check if pv implements it.
|
||||
if rt.Kind() == reflect.Interface && !pt.Implements(rt) {
|
||||
// Check if pointer to pv implements it.
|
||||
|
@ -200,7 +225,7 @@ func assignValue(val reflect.Value, fi []int, pv reflect.Value) {
|
|||
} else if rt.ConvertibleTo(pt) {
|
||||
rv.Set(pv.Convert(rt))
|
||||
} else {
|
||||
panic(fmt.Sprintf("cannot assign %s (%s) to %s (%s)", rt.Name(), rt.Kind(), pt.Name(), pt.Kind()))
|
||||
panic(fmt.Sprintf("cannot assign %q (%s) to %q (%s)", rt.Name(), rt.Kind(), pt.Name(), pt.Kind()))
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -211,23 +236,6 @@ func assignValue(val reflect.Value, fi []int, pv reflect.Value) {
|
|||
|
||||
var arrayOfRegexp = regexp.MustCompile("ArrayOf(.*)$")
|
||||
|
||||
func anyTypeToValue(t interface{}) reflect.Value {
|
||||
rt := reflect.TypeOf(t)
|
||||
rv := reflect.ValueOf(t)
|
||||
|
||||
// Dereference if ArrayOfXYZ type
|
||||
m := arrayOfRegexp.FindStringSubmatch(rt.Name())
|
||||
if len(m) > 0 {
|
||||
// ArrayOfXYZ type has single field named XYZ
|
||||
rv = rv.FieldByName(m[1])
|
||||
if !rv.IsValid() {
|
||||
panic(fmt.Sprintf("expected %s type to have field %s", m[0], m[1]))
|
||||
}
|
||||
}
|
||||
|
||||
return rv
|
||||
}
|
||||
|
||||
// LoadObjectFromContent loads properties from the 'PropSet' field in the
|
||||
// specified ObjectContent value into the value it represents, which is
|
||||
// returned as a reflect.Value.
|
||||
|
@ -240,7 +248,7 @@ func (t *typeInfo) LoadFromObjectContent(o types.ObjectContent) (reflect.Value,
|
|||
if !ok {
|
||||
continue
|
||||
}
|
||||
assignValue(v, rv, anyTypeToValue(p.Val))
|
||||
assignValue(v, rv, reflect.ValueOf(p.Val))
|
||||
}
|
||||
|
||||
return v, nil
|
||||
|
|
|
@ -77,6 +77,17 @@ type Client struct {
|
|||
|
||||
var schemeMatch = regexp.MustCompile(`^\w+://`)
|
||||
|
||||
type errInvalidCACertificate struct {
|
||||
File string
|
||||
}
|
||||
|
||||
func (e errInvalidCACertificate) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"invalid certificate '%s', cannot be used as a trusted CA certificate",
|
||||
e.File,
|
||||
)
|
||||
}
|
||||
|
||||
// ParseURL is wrapper around url.Parse, where Scheme defaults to "https" and Path defaults to "/sdk"
|
||||
func ParseURL(s string) (*url.URL, error) {
|
||||
var err error
|
||||
|
@ -200,7 +211,11 @@ func (c *Client) SetRootCAs(file string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
pool.AppendCertsFromPEM(pem)
|
||||
if ok := pool.AppendCertsFromPEM(pem); !ok {
|
||||
return errInvalidCACertificate{
|
||||
File: name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.t.TLSClientConfig.RootCAs = pool
|
||||
|
|
|
@ -39,7 +39,11 @@ func (s soapFaultError) Error() string {
|
|||
msg := s.fault.String
|
||||
|
||||
if msg == "" {
|
||||
msg = reflect.TypeOf(s.fault.Detail.Fault).Name()
|
||||
if s.fault.Detail.Fault == nil {
|
||||
msg = "unknown fault"
|
||||
} else {
|
||||
msg = reflect.TypeOf(s.fault.Detail.Fault).Name()
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s: %s", s.fault.Code, msg)
|
||||
|
|
Loading…
Reference in New Issue