diff --git a/go.mod b/go.mod index e156f07500..9f0583f680 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,7 @@ require ( github.com/golang/protobuf v1.5.4 github.com/golang/snappy v0.0.4 github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.0 github.com/gosnmp/gosnmp v1.35.0 github.com/grafana/loki v1.6.2-0.20210806161513-f5fd02966003 @@ -187,7 +187,7 @@ require ( github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da github.com/google/gnostic v0.6.9 // indirect - github.com/google/go-cmp v0.5.9 + github.com/google/go-cmp v0.6.0 github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/mux v1.8.0 // indirect @@ -367,6 +367,7 @@ require ( github.com/rosedblabs/wal v1.3.6 github.com/sijms/go-ora/v2 v2.8.19 github.com/spf13/cobra v1.5.0 + github.com/vmware/govmomi v0.38.0 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 k8s.io/kubelet v0.0.0-00010101000000-000000000000 ) diff --git a/go.sum b/go.sum index feb924a013..01516ec91f 100644 --- a/go.sum +++ b/go.sum @@ -143,8 +143,6 @@ github.com/DataDog/sketches-go v1.4.1 h1:j5G6as+9FASM2qC36lvpvQAj9qsv/jUs3FtO8Cw github.com/DataDog/sketches-go v1.4.1/go.mod h1:xJIXldczJyyjnbDop7ZZcLxJdV3+7Kra7H1KMgpgkLk= github.com/GuanceCloud/client_model v0.0.0-20230418154757-93bd4e878a5e h1:i34dA4kiRTfG+KdvkIXCLPDduarVeFlQhGDD3TefgS4= github.com/GuanceCloud/client_model v0.0.0-20230418154757-93bd4e878a5e/go.mod h1:PMnE48aPzuRu83FmWZugC0O3d54ZupJd/MmiaYxz8sM= -github.com/GuanceCloud/cliutils v1.1.21-0.20240904042137-2a87297900d6 h1:hXvV/9i3aWkVVnpnHLngbpjZwTU+ut36YxOZOS2J4MM= -github.com/GuanceCloud/cliutils v1.1.21-0.20240904042137-2a87297900d6/go.mod h1:Qbeedf/Ji3immd8Ka01NDQG6SP6j8JBnbZwsHTtxyqs= github.com/GuanceCloud/cliutils v1.1.21 h1:UkENug9Kg4GVTq1ITWIz2KmIPIvpNrZxKKUmRxWWFfA= github.com/GuanceCloud/cliutils v1.1.21/go.mod h1:5bIAZ9yA6l7W8MMUKw0+SIZJRpmEwxM6ZYLy4vweTgU= github.com/GuanceCloud/confd v0.1.101 h1:yjHgfl6YzAlTbFOFMTE4ERpFJzIyovOW7ZFc2/ZssL0= @@ -1175,8 +1173,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -1214,8 +1212,8 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -2079,8 +2077,6 @@ github.com/rosedblabs/wal v1.3.6/go.mod h1:wdq54KJUyVTOv1uddMc6Cdh2d/YCIo8yjcwJA github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -2334,6 +2330,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/vmware/govmomi v0.19.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/vmware/govmomi v0.38.0 h1:UvQpLAOjDpO0JUxoPCXnEzOlEa/9kejO6K58qOFr6cM= +github.com/vmware/govmomi v0.38.0/go.mod h1:mtGWtM+YhTADHlCgJBiskSRPOZRsN9MSjPzaZLte/oQ= github.com/wavefronthq/wavefront-sdk-go v0.9.2/go.mod h1:hQI6y8M9OtTCtc0xdwh+dCER4osxXdEAeCpacjpDZEU= github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= @@ -2959,8 +2957,6 @@ golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -3256,8 +3252,6 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/CodapeWild/dd-trace-go.v1 v1.35.18 h1:RvveUgTvm5M1oOJGIySvMJnKcXbCQ+dTjcTBuQTKbWY= diff --git a/internal/export/dashboard/vsphere/vsphere.json b/internal/export/dashboard/vsphere/vsphere.json new file mode 100644 index 0000000000..af882d59ae --- /dev/null +++ b/internal/export/dashboard/vsphere/vsphere.json @@ -0,0 +1,2460 @@ +{ + "title": "{{.Dashboard.title}}", + "dashboardType": "CUSTOM", + "dashboardExtend": { + "groupUnfoldStatus": { + "Cluster": true, + "Datastores": true, + "ESXi Hosts": true, + "Virtual Machines": true + } + }, + "dashboardMapping": [], + "dashboardOwnerType": "node", + "iconSet": {}, + "dashboardBindSet": [], + "thumbnail": "", + "tagInfo": [], + "summary": "", + "main": { + "vars": [ + { + "name": "vcenter_server", + "seq": 0, + "datasource": "custom_object", + "code": "vcenter_server", + "type": "FIELD", + "definition": { + "tag": "", + "field": "host", + "value": "", + "metric": "", + "object": "vsphere_cluster", + "defaultVal": { + "label": "", + "value": "" + } + }, + "valueSort": "asc", + "hide": 0, + "isHiddenAsterisk": 0, + "multiple": true, + "includeStar": true + }, + { + "name": "cluster_name", + "seq": 1, + "datasource": "ftinfluxdb", + "code": "cluster_name", + "type": "TAG", + "definition": { + "tag": "cluster_name", + "field": "", + "value": "", + "metric": "vsphere_cluster", + "object": "", + "defaultVal": { + "label": "", + "value": "" + } + }, + "valueSort": "asc", + "hide": 0, + "isHiddenAsterisk": 0, + "multiple": true, + "includeStar": true + }, + { + "name": "esx_host", + "seq": 2, + "datasource": "custom_object", + "code": "esx_host", + "type": "FIELD", + "definition": { + "tag": "", + "field": "esx_hostname", + "value": "", + "metric": "", + "object": "vsphere_host", + "defaultVal": { + "label": "", + "value": "" + } + }, + "valueSort": "asc", + "hide": 0, + "isHiddenAsterisk": 0, + "multiple": true, + "includeStar": true + }, + { + "name": "vm_name", + "seq": 3, + "datasource": "ftinfluxdb", + "code": "vm_name", + "type": "TAG", + "definition": { + "tag": "vm_name", + "field": "", + "value": "", + "metric": "vsphere_vm", + "object": "", + "defaultVal": { + "label": "", + "value": "" + } + }, + "valueSort": "asc", + "hide": 0, + "isHiddenAsterisk": 0, + "multiple": true, + "includeStar": true + } + ], + "charts": [ + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "bgColor": "", + "mappings": [], + "showLine": false, + "unitType": "global", + "fixedTime": "", + "fontColor": "", + "lineColor": "#3AB8FF", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "downsample": "last", + "globalUnit": [], + "isSampling": true, + "compareType": "", + "openCompare": false, + "showLineAxis": false, + "timeInterval": "auto", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "singlestat", + "showFieldMapping": false, + "sequenceChartType": "line", + "openThousandsSeparator": true + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": null + }, + "name": "Cluster", + "pos": { + "h": 8, + "w": 6, + "x": 0, + "y": 0 + }, + "type": "singlestat", + "queries": [ + { + "name": "", + "type": "singlestat", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "CO::`vsphere_cluster`:(count(`*`)) { `cluster_name` = '#{cluster_name}' and `host` = '#{vcenter_server}' }", + "code": "A", + "fill": "", + "type": "simple", + "alias": "", + "field": "*", + "search": "", + "filters": [ + { + "id": "4da849c0-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "56ed55c0-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "count", + "fieldType": "keyword", + "namespace": "custom_object", + "dataSource": "vsphere_cluster", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "bgColor": "", + "mappings": [], + "showLine": false, + "unitType": "global", + "fixedTime": "", + "fontColor": "", + "lineColor": "#3AB8FF", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "downsample": "last", + "globalUnit": [], + "isSampling": true, + "compareType": "", + "openCompare": false, + "showLineAxis": false, + "timeInterval": "auto", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "singlestat", + "showFieldMapping": false, + "sequenceChartType": "line", + "openThousandsSeparator": true + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": null + }, + "name": "ESXI", + "pos": { + "h": 8, + "w": 6, + "x": 6, + "y": 0 + }, + "type": "singlestat", + "queries": [ + { + "name": "", + "type": "singlestat", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "CO::`vsphere_host`:(count(`*`)) { `host` = '#{vcenter_server}' and `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' }", + "code": "A", + "fill": "", + "type": "simple", + "alias": "", + "field": "*", + "search": "", + "filters": [ + { + "id": "8d75e800-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + }, + { + "id": "98030460-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "a0e7a0e0-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "count", + "fieldType": "keyword", + "namespace": "custom_object", + "dataSource": "vsphere_host", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "bgColor": "", + "mappings": [], + "showLine": false, + "unitType": "global", + "fixedTime": "", + "fontColor": "", + "lineColor": "#3AB8FF", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "downsample": "last", + "globalUnit": [], + "isSampling": true, + "compareType": "", + "openCompare": false, + "showLineAxis": false, + "timeInterval": "auto", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "singlestat", + "showFieldMapping": false, + "sequenceChartType": "line", + "openThousandsSeparator": true + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": null + }, + "name": "VM", + "pos": { + "h": 8, + "w": 6, + "x": 12, + "y": 0 + }, + "type": "singlestat", + "queries": [ + { + "name": "", + "type": "singlestat", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "CO::`vsphere_vm`:(count(`*`)) { `host` = '#{vcenter_server}' and `cluster_name` = '#{cluster_name}' and `vm_name` = '#{vm_name}' and `esx_hostname` = '#{esx_host}' }", + "code": "A", + "fill": "", + "type": "simple", + "alias": "", + "field": "*", + "search": "", + "filters": [ + { + "id": "af485a80-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + }, + { + "id": "b7a8d2e0-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "bdf426e0-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "vm_name", + "type": "keyword", + "logic": "and", + "value": "#{vm_name}", + "values": [] + }, + { + "id": "c7d2b3c0-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "count", + "fieldType": "keyword", + "namespace": "custom_object", + "dataSource": "vsphere_vm", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "bgColor": "", + "mappings": [], + "showLine": false, + "unitType": "global", + "fixedTime": "", + "fontColor": "", + "lineColor": "#3AB8FF", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "downsample": "last", + "globalUnit": [], + "isSampling": true, + "compareType": "", + "openCompare": false, + "showLineAxis": false, + "timeInterval": "auto", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "singlestat", + "showFieldMapping": false, + "sequenceChartType": "line", + "openThousandsSeparator": true + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": null + }, + "name": "Datastore", + "pos": { + "h": 8, + "w": 6, + "x": 18, + "y": 0 + }, + "type": "singlestat", + "queries": [ + { + "name": "", + "type": "singlestat", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "CO::`vsphere_datastore`:(count(`*`)) { `host` = '#{vcenter_server}' }", + "code": "A", + "fill": "", + "type": "simple", + "alias": "", + "field": "*", + "search": "", + "filters": [ + { + "id": "e1122c30-7a58-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "count", + "fieldType": "keyword", + "namespace": "custom_object", + "dataSource": "vsphere_datastore", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "index": "default", + "units": [], + "colors": [], + "levels": [], + "unitType": "global", + "fixedTime": "", + "inColumns": [ + { + "field": "time", + "headerName": "时间" + } + ], + "showTitle": true, + "titleDesc": "", + "addColumns": [ + { + "hide": true, + "field": "status" + }, + { + "hide": true, + "field": "__docid" + }, + { + "field": "resource_type" + }, + { + "field": "user_name" + }, + { + "field": "event_type_id" + }, + { + "field": "message" + } + ], + "globalUnit": [], + "isSampling": true, + "valMappings": [], + "timeInterval": "", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "log", + "showFieldMapping": false, + "valColorMappings": [] + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": null + }, + "name": "vSphere events", + "pos": { + "h": 17, + "w": 24, + "x": 0, + "y": 8 + }, + "type": "log", + "queries": [ + { + "name": "", + "type": "log", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "L('default')::`vsphere_event`:(`status`, `__docid`, `resource_type`, `user_name`, `event_type_id`, `message`) { `host` = '#{vcenter_server}' and `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' }", + "code": "A", + "fill": null, + "type": "simple", + "alias": "内容", + "field": null, + "fields": [ + { + "hide": true, + "field": "status" + }, + { + "hide": true, + "field": "__docid" + }, + { + "field": "resource_type" + }, + { + "field": "user_name" + }, + { + "field": "event_type_id" + }, + { + "alias": "", + "field": "message", + "isEditAlias": false + } + ], + "filters": [ + { + "id": "c4589640-7a5a-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + }, + { + "id": "d1f340c0-7a5a-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "f77fae00-7a5a-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "count", + "fieldType": "keyword", + "highlight": true, + "namespace": "logging", + "dataSource": "vsphere_event", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "default", + "additionalFields": null, + "disableMultipleField": false + }, + "datasource": "dataflux", + "noTimeRange": false + } + ] + }, + { + "extend": { + "settings": { + "bar": { + "direction": "horizontal", + "xAxisShowType": "groupBy" + }, + "alias": [], + "color": "#498bfe", + "table": { + "queryMode": "toGroupColumn" + }, + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "topSize": 10, + "unitType": "global", + "chartType": "bar", + "fixedTime": "", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "openCompare": false, + "showTopSize": true, + "timeInterval": "auto", + "showTableHead": true, + "tableSortType": "top", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "toplist", + "showFieldMapping": false, + "mainMeasurementSort": "top", + "tableSortMetricName": "", + "mainMeasurementLimit": 20, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "ESXi Hosts" + }, + "name": "CPU usage Top 10", + "pos": { + "h": 10, + "w": 8, + "x": 0, + "y": 0 + }, + "type": "toplist", + "queries": [ + { + "name": "", + "type": "toplist", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_host`:(avg(`cpu_usage_average`)) { `cluster_name` = '#{cluster_name}' and `host` = '#{vcenter_server}' and `esx_hostname` = '#{esx_host}' } BY `esx_hostname`", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "cpu_usage_average", + "filters": [ + { + "id": "cf426050-7a54-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "c24a64d0-7a5c-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + }, + { + "id": "cfe29e50-7a5c-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + } + ], + "groupBy": [ + "esx_hostname" + ], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_host", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "ESXi Hosts" + }, + "name": "CPU usage", + "pos": { + "h": 10, + "w": 8, + "x": 8, + "y": 0 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_host`:(avg(`cpu_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `host` = '#{vcenter_server}' }", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "cpu_usage_average", + "filters": [ + { + "id": "4cd4e340-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "51faca10-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "45605b10-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_host", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "bar": { + "direction": "horizontal", + "xAxisShowType": "groupBy" + }, + "alias": [], + "color": "#498bfe", + "table": { + "queryMode": "toGroupColumn" + }, + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "topSize": 10, + "unitType": "global", + "chartType": "bar", + "fixedTime": "", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "openCompare": false, + "showTopSize": true, + "timeInterval": "auto", + "showTableHead": true, + "tableSortType": "top", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "toplist", + "showFieldMapping": false, + "mainMeasurementSort": "top", + "tableSortMetricName": "", + "mainMeasurementLimit": 20, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "ESXi Hosts" + }, + "name": "Memory usage Top 10", + "pos": { + "h": 10, + "w": 8, + "x": 0, + "y": 10 + }, + "type": "toplist", + "queries": [ + { + "name": "", + "type": "toplist", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_host`:(avg(`mem_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `host` = '#{vcenter_server}' } BY `esx_hostname`", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "mem_usage_average", + "filters": [ + { + "id": "d4d8c390-7a51-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "da2e6cf0-7a51-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "59ba9f30-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [ + "esx_hostname" + ], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_host", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "ESXi Hosts" + }, + "name": "Memory usage", + "pos": { + "h": 10, + "w": 8, + "x": 8, + "y": 10 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_host`:(avg(`mem_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `host` = '#{vcenter_server}' }", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "mem_usage_average", + "filters": [ + { + "id": "4cd4e340-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "51faca10-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "646be560-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_host", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [ + "traffic", + "KB/S" + ], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "ESXi Hosts" + }, + "name": "Network utilization", + "pos": { + "h": 10, + "w": 8, + "x": 16, + "y": 0 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_host`:(avg(`net_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `host` = '#{vcenter_server}' }", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "net_usage_average", + "filters": [ + { + "id": "4cd4e340-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "51faca10-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "4edfff10-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_host", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [ + "digital", + "KB" + ], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "ESXi Hosts" + }, + "name": "Disk read", + "pos": { + "h": 10, + "w": 8, + "x": 16, + "y": 10 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_host`:(avg(`disk_read_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `host` = '#{vcenter_server}' }", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "disk_read_average", + "filters": [ + { + "id": "4cd4e340-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "51faca10-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "6e4a4b30-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_host", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "bar": { + "direction": "horizontal", + "xAxisShowType": "groupBy" + }, + "alias": [], + "color": "#498bfe", + "table": { + "queryMode": "toGroupColumn" + }, + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "topSize": 10, + "unitType": "global", + "chartType": "bar", + "fixedTime": "", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "openCompare": false, + "showTopSize": true, + "timeInterval": "auto", + "showTableHead": true, + "tableSortType": "top", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "toplist", + "showFieldMapping": false, + "mainMeasurementSort": "top", + "tableSortMetricName": "", + "mainMeasurementLimit": 20, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Virtual Machines" + }, + "name": "CPU usage Top 10", + "pos": { + "h": 10, + "w": 8, + "x": 0, + "y": 0 + }, + "type": "toplist", + "queries": [ + { + "name": "", + "type": "toplist", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_vm`:(avg(`cpu_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `vm_name` = '#{vm_name}' and `host` = '#{vcenter_server}' } BY `vm_name`", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "cpu_usage_average", + "filters": [ + { + "id": "b7285510-7a54-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "bbc005a0-7a54-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "c26c1740-7a54-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "vm_name", + "type": "keyword", + "logic": "and", + "value": "#{vm_name}", + "values": [] + }, + { + "id": "7b765560-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [ + "vm_name" + ], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_vm", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Virtual Machines" + }, + "name": "CPU usage", + "pos": { + "h": 10, + "w": 8, + "x": 8, + "y": 0 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_vm`:(avg(`cpu_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `vm_name` = '#{vm_name}' and `host` = '#{vcenter_server}' }", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "cpu_usage_average", + "filters": [ + { + "id": "4cd4e340-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "51faca10-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "9d1deb80-7a54-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "vm_name", + "type": "keyword", + "logic": "and", + "value": "#{vm_name}", + "values": [] + }, + { + "id": "83eee9a0-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_vm", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "bar": { + "direction": "horizontal", + "xAxisShowType": "groupBy" + }, + "alias": [], + "color": "#498bfe", + "table": { + "queryMode": "toGroupColumn" + }, + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "topSize": 10, + "unitType": "global", + "chartType": "bar", + "fixedTime": "", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "openCompare": false, + "showTopSize": true, + "timeInterval": "auto", + "showTableHead": true, + "tableSortType": "top", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "toplist", + "showFieldMapping": false, + "mainMeasurementSort": "top", + "tableSortMetricName": "", + "mainMeasurementLimit": 10, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Virtual Machines" + }, + "name": "Memory usage Top 10", + "pos": { + "h": 10, + "w": 8, + "x": 0, + "y": 10 + }, + "type": "toplist", + "queries": [ + { + "name": "", + "type": "toplist", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_vm`:(avg(`mem_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `vm_name` = '#{vm_name}' and `host` = '#{vcenter_server}' } BY `vm_name`", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "mem_usage_average", + "filters": [ + { + "id": "d4d8c390-7a51-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "da2e6cf0-7a51-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "21cd0d70-7a55-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "vm_name", + "type": "keyword", + "logic": "and", + "value": "#{vm_name}", + "values": [] + }, + { + "id": "9395dee0-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [ + "vm_name" + ], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_vm", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Virtual Machines" + }, + "name": "Memory usage", + "pos": { + "h": 10, + "w": 8, + "x": 8, + "y": 10 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_vm`:(avg(`mem_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `vm_name` = '#{vm_name}' and `host` = '#{vcenter_server}' }", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "mem_usage_average", + "filters": [ + { + "id": "4cd4e340-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "51faca10-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "3efc5db0-7a55-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "vm_name", + "type": "keyword", + "logic": "and", + "value": "#{vm_name}", + "values": [] + }, + { + "id": "9e945ab0-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_vm", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [ + "traffic", + "KB/S" + ], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Virtual Machines" + }, + "name": "Network utilization", + "pos": { + "h": 10, + "w": 8, + "x": 16, + "y": 0 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_vm`:(avg(`mem_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `vm_name` = '#{vm_name}' and `host` = '#{vcenter_server}' }", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "mem_usage_average", + "filters": [ + { + "id": "4cd4e340-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "51faca10-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "4ed07d70-7a55-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "vm_name", + "type": "keyword", + "logic": "and", + "value": "#{vm_name}", + "values": [] + }, + { + "id": "8be22140-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_vm", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [ + "traffic", + "KB/S" + ], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Virtual Machines" + }, + "name": "Disk I/O rates", + "pos": { + "h": 10, + "w": 8, + "x": 16, + "y": 10 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_vm`:(avg(`disk_usage_average`)) { `cluster_name` = '#{cluster_name}' and `esx_hostname` = '#{esx_host}' and `vm_name` = '#{vm_name}' and `host` = '#{vcenter_server}' } BY `vm_name`", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "disk_usage_average", + "filters": [ + { + "id": "4cd4e340-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "cluster_name", + "type": "keyword", + "logic": "and", + "value": "#{cluster_name}", + "values": [] + }, + { + "id": "51faca10-7a4f-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "esx_hostname", + "type": "keyword", + "logic": "and", + "value": "#{esx_host}", + "values": [] + }, + { + "id": "779643c0-7a55-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "vm_name", + "type": "keyword", + "logic": "and", + "value": "#{vm_name}", + "values": [] + }, + { + "id": "a62cef30-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [ + "vm_name" + ], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_vm", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "bar": { + "direction": "horizontal", + "xAxisShowType": "groupBy" + }, + "alias": [], + "color": "#498bfe", + "table": { + "queryMode": "toGroupColumn" + }, + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "topSize": 10, + "unitType": "global", + "chartType": "bar", + "fixedTime": "", + "precision": "2", + "showTitle": true, + "titleDesc": "", + "globalUnit": [ + "percent", + "percent" + ], + "isSampling": true, + "openCompare": false, + "showTopSize": true, + "timeInterval": "auto", + "showTableHead": true, + "tableSortType": "top", + "isTimeInterval": false, + "changeWorkspace": false, + "currentChartType": "toplist", + "showFieldMapping": false, + "mainMeasurementSort": "top", + "tableSortMetricName": "", + "mainMeasurementLimit": 20, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Datastores" + }, + "name": "Used space percent", + "pos": { + "h": 10, + "w": 8, + "x": 0, + "y": 0 + }, + "type": "toplist", + "queries": [ + { + "name": "", + "type": "toplist", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "eval(A/B * 100, A=\"M::`vsphere_datastore`:(avg(`disk_used_latest`)) { `host` = '#{vcenter_server}' } BY `dsname`\", B=\"M::`vsphere_datastore`:(avg(`disk_capacity_latest`)) { `host` = '#{vcenter_server}' } BY `dsname`\")", + "code": "A", + "type": "expression", + "alias": "", + "children": [ + { + "q": "M::`vsphere_datastore`:(avg(`disk_used_latest`)) { `host` = '#{vcenter_server}' } BY `dsname`", + "code": "A", + "fill": null, + "type": "simple", + "alias": "", + "field": "disk_used_latest", + "filters": [ + { + "id": "b5347020-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [ + "dsname" + ], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_datastore", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + { + "q": "M::`vsphere_datastore`:(avg(`disk_capacity_latest`)) { `host` = '#{vcenter_server}' } BY `dsname`", + "code": "B", + "fill": null, + "type": "simple", + "alias": "", + "field": "disk_capacity_latest", + "filters": [ + { + "id": "c2056200-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [ + "dsname" + ], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_datastore", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + } + ], + "funcList": [], + "expression": "A/B * 100" + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Datastores" + }, + "name": "Number of reads", + "pos": { + "h": 10, + "w": 8, + "x": 8, + "y": 0 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_datastore`:(avg(`datastore_numberReadAveraged_average`) AS `number`) { `host` = '#{vcenter_server}' } BY `dsname`", + "code": "A", + "fill": null, + "type": "simple", + "alias": "number", + "field": "datastore_numberReadAveraged_average", + "filters": [ + { + "id": "cbc80270-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [ + "dsname" + ], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_datastore", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + }, + { + "extend": { + "settings": { + "alias": [], + "units": [], + "colors": [], + "levels": [], + "slimit": 20, + "showLine": false, + "unitType": "global", + "chartType": "line", + "fixedTime": "", + "isPercent": false, + "openStack": false, + "precision": "2", + "showLabel": false, + "showTitle": true, + "stackType": "time", + "titleDesc": "", + "globalUnit": [], + "isSampling": true, + "compareType": [], + "openCompare": false, + "yAxixMaxVal": null, + "yAxixMinVal": null, + "connectNulls": true, + "legendValues": "", + "timeInterval": "auto", + "legendPostion": "none", + "maxPointCount": null, + "sorderByOrder": "desc", + "xAxisShowType": "time", + "isTimeInterval": true, + "changeWorkspace": false, + "currentChartType": "sequence", + "showFieldMapping": false, + "onlyShowGroupName": false, + "openThousandsSeparator": true, + "mainMeasurementQueryCode": "A" + }, + "fixedTime": "", + "isRefresh": false + }, + "group": { + "name": "Datastores" + }, + "name": "Number of writes", + "pos": { + "h": 10, + "w": 8, + "x": 16, + "y": 0 + }, + "type": "sequence", + "queries": [ + { + "name": "", + "type": "sequence", + "unit": "", + "color": "", + "qtype": "dql", + "query": { + "q": "M::`vsphere_datastore`:(avg(`datastore_numberWriteAveraged_average`) AS `number`) { `host` = '#{vcenter_server}' } BY `dsname`", + "code": "A", + "fill": null, + "type": "simple", + "alias": "number", + "field": "datastore_numberWriteAveraged_average", + "filters": [ + { + "id": "cbc80270-7a5b-11ef-b5b2-3b763c15fe27", + "op": "=", + "name": "host", + "type": "keyword", + "logic": "and", + "value": "#{vcenter_server}", + "values": [] + } + ], + "groupBy": [ + "dsname" + ], + "funcList": [], + "fieldFunc": "avg", + "fieldType": "float", + "namespace": "metric", + "dataSource": "vsphere_datastore", + "queryFuncs": [], + "groupByTime": "", + "indexFilter": "", + "additionalFields": null + }, + "datasource": "dataflux" + } + ] + } + ], + "groups": [ + { + "name": "ESXi Hosts", + "extend": { + "bgColor": "" + } + }, + { + "name": "Virtual Machines", + "extend": { + "bgColor": "" + } + }, + { + "name": "Datastores", + "extend": { + "bgColor": "" + } + } + ], + "type": "template" + } +} \ No newline at end of file diff --git a/internal/export/doc/en/inputs/vsphere.md b/internal/export/doc/en/inputs/vsphere.md new file mode 100755 index 0000000000..0e119d18ca --- /dev/null +++ b/internal/export/doc/en/inputs/vsphere.md @@ -0,0 +1,129 @@ +--- +title : 'vSphere' +summary : 'Collect vSphere metrics' +tags: + - 'VMWARE' +__int_icon : 'icon/vsphere' +dashboard : + - desc : 'vSphere' + path : 'dashboard/en/vsphere' +monitor : + - desc : '-' + path : '-' +--- + + +# vSphere + + +--- + +{{.AvailableArchs}} + +--- + +This collector gathers resource usage metrics from vSphere clusters, including resources such as CPU, memory, and network, and reports this data to the Guance Cloud. + +## Configuration {#config} + +### Preconditions {#requrements} + +- Create a vSphere account: + +In the vCenter management interface, create a user `datakit` and assign `read-only` permissions, applying these to the resources that need to be monitored. If monitoring of all child objects is required, you can select the `Propagate to children` option. + +### Collector Configuration {#input-config} + + +=== "Host Installation" + + Go to the `conf.d/{{.Catalog}}` directory under the DataKit installation directory, copy `{{.InputName}}.conf.sample` and name it `{{.InputName}}.conf`. Examples are as follows: + + ```toml + {{ CodeBlock .InputSample 4 }} + ``` + + After configuration, restart DataKit. + +=== "Kubernetes" + + The collector can now be turned on by [configMap injection collector configuration](../datakit/datakit-daemonset-deploy.md#configmap-setting). + + +## Metric {#metric} + +For all of the following data collections, a global tag named `host` is appended by default (the tag value is the host name of the DataKit), or other tags can be specified in the configuration by `[inputs.{{.InputName}}.tags]`: + +``` toml + [inputs.{{.InputName}}.tags] + # some_tag = "some_value" + # more_tag = "some_other_value" + # ... +``` + + +???+ attention + + - Not all of the metrics listed below are collected; for specifics, refer to the explanations in the [Data Collection Levels](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.monitoring.doc/GUID-25800DE4-68E5-41CC-82D9-8811E27924BC.html){:target="_blank"} + + +{{ range $i, $m := .Measurements }} + +{{if eq $m.Type "metric"}} + +### `{{$m.Name}}` + +{{$m.Desc}} + +- Tags + +{{$m.TagsMarkdownTable}} + +- Metrics + +{{$m.FieldsMarkdownTable}}{{end}} + +{{ end }} + + +## Object {#object} + +{{ range $i, $m := .Measurements }} + +{{if eq $m.Type "object"}} + +### `{{$m.Name}}` + +{{$m.Desc}} + +- Tags + +{{$m.TagsMarkdownTable}} + +- Metrics + +{{$m.FieldsMarkdownTable}} +{{end}} + +{{ end }} + + +## Logs {#logging} + +{{ range $i, $m := .Measurements }} + +{{if eq $m.Type "logging"}} + +### `{{$m.Name}}` + +{{$m.Desc}} + +- Tags + +{{$m.TagsMarkdownTable}} + +- Metrics + +{{$m.FieldsMarkdownTable}}{{end}} + +{{ end }} \ No newline at end of file diff --git a/internal/export/doc/zh/inputs/vsphere.md b/internal/export/doc/zh/inputs/vsphere.md new file mode 100644 index 0000000000..5b4b260820 --- /dev/null +++ b/internal/export/doc/zh/inputs/vsphere.md @@ -0,0 +1,131 @@ +--- +title : 'vSphere' +summary : '采集 vSphere 的指标数据' +tags: + - 'VMWARE' +__int_icon : 'icon/vsphere' +dashboard : + - desc : 'vSphere' + path : 'dashboard/zh/vsphere' +monitor : + - desc : '暂无' + path : '-' +--- + + +# vSphere + + +--- + +{{.AvailableArchs}} + +--- + +本采集器采集 vSphere 集群的资源使用指标,包括 CPU、内存和网络等资源,并把这些数据上报到观测云。 + +## 配置 {#config} + +### 前置条件 {#requirements} + +- 创建用户 + +在 vCenter 的管理界面中创建一个用户 `datakit`,并赋予 `read-only` 权限,并应用到需要监控的资源上。如果需要监控所有子对象,可以勾选 `Propagate to children` 选项。 + +### 采集器配置 {#input-config} + + +=== "主机安装" + + 进入 DataKit 安装目录下的 `conf.d/{{.Catalog}}` 目录,复制 `{{.InputName}}.conf.sample` 并命名为 `{{.InputName}}.conf`。示例如下: + + ```toml + {{ CodeBlock .InputSample 4 }} + ``` + + 配置好后,重启 DataKit 即可。 + +=== "Kubernetes" + + 目前可以通过 [ConfigMap 方式注入采集器配置](../datakit/datakit-daemonset-deploy.md#configmap-setting)来开启采集器。 + + +## 指标 {#metric} + +以下所有数据采集,默认会追加名为 `host` 的全局 tag(tag 值为 DataKit 所在主机名),也可以在配置中通过 `[inputs.{{.InputName}}.tags]` 指定其它标签: + +``` toml + [inputs.{{.InputName}}.tags] + # some_tag = "some_value" + # more_tag = "some_other_value" + # ... +``` + + +???+ attention + + 下面的指标并非全部被采集到,具体可参阅[数据集合级别](https://docs.vmware.com/cn/VMware-vSphere/7.0/com.vmware.vsphere.monitoring.doc/GUID-25800DE4-68E5-41CC-82D9-8811E27924BC.html){:target="_blank"}中的说明。 + + +{{ range $i, $m := .Measurements }} + +{{if eq $m.Type "metric"}} + +### `{{$m.Name}}` + +{{$m.Desc}} + +- 标签 + +{{$m.TagsMarkdownTable}} + +- 指标列表 + +{{$m.FieldsMarkdownTable}} +{{end}} + +{{ end }} + + +## 对象 {#object} + +{{ range $i, $o := .Measurements }} + +{{if eq $o.Type "object"}} + +### `{{$o.Name}}` + +{{$o.Desc}} + +- 标签 + +{{$o.TagsMarkdownTable}} + +- 指标列表 + +{{$o.FieldsMarkdownTable}} +{{end}} + +{{ end }} + + +## 日志 {#logging} + +{{ range $i, $l := .Measurements }} + +{{if eq $l.Type "logging"}} + +### `{{$l.Name}}` + +{{$l.Desc}} + +- 标签 + +{{$l.TagsMarkdownTable}} + +- 字段列表 + +{{$l.FieldsMarkdownTable}} +{{end}} + +{{ end }} \ No newline at end of file diff --git a/internal/plugins/inputs/all/all.go b/internal/plugins/inputs/all/all.go index 50d7f43e2c..ba25ba0c18 100644 --- a/internal/plugins/inputs/all/all.go +++ b/internal/plugins/inputs/all/all.go @@ -99,6 +99,7 @@ import ( _ "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs/statsd" _ "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs/tdengine" _ "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs/tomcat" + _ "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs/vsphere" _ "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs/zabbix_exporter" _ "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs/zipkin" diff --git a/internal/plugins/inputs/measurement.go b/internal/plugins/inputs/measurement.go index b74b656337..936790f2d7 100644 --- a/internal/plugins/inputs/measurement.go +++ b/internal/plugins/inputs/measurement.go @@ -47,6 +47,7 @@ const ( SizeMB = "MB" SizeMBits = "Mb" SizeGB = "GB" + SizeTB = "TB" NCount = "count" // time units. diff --git a/internal/plugins/inputs/mem/input.go b/internal/plugins/inputs/mem/input.go index 4847029c6c..2cc661119a 100644 --- a/internal/plugins/inputs/mem/input.go +++ b/internal/plugins/inputs/mem/input.go @@ -175,8 +175,10 @@ func (ipt *Input) Terminate() { ipt.semStop.Close() } } -func (*Input) Catalog() string { return "host" } -func (*Input) SampleConfig() string { return sampleCfg } +func (*Input) Catalog() string { return "host" } +func (*Input) SampleConfig() string { + return sampleCfg +} func (*Input) AvailableArchs() []string { return datakit.AllOS } func (*Input) SampleMeasurement() []inputs.Measurement { return []inputs.Measurement{ diff --git a/internal/plugins/inputs/vsphere/client.go b/internal/plugins/inputs/vsphere/client.go new file mode 100644 index 0000000000..4e692b77d6 --- /dev/null +++ b/internal/plugins/inputs/vsphere/client.go @@ -0,0 +1,947 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. +// Some code modified from project Telegraf (https://github.com/influxdata/telegraf.git). + +package vsphere + +import ( + "context" + "crypto/tls" + "fmt" + "math/rand" + "net/url" + "regexp" + "strconv" + "strings" + "sync" + "time" + + "github.com/vmware/govmomi" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/performance" + "github.com/vmware/govmomi/session" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/filter" +) + +var isolateLUN = regexp.MustCompile(`.*/([^/]+)/?$`) + +var isIPv4 = regexp.MustCompile(`^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`) + +var isIPv6 = regexp.MustCompile(`^(?:[A-Fa-f0-9]{0,4}:){1,7}[A-Fa-f0-9]{1,4}$`) + +const maxSampleConst = 10 // Absolute maximum number of samples regardless of period + +const maxMetadataSamples = 100 // Number of resources to sample for metric metadata + +const maxRealtimeMetrics = 50000 // Absolute maximum metrics per realtime query + +type Client struct { + Client *govmomi.Client + Perf *performance.Manager + Timeout time.Duration + resourceKinds map[string]*resourceKind + apiVersion string + metricNameLookup map[int32]string + collectMux sync.RWMutex + metricNameMux sync.RWMutex + busy sync.Mutex + lun2ds map[string]string +} + +type objectMap map[string]*objectRef + +type objectRef struct { + name string + altID string + ref types.ManagedObjectReference + parentRef *types.ManagedObjectReference // Pointer because it must be nillable + guest string + dcname string + rpname string // ResourcePool name, default Resources + lookup map[string]string + objectTags map[string]string + objectFields map[string]interface{} + lastLogTime map[string]time.Time +} + +type metricEntry struct { + tags map[string]string + name string + ts time.Time + fields map[string]interface{} +} + +type resourceKind struct { + name string + vcName string + pKey string + parentTag string + enabled bool + realTime bool + sampling int32 + objects objectMap + filters filter.Filter + paths []string + excludePaths []string + collectInstances bool + getObjects func(context.Context, *Client, *ResourceFilter) (objectMap, error) + include []string + simple bool + metrics performance.MetricList + parent string + latestSample time.Time + lastColl time.Time +} + +// CounterInfoByKey wraps performance.CounterInfoByKey to give it proper timeouts. +func (c *Client) CounterInfoByKey(ctx context.Context) (map[int32]*types.PerfCounterInfo, error) { + return c.Perf.CounterInfoByKey(ctx) +} + +func (c *Client) getMetricNameForID(id int32) string { + c.metricNameMux.RLock() + defer c.metricNameMux.RUnlock() + return c.metricNameLookup[id] +} + +func (c *Client) reloadMetricNameMap(ctx context.Context) error { + c.metricNameMux.Lock() + defer c.metricNameMux.Unlock() + mn, err := c.CounterInfoByKey(ctx) + if err != nil { + return err + } + c.metricNameLookup = make(map[int32]string) + for key, m := range mn { + c.metricNameLookup[key] = m.Name() + } + return nil +} + +func (c *Client) discover(ctx context.Context) error { + c.busy.Lock() + defer c.busy.Unlock() + if ctx.Err() != nil { + return ctx.Err() + } + + err := c.reloadMetricNameMap(ctx) + if err != nil { + return err + } + + // get the vSphere API version + c.apiVersion = c.Client.ServiceContent.About.ApiVersion + + dcNameCache := make(map[string]string) + + numRes := int64(0) + + // Populate resource objects, and endpoint instance info. + newObjects := make(map[string]objectMap) + + for k, res := range c.resourceKinds { + // Need to do this for all resource types even if they are not enabled + if res.enabled || k != "vm" { + rf := ResourceFilter{ + finder: &Finder{c}, + resType: res.vcName, + paths: res.paths, + excludePaths: res.excludePaths, + } + + ctx1, cancel1 := context.WithTimeout(ctx, c.Timeout) + objects, err := res.getObjects(ctx1, c, &rf) + cancel1() + if err != nil { + return err + } + + // Fill in datacenter names where available (no need to do it for Datacenters) + if res.name != "datacenter" { + for k, obj := range objects { + if obj.parentRef != nil { + obj.dcname, _ = c.getDatacenterName(ctx, c, dcNameCache, *obj.parentRef) + objects[k] = obj + } + } + } + + // No need to collect metric metadata if resource type is not enabled + if res.enabled { + if res.simple { + c.simpleMetadataSelect(ctx, res) + } else { + c.complexMetadataSelect(ctx, res, objects) + } + } + newObjects[k] = objects + + numRes += int64(len(objects)) + } + } + + // Build lun2ds map + dss := newObjects["datastore"] + l2d := make(map[string]string) + for _, ds := range dss { + lunID := ds.altID + m := isolateLUN.FindStringSubmatch(lunID) + if m != nil { + l2d[m[1]] = ds.name + } + } + + // Atomically swap maps + c.collectMux.Lock() + defer c.collectMux.Unlock() + + for k, v := range newObjects { + c.resourceKinds[k].objects = v + } + c.lun2ds = l2d + + return nil +} + +// CounterInfoByName wraps performance.CounterInfoByName to give it proper timeouts. +func (c *Client) CounterInfoByName(ctx context.Context) (map[string]*types.PerfCounterInfo, error) { + ctx1, cancel1 := context.WithTimeout(ctx, c.Timeout) + defer cancel1() + return c.Perf.CounterInfoByName(ctx1) +} + +// QueryMetrics wraps performance.Query to give it proper timeouts. +func (c *Client) QueryMetrics(ctx context.Context, pqs []types.PerfQuerySpec) ([]performance.EntityMetric, error) { + ctx1, cancel1 := context.WithTimeout(ctx, c.Timeout) + defer cancel1() + metrics, err := c.Perf.Query(ctx1, pqs) + if err != nil { + return nil, err + } + + ctx2, cancel2 := context.WithTimeout(ctx, c.Timeout) + defer cancel2() + return c.Perf.ToMetricSeries(ctx2, metrics) +} + +func (c *Client) populateTags(objectRef *objectRef, resource *resourceKind, t map[string]string, v performance.MetricSeries) { + if t == nil { + return + } + + // Map name of object. + if resource.pKey != "" { + t[resource.pKey] = objectRef.name + delete(t, "source") + } + + // Map parent reference + currentRef := objectRef + currentResource := resource + for { + if currentRef == nil || currentResource == nil { + break + } + + parent, found := c.getParent(currentRef, currentResource) + if found && currentResource.parentTag != "" { + t[currentResource.parentTag] = parent.name + currentResource = c.resourceKinds[currentResource.parent] + currentRef = parent + } else { + break + } + } + + // Fill in Datacenter name + if objectRef.dcname != "" { + t["dcname"] = objectRef.dcname + } + + // Determine which point tag to map to the instance + if v.Instance != "" { + t["instance"] = v.Instance + } +} + +func (c *Client) getParent(obj *objectRef, res *resourceKind) (*objectRef, bool) { + if pKind, ok := c.resourceKinds[res.parent]; ok { + if p, ok := pKind.objects[obj.parentRef.Value]; ok { + return p, true + } + } + return nil, false +} + +func (c *Client) alignSamples(info []types.PerfSampleInfo, values []int64, interval time.Duration) ([]types.PerfSampleInfo, []float64) { + rInfo := make([]types.PerfSampleInfo, 0, len(info)) + rValues := make([]float64, 0, len(values)) + bi := 1.0 + var lastBucket time.Time + for idx := range info { + // According to the docs, SampleInfo and Value should have the same length, but we've seen corrupted + // data coming back with missing values. Take care of that gracefully! + if idx >= len(values) { + l.Debugf("len(SampleInfo)>len(Value) %d > %d during alignment", len(info), len(values)) + break + } + v := float64(values[idx]) + if v < 0 { + continue + } + ts := info[idx].Timestamp + roundedTS := ts.Truncate(interval) + + // Are we still working on the same bucket? + if roundedTS == lastBucket { + bi++ + p := len(rValues) - 1 + rValues[p] = ((bi-1)/bi)*rValues[p] + v/bi + } else { + rValues = append(rValues, v) + roundedInfo := types.PerfSampleInfo{ + Timestamp: roundedTS, + Interval: info[idx].Interval, + } + rInfo = append(rInfo, roundedInfo) + bi = 1.0 + lastBucket = roundedTS + } + } + return rInfo, rValues +} + +func (c *Client) simpleMetadataSelect(ctx context.Context, res *resourceKind) { + m, err := c.CounterInfoByName(ctx) + if err != nil { + l.Errorf("Getting metric metadata. Discovery will be incomplete. Error: %s", err.Error()) + return + } + res.metrics = make(performance.MetricList, 0, len(res.include)) + for _, s := range res.include { + if pci, ok := m[s]; ok { + cnt := types.PerfMetricId{ + CounterId: pci.Key, + } + if res.collectInstances { + cnt.Instance = "*" + } else { + cnt.Instance = "" + } + res.metrics = append(res.metrics, cnt) + } else { + l.Warnf("Metric name %s is unknown. Will not be collected", s) + } + } +} + +func (c *Client) complexMetadataSelect(ctx context.Context, res *resourceKind, objects objectMap) { + // We're only going to get metadata from maxMetadataSamples resources. If we have + // more resources than that, we pick maxMetadataSamples samples at random. + sampledObjects := make([]*objectRef, 0, len(objects)) + for _, obj := range objects { + sampledObjects = append(sampledObjects, obj) + } + if len(sampledObjects) > maxMetadataSamples { + // Shuffle samples into the maxMetadataSamples positions + for i := 0; i < maxMetadataSamples; i++ { + j := int(rand.Int31n(int32(i + 1))) //nolint:gosec // G404: not security critical + sampledObjects[i], sampledObjects[j] = sampledObjects[j], sampledObjects[i] + } + sampledObjects = sampledObjects[0:maxMetadataSamples] + } + + for _, obj := range sampledObjects { + metrics, err := c.getMetadata(ctx, obj, res.sampling) + if err != nil { + l.Errorf("Getting metric metadata. Discovery will be incomplete. Error: %s", err.Error()) + } + mMap := make(map[string]types.PerfMetricId) + for _, m := range metrics { + if m.Instance != "" && res.collectInstances { + m.Instance = "*" + } else { + m.Instance = "" + } + if res.filters.Match(c.getMetricNameForID(m.CounterId)) { + mMap[strconv.Itoa(int(m.CounterId))+"|"+m.Instance] = m + } + } + if len(mMap) > len(res.metrics) { + res.metrics = make(performance.MetricList, len(mMap)) + i := 0 + for _, m := range mMap { + res.metrics[i] = m + i++ + } + } + } +} + +// GetServerTime returns the time at the vCenter server.JJ. +func (c *Client) GetServerTime(ctx context.Context) (time.Time, error) { + ctx, cancel := context.WithTimeout(ctx, c.Timeout) + defer cancel() + t, err := methods.GetCurrentTime(ctx, c.Client) + if err != nil { + return time.Time{}, err + } + return *t, nil +} + +func (c *Client) getDatacenterName(ctx context.Context, client *Client, cache map[string]string, r types.ManagedObjectReference) (string, bool) { + return c.getAncestorName(ctx, client, "Datacenter", cache, r) +} + +func (c *Client) getAncestorName( + ctx context.Context, + client *Client, + resourceType string, + cache map[string]string, + r types.ManagedObjectReference, +) (string, bool) { + path := make([]string, 0) + returnVal := "" + here := r + done := false + for !done { + done = func() bool { + if name, ok := cache[here.Reference().String()]; ok { + // Populate cache for the entire chain of objects leading here. + returnVal = name + return true + } + path = append(path, here.Reference().String()) + o := object.NewCommon(client.Client.Client, r) + var result mo.ManagedEntity + ctx1, cancel1 := context.WithTimeout(ctx, c.Timeout) + defer cancel1() + err := o.Properties(ctx1, here, []string{"parent", "name"}, &result) + if err != nil { + l.Warnf("Error while resolving parent. Assuming no parent exists. Error: %s", err.Error()) + return true + } + if result.Reference().Type == resourceType { + // Populate cache for the entire chain of objects leading here. + returnVal = result.Name + return true + } + if result.Parent == nil { + return true + } + here = result.Parent.Reference() + return false + }() + } + for _, s := range path { + cache[s] = returnVal + } + return returnVal, returnVal != "" +} + +func (c *Client) makeMetricIdentifier(prefix, metric string) (metricName string, fieldName string) { + parts := strings.Split(metric, ".") + if len(parts) == 1 { + return prefix, parts[0] + } + return prefix, strings.Join(parts, "_") +} + +func cleanGuestID(id string) string { + return strings.TrimSuffix(id, "Guest") +} + +func (c *Client) getMetadata(ctx context.Context, obj *objectRef, sampling int32) (performance.MetricList, error) { + ctx1, cancel1 := context.WithTimeout(ctx, c.Timeout) + defer cancel1() + metrics, err := c.Perf.AvailableMetric(ctx1, obj.ref.Reference(), sampling) + if err != nil { + return nil, err + } + return metrics, nil +} + +func (ipt *Input) createVSphereClient(vSphereURL string) (*Client, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) + defer cancel() + + u, err := url.Parse(vSphereURL) + if err != nil { + return nil, fmt.Errorf("fail to parse URL: %w", err) + } + u.User = url.UserPassword(ipt.Username, ipt.Password) + + var tlsConfig *tls.Config + if ipt.TLSClientConfig != nil { + if conf, err := ipt.TLSClientConfig.TLSConfig(); err != nil { + return nil, fmt.Errorf("failed to get TLS config: %w", err) + } else { + tlsConfig = conf + } + } + + if tlsConfig == nil { + tlsConfig = &tls.Config{} //nolint + } + + soapClient := soap.NewClient(u, tlsConfig.InsecureSkipVerify) + if len(tlsConfig.Certificates) > 0 { + soapClient.SetCertificate(tlsConfig.Certificates[0]) + } + + vimClient, err := vim25.NewClient(ctx, soapClient) + if err != nil { + return nil, fmt.Errorf("failed to create vim25 client: %w", err) + } + + sm := session.NewManager(vimClient) + + govmomiClient := &govmomi.Client{ + Client: vimClient, + SessionManager: sm, + } + + if u.User != nil { + if err := govmomiClient.Login(ctx, u.User); err != nil { + return nil, fmt.Errorf("failed to login: %w", err) + } + } + + perf := performance.NewManager(govmomiClient.Client) + + client := &Client{ + Client: govmomiClient, + Perf: perf, + } + + return client, nil +} + +func getDatacenters(ctx context.Context, c *Client, resourceFilter *ResourceFilter) (objectMap, error) { + var resources []mo.Datacenter + ctx1, cancel1 := context.WithTimeout(ctx, c.Timeout) + defer cancel1() + err := resourceFilter.FindAll(ctx1, &resources) + if err != nil { + return nil, err + } + m := make(objectMap, len(resources)) + for i := range resources { + r := &resources[i] + + m[r.ExtensibleManagedObject.Reference().Value] = &objectRef{ + name: r.Name, + ref: r.ExtensibleManagedObject.Reference(), + parentRef: r.Parent, + dcname: r.Name, + } + } + return m, nil +} + +func getDatastores(ctx context.Context, c *Client, resourceFilter *ResourceFilter) (objectMap, error) { + var resources []mo.Datastore + ctx1, cancel1 := context.WithTimeout(ctx, c.Timeout) + defer cancel1() + err := resourceFilter.FindAll(ctx1, &resources) + if err != nil { + return nil, err + } + m := make(objectMap) + for i := range resources { + r := &resources[i] + + lunID := "" + if r.Info != nil { + info := r.Info.GetDatastoreInfo() + if info != nil { + lunID = info.Url + } + } + tags, fields := getDatastoreTagsAndFields(r) + m[r.ExtensibleManagedObject.Reference().Value] = &objectRef{ + name: r.Name, + ref: r.ExtensibleManagedObject.Reference(), + parentRef: r.Parent, + altID: lunID, + objectTags: tags, + objectFields: fields, + } + } + return m, nil +} + +func getClusters(ctx context.Context, client *Client, resourceFilter *ResourceFilter) (objectMap, error) { + var resources []mo.ClusterComputeResource + ctx1, cancel1 := context.WithTimeout(ctx, client.Timeout) + defer cancel1() + err := resourceFilter.FindAll(ctx1, &resources) + if err != nil { + return nil, err + } + cache := make(map[string]*types.ManagedObjectReference) + m := make(objectMap, len(resources)) + for i := range resources { + r := &resources[i] + + // Wrap in a function to make defer work correctly. + err := func() error { + // We're not interested in the immediate parent (a folder), but the data center. + p, ok := cache[r.Parent.Value] + if !ok { + o := object.NewFolder(client.Client.Client, *r.Parent) + var folder mo.Folder + ctx3, cancel3 := context.WithTimeout(ctx, client.Timeout) + defer cancel3() + err = o.Properties(ctx3, *r.Parent, []string{"parent"}, &folder) + if err != nil { + l.Warnf("Error while getting folder parent: %s", err.Error()) + p = nil + } else { + pp := folder.Parent.Reference() + p = &pp + cache[r.Parent.Value] = p + } + } + tags, fields := getClusterTagsAndFields(r) + m[r.ExtensibleManagedObject.Reference().Value] = &objectRef{ + name: r.Name, + ref: r.ExtensibleManagedObject.Reference(), + parentRef: p, + objectTags: tags, + objectFields: fields, + } + return nil + }() + if err != nil { + return nil, err + } + } + return m, nil +} + +// noinspection GoUnusedParameterJJ. +func getResourcePools(ctx context.Context, resourceFilter *ResourceFilter) (objectMap, error) { + var resources []mo.ResourcePool + err := resourceFilter.FindAll(ctx, &resources) + if err != nil { + return nil, err + } + m := make(objectMap) + for i := range resources { + r := &resources[i] + + m[r.ExtensibleManagedObject.Reference().Value] = &objectRef{ + name: r.Name, + ref: r.ExtensibleManagedObject.Reference(), + parentRef: r.Parent, + } + } + return m, nil +} + +func getResourcePoolName(rp types.ManagedObjectReference, rps objectMap) string { + // Loop through the Resource Pools objectmap to find the corresponding one + for _, r := range rps { + if r.ref == rp { + return r.name + } + } + return "Resources" // Default value +} + +// noinspection GoUnusedParameter. +func getHosts(ctx context.Context, c *Client, resourceFilter *ResourceFilter) (objectMap, error) { + var resources []mo.HostSystem + err := resourceFilter.FindAll(ctx, &resources) + if err != nil { + return nil, err + } + m := make(objectMap) + for i := range resources { + r := &resources[i] + tags, fields := getHostTagsAndFields(r) + + m[r.ExtensibleManagedObject.Reference().Value] = &objectRef{ + name: r.Name, + ref: r.ExtensibleManagedObject.Reference(), + parentRef: r.Parent, + objectTags: tags, + objectFields: fields, + } + } + return m, nil +} + +func getVMs(ctx context.Context, client *Client, resourceFilter *ResourceFilter) (objectMap, error) { + var resources []mo.VirtualMachine + ctx1, cancel1 := context.WithTimeout(ctx, client.Timeout) + defer cancel1() + err := resourceFilter.FindAll(ctx1, &resources) + if err != nil { + return nil, err + } + m := make(objectMap) + // Create a ResourcePool Filter and get the list of Resource Pools + rprf := ResourceFilter{ + finder: &Finder{client}, + resType: "ResourcePool", + paths: []string{"/*/host/**"}, + excludePaths: nil, + } + resourcePools, err := getResourcePools(ctx, &rprf) + if err != nil { + return nil, err + } + for i := range resources { + r := &resources[i] + + if r.Runtime.PowerState != "poweredOn" { + continue + } + guest := "unknown" + uuid := "" + lookup := make(map[string]string) + // Get the name of the VM resource pool + rpname := getResourcePoolName(*r.ResourcePool, resourcePools) + + // Extract host name + if r.Guest != nil && r.Guest.HostName != "" { + lookup["guesthostname"] = r.Guest.HostName + } + + // Collect network information + for _, net := range r.Guest.Net { + if net.DeviceConfigId == -1 { + continue + } + if net.IpConfig == nil || net.IpConfig.IpAddress == nil { + continue + } + ips := make(map[string][]string) + for _, ip := range net.IpConfig.IpAddress { + addr := ip.IpAddress + for _, ipType := range []string{"ipv6", "ipv4"} { + if !(ipType == "ipv4" && isIPv4.MatchString(addr) || + ipType == "ipv6" && isIPv6.MatchString(addr)) { + continue + } + + // By convention, we want the preferred addresses to appear first in the array. + if _, ok := ips[ipType]; !ok { + ips[ipType] = make([]string, 0) + } + if ip.State == "preferred" { + ips[ipType] = append([]string{addr}, ips[ipType]...) + } else { + ips[ipType] = append(ips[ipType], addr) + } + } + } + for ipType, ipList := range ips { + lookup["nic/"+strconv.Itoa(int(net.DeviceConfigId))+"/"+ipType] = strings.Join(ipList, ",") + } + } + + // Sometimes Config is unknown and returns a nil pointer + if r.Config != nil { + guest = cleanGuestID(r.Config.GuestId) + if r.Guest.GuestId != "" { + guest = cleanGuestID(r.Guest.GuestId) + } + uuid = r.Config.Uuid + } + tags, fields := getVMTagsAndFields(r) + m[r.ExtensibleManagedObject.Reference().Value] = &objectRef{ + name: r.Name, + ref: r.ExtensibleManagedObject.Reference(), + parentRef: r.Runtime.Host, + guest: guest, + altID: uuid, + rpname: rpname, + lookup: lookup, + objectTags: tags, + objectFields: fields, + } + } + return m, nil +} + +func (ipt *Input) getClient() (*Client, error) { + var client *Client + var err error + if ipt.TLSClientConfig != nil && ipt.InsecureSkipVerify { + client, err = ipt.createVSphereClient2(ipt.vcenter.String()) + } else { + client, err = ipt.createVSphereClient(ipt.vcenter.String()) + } + + if err != nil { + return nil, err + } + + ipt.setupResource(client) + + err = client.discover(context.Background()) + return client, err +} + +func (ipt *Input) testClient(ctx context.Context) error { + // Execute a dummy call against the server to make sure the client is + // still functional. If not, try to log back in. If that doesn't work, + // we give up. + ctx1, cancel1 := context.WithTimeout(ctx, ipt.timeout) + defer cancel1() + if _, err := methods.GetCurrentTime(ctx1, ipt.client.Client); err != nil { + l.Info("Client session seems to have time out. Reauthenticating!") + ctx2, cancel2 := context.WithTimeout(ctx, ipt.timeout) + defer cancel2() + + auth := url.UserPassword(ipt.Username, ipt.Password) + + if err := ipt.client.Client.SessionManager.Login(ctx2, auth); err != nil { + return fmt.Errorf("renewing authentication failed: %w", err) + } + } + + return nil +} + +func (ipt *Input) setupResource(client *Client) { + client.resourceKinds = map[string]*resourceKind{ + "datacenter": { + name: "datacenter", + vcName: "Datacenter", + pKey: "dcname", + parentTag: "", + enabled: anythingEnabled(ipt.DatacenterMetricExclude), + realTime: false, + sampling: int32(ipt.HistoricalInterval.Duration.Seconds()), + filters: newFilterOrPanic(ipt.DatacenterMetricInclude, ipt.DatacenterMetricExclude), + objects: make(objectMap), + paths: ipt.DatacenterInclude, + excludePaths: ipt.DatacenterExclude, + simple: isSimple(ipt.DatacenterMetricInclude, ipt.DatacenterMetricExclude), + collectInstances: ipt.DatacenterInstances, + getObjects: getDatacenters, + parent: "", + }, + "cluster": { + name: "cluster", + vcName: "ClusterComputeResource", + pKey: "cluster_name", + parentTag: "dcname", + enabled: anythingEnabled(ipt.ClusterMetricExclude), + realTime: false, + sampling: int32((ipt.HistoricalInterval.Duration).Seconds()), + objects: make(objectMap), + filters: newFilterOrPanic(ipt.ClusterMetricInclude, ipt.ClusterMetricExclude), + paths: ipt.ClusterInclude, + excludePaths: ipt.ClusterExclude, + simple: isSimple(ipt.ClusterMetricInclude, ipt.ClusterMetricExclude), + include: ipt.ClusterMetricInclude, + collectInstances: ipt.ClusterInstances, + getObjects: getClusters, + parent: "datacenter", + }, + "host": { + name: "host", + vcName: "HostSystem", + pKey: "esx_hostname", + parentTag: "cluster_name", + enabled: anythingEnabled(ipt.HostMetricExclude), + realTime: true, + sampling: 20, + objects: make(objectMap), + filters: newFilterOrPanic(ipt.HostMetricInclude, ipt.HostMetricExclude), + paths: ipt.HostInclude, + excludePaths: ipt.HostExclude, + simple: isSimple(ipt.HostMetricInclude, ipt.HostMetricExclude), + include: ipt.HostMetricInclude, + collectInstances: ipt.HostInstances, + getObjects: getHosts, + parent: "cluster", + }, + "vm": { + name: "vm", + vcName: "VirtualMachine", + pKey: "vm_name", + parentTag: "esx_hostname", + enabled: anythingEnabled(ipt.VMMetricExclude), + realTime: true, + sampling: 20, + objects: make(objectMap), + filters: newFilterOrPanic(ipt.VMMetricInclude, ipt.VMMetricExclude), + paths: ipt.VMInclude, + excludePaths: ipt.VMExclude, + simple: isSimple(ipt.VMMetricInclude, ipt.VMMetricExclude), + include: ipt.VMMetricInclude, + collectInstances: ipt.VMInstances, + getObjects: getVMs, + parent: "host", + }, + "datastore": { + name: "datastore", + vcName: "Datastore", + pKey: "dsname", + enabled: anythingEnabled(ipt.DatastoreMetricExclude), + realTime: false, + sampling: int32(ipt.HistoricalInterval.Duration.Seconds()), + objects: make(objectMap), + filters: newFilterOrPanic(ipt.DatastoreMetricInclude, ipt.DatastoreMetricExclude), + paths: ipt.DatastoreInclude, + excludePaths: ipt.DatastoreExclude, + simple: isSimple(ipt.DatastoreMetricInclude, ipt.DatastoreMetricExclude), + include: ipt.DatastoreMetricInclude, + collectInstances: ipt.DatastoreInstances, + getObjects: getDatastores, + parent: "", + }, + } +} + +func (ipt *Input) createVSphereClient2(vSphereURL string) (*Client, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) + defer cancel() + u, err := url.Parse(vSphereURL) + if err != nil { + return nil, fmt.Errorf("fail to parse URL: %w", err) + } + u.User = url.UserPassword(ipt.Username, ipt.Password) + soapClient := soap.NewClient(u, true) + vimClient, err := vim25.NewClient(ctx, soapClient) + if err != nil { + return nil, fmt.Errorf("failed to create vim25 client: %w", err) + } + + sm := session.NewManager(vimClient) + + if u.User != nil { + if err := sm.Login(ctx, u.User); err != nil { + return nil, fmt.Errorf("failed to login: %w", err) + } + } + + govmomiClient := &govmomi.Client{ + Client: vimClient, + SessionManager: sm, + } + + perf := performance.NewManager(govmomiClient.Client) + + client := &Client{ + Client: govmomiClient, + Perf: perf, + Timeout: ipt.timeout, + } + + return client, nil +} diff --git a/internal/plugins/inputs/vsphere/conf.go b/internal/plugins/inputs/vsphere/conf.go new file mode 100644 index 0000000000..1030001125 --- /dev/null +++ b/internal/plugins/inputs/vsphere/conf.go @@ -0,0 +1,169 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package vsphere + +var sampleConfig = ` +[[inputs.vsphere]] + ## Collect interval + interval = "60s" + + ## vCenter URL to be monitored + vcenter = "https://vcenter.local" + + ## Username and password to be used for authentication + username = "datakit@corp.local" + password = "secret" + + ## timeout applies to any of the api request made to vcenter + timeout = "60s" + + ## VMs + ## Typical VM metrics (if omitted or empty, all metrics are collected) + # vm_include = [ "/*/vm/**"] # Inventory path to VMs to collect (by default all are collected) + # vm_exclude = [] # Inventory paths to exclude + vm_metric_include = [ + "cpu.demand.average", + "cpu.idle.summation", + "cpu.latency.average", + "cpu.readiness.average", + "cpu.ready.summation", + "cpu.run.summation", + "cpu.usagemhz.average", + "cpu.used.summation", + "cpu.wait.summation", + "mem.active.average", + "mem.granted.average", + "mem.latency.average", + "mem.swapin.average", + "mem.swapinRate.average", + "mem.swapout.average", + "mem.swapoutRate.average", + "mem.usage.average", + "mem.vmmemctl.average", + "net.bytesRx.average", + "net.bytesTx.average", + "net.droppedRx.summation", + "net.droppedTx.summation", + "net.usage.average", + "power.power.average", + "virtualDisk.numberReadAveraged.average", + "virtualDisk.numberWriteAveraged.average", + "virtualDisk.read.average", + "virtualDisk.readOIO.latest", + "virtualDisk.throughput.usage.average", + "virtualDisk.totalReadLatency.average", + "virtualDisk.totalWriteLatency.average", + "virtualDisk.write.average", + "virtualDisk.writeOIO.latest", + "sys.uptime.latest", + ] + # vm_metric_exclude = [] ## Nothing is excluded by default + # vm_instances = true ## true by default + + ## Hosts + ## Typical host metrics (if omitted or empty, all metrics are collected) + # host_include = [ "/*/host/**"] # Inventory path to hosts to collect (by default all are collected) + # host_exclude [] # Inventory paths to exclude + host_metric_include = [ + "cpu.coreUtilization.average", + "cpu.costop.summation", + "cpu.demand.average", + "cpu.idle.summation", + "cpu.latency.average", + "cpu.readiness.average", + "cpu.ready.summation", + "cpu.swapwait.summation", + "cpu.usage.average", + "cpu.usagemhz.average", + "cpu.used.summation", + "cpu.utilization.average", + "cpu.wait.summation", + "disk.deviceReadLatency.average", + "disk.deviceWriteLatency.average", + "disk.kernelReadLatency.average", + "disk.kernelWriteLatency.average", + "disk.numberReadAveraged.average", + "disk.numberWriteAveraged.average", + "disk.read.average", + "disk.totalReadLatency.average", + "disk.totalWriteLatency.average", + "disk.write.average", + "mem.active.average", + "mem.latency.average", + "mem.state.latest", + "mem.swapin.average", + "mem.swapinRate.average", + "mem.swapout.average", + "mem.swapoutRate.average", + "mem.totalCapacity.average", + "mem.usage.average", + "mem.vmmemctl.average", + "net.bytesRx.average", + "net.bytesTx.average", + "net.droppedRx.summation", + "net.droppedTx.summation", + "net.errorsRx.summation", + "net.errorsTx.summation", + "net.usage.average", + "power.power.average", + "storageAdapter.numberReadAveraged.average", + "storageAdapter.numberWriteAveraged.average", + "storageAdapter.read.average", + "storageAdapter.write.average", + "sys.uptime.latest", + ] + + # host_metric_exclude = [] ## Nothing excluded by default + host_instances = true ## true by default + + ## Clusters + # cluster_include = [ "/*/host/**"] # Inventory path to clusters to collect (by default all are collected) + # cluster_exclude = [] # Inventory paths to exclude + # cluster_metric_include = [] ## if omitted or empty, all metrics are collected + # cluster_metric_exclude = [] ## Nothing excluded by default + # cluster_instances = false ## false by default + + ## Datastores + # datastore_include = [ "/*/datastore/**"] # Inventory path to datastores to collect (by default all are collected) + # datastore_exclude = [] # Inventory paths to exclude + # datastore_metric_include = [] ## if omitted or empty, all metrics are collected + # datastore_metric_exclude = [] ## Nothing excluded by default + # datastore_instances = false ## false by default + + ## Datacenters + # datacenter_include = [ "/*/host/**"] # Inventory path to clusters to collect (by default all are collected) + # datacenter_exclude = [] # Inventory paths to exclude + datacenter_metric_include = [] ## if omitted or empty, all metrics are collected + datacenter_metric_exclude = [ "*" ] ## Datacenters are not collected by default. + datacenter_instances = false ## false by default + + ## number of objects to retrieve per query for realtime resources (vms and hosts) + ## set to 64 for vCenter 5.5 and 6.0 (default: 256) + # max_query_objects = 256 + + ## number of metrics to retrieve per query for non-realtime resources (clusters and datastores) + ## set to 64 for vCenter 5.5 and 6.0 (default: 256) + # max_query_metrics = 256 + + ## The Historical Interval value must match EXACTLY the interval in the daily + # "Interval Duration" found on the VCenter server under Configure > General > Statistics > Statistic intervals + historical_interval = "5m" + + ## Set true to enable election + election = true + + ## TLS connection config + # ca_certs = ["/etc/ssl/certs/mongod.cert.pem"] + # cert = "/etc/ssl/certs/mongo.cert.pem" + # cert_key = "/etc/ssl/certs/mongo.key.pem" + # insecure_skip_verify = true + # server_name = "" + +# [inputs.vsphere.tags] + # "key1" = "value1" + # "key2" = "value2" + # ... +` diff --git a/internal/plugins/inputs/vsphere/config_name.go b/internal/plugins/inputs/vsphere/config_name.go new file mode 100644 index 0000000000..61c146ceb7 --- /dev/null +++ b/internal/plugins/inputs/vsphere/config_name.go @@ -0,0 +1,398 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package vsphere + +const ( + EventMeasurementName = "vsphere_event" + Name = "name" + HaEnabled = "ha_enabled" + VMMonitoring = "vm_monitoring" + HostMonitoring = "host_monitoring" + VMComponentProtecting = "vm_component_protecting" + FailoverLevel = "failover_level" + AdmissionControlEnabled = "admission_control_enabled" + HBDatastoreCandidatePolicy = "HBDatastoreCandidatePolicy" + WorkflowState = "workflow_state" + LockdownMode = "lockdown_mode" + DateTimeConfigTimeZone = "datetime_config_time_zone" + DateTimeConfigProtocol = "datetime_config_protocol" + DateTimeConfigEnabled = "datetime_config_enabled" + DateTimeConfigDisableEvents = "datetime_config_disable_events" + DateTimeConfigDisableFallback = "datetime_config_disable_fallback" + DateTimeConfigResetToFactoryDefaults = "datetime_config_reset_to_factory_defaults" +) + +const ( + HostName = "host_name" + TotalCPU = "total_cpu" + NumHosts = "num_hosts" + NumEffectiveHosts = "num_effective_hosts" + EffectiveCPU = "effective_cpu" + EffectiveMemory = "effective_memory" + TotalMemory = "total_memory" + Vendor = "vendor" + Model = "model" + CPUModel = "cpu_model" + MemorySize = "memory_size" + NumCPUCores = "num_cpu_cores" + NumCPUThreads = "num_cpu_threads" + NumNics = "num_nics" + MemoryTieringType = "memory_tiering_type" + Uptime = "uptime" + BootTime = "boot_time" + PingStatus = "ping_status" + ConnectionState = "connection_state" + PowerState = "power_state" + OverallMemoryUsage = "overall_memory_usage" + StandbyMode = "standby_mode" + InMaintenanceMode = "in_maintenance_mode" + InQuarantineMode = "in_quarantine_mode" + CryptoState = "crypto_state" + OverallStatus = "overall_status" + StatelessNvdsMigrationReady = "stateless_nvds_migration_ready" + DasHostState = "das_host_state" + MaxVirtualDiskCapacity = "max_virtual_disk_capacity" + ManagementServerIP = "management_server_ip" + MaxEvcModeKey = "max_EVC_mode_key" + CurrentEvcModeKey = "current_EVC_mode_key" + CurrentEvcGraphicsModeKey = "current_EVC_graphics_mode_key" + RebootRequired = "reboot_required" + SystemInfoVendor = "system_info_vendor" + SystemInfoModel = "system_info_model" + SystemInfoUUID = "system_info_uuid" + SystemInfoSerialNumber = "system_info_serial_number" + VvolHostID = "vvol_host_id" + BootCommandLine = "boot_command_line" + CPUPowerManagementCurrentPolicy = "cpu_power_management_current_policy" + CPUPowerManagementHardwareSupport = "cpu_power_management_hardware_support" + CPUNumaType = "cpu_numa_type" + CPUNumaNumNodes = "cpu_numa_num_nodes" + CPUNumPackages = "cpu_num_packages" + CPUNumCores = "cpu_num_cores" + CPUNumThreads = "cpu_num_threads" + CPUSpeedHz = "cpu_speed_hz" + HostMemorySize = "host_memory_size" + BiosVersion = "bios_version" + BiosVendor = "bios_vendor" + BiosMajorRelease = "bios_major_release" + BiosMinorRelease = "bios_minor_release" + FirmwareMajorRelease = "firmware_major_release" + FirmwareMinorRelease = "firmware_minor_release" + FirmwareType = "firmware_type" + ReliableMemoryInfoMemorySize = "reliable_memory_info_memory_size" + CapacityInMB = "capacity_inMB" + VolumeUUID = "volume_uuid" + SgxState = "sgx_state" + TotalEpcMemory = "total_epc_memory" + FlcMode = "flc_mode" + LePubKeyHash = "le_pub_key_hash" + BiosReleaseDate = "bios_release_date" + SevState = "sev_state" + MaxSevEsGuests = "max_sev_es_guests" + RemediationState = "remediation_state" + RemediationOperationTime = "remediation_operation_time" + RemediationStartTime = "remediation_start_time" + RemediationCompleteTime = "remediation_complete_time" + RemediationHost = "remediation_host" + RemediationStatus = "remediation_status" + CPUScheduler = "cpu_scheduler" + DatastoreSystem = "datastore_system" + MemoryManager = "memory_manager" + StorageSystem = "storage_system" + NetworkSystem = "network_system" + VMotionSystem = "vmotion_system" + VirtualNicManager = "virtual_nic_manager" + ServiceSystem = "service_system" + FirewallSystem = "firewall_system" + AdvancedOption = "advanced_option" + DiagnosticSystem = "diagnostic_system" + AutoStartManager = "auto_start_manager" + SnmpSystem = "snmp_system" + DateTimeSystem = "date_time_system" + PatchManager = "patch_manager" + ImageConfigManager = "image_config_manager" + BootDeviceSystem = "boot_device_system" + FirmwareSystem = "firmware_system" + HealthStatusSystem = "health_status_system" + PciPassthruSystem = "pci_passthru_system" //nolint:gosec + LicenseManager = "license_manager" + KernelModuleSystem = "kernel_module_system" + AuthenticationManager = "authentication_manager" + PowerSystem = "power_system" + CacheConfigurationManager = "cache_configuration_manager" + EsxAgentHostManager = "esx_agent_host_manager" + IscsiManager = "iscsi_manager" + VFlashManager = "v_flash_manager" + VsanSystem = "vsan_system" + MessageBusProxy = "message_bus_proxy" + UserDirectory = "user_directory" + AccountManager = "account_manager" + HostAccessManager = "host_access_manager" + GraphicsManager = "graphics_manager" + VsanInternalSystem = "vsan_internal_system" + CertificateManager = "certificate_manager" + CryptoManager = "crypto_manager" + NvdimmSystem = "nvdimm_system" + AssignableHardwareManager = "assignable_hardware_manager" + DatastoreBrowserType = "datastore_browser_type" + DatastoreBrowserValue = "datastore_browser_value" + DatastoreBrowserServerGUID = "datastore_browser_server_guid" + AnswerFileValidationStateCheckedTime = "answer_file_validation_state_checked_time" + AnswerFileValidationStateHost = "answer_file_validation_state_host" + AnswerFileValidationStateStatus = "answer_file_validation_state_status" + AnswerFileValidationResultCheckedTime = "answer_file_validation_result_checked_time" + AnswerFileValidationResultHost = "answer_file_validation_result_host" + AnswerFileValidationResultStatus = "answer_file_validation_result_status" + IPAddress = "ip_address" +) + +const ( + Datastore = "datastore" + SnapshotOperationsSupported = "snapshot_operations_supported" + MultipleSnapshotsSupported = "multiple_snapshots_supported" + SnapshotConfigSupported = "snapshot_config_supported" + PoweredOffSnapshotsSupported = "powered_off_snapshots_supported" + MemorySnapshotsSupported = "memory_snapshots_supported" + RevertToSnapshotSupported = "revert_to_snapshot_supported" + QuiescedSnapshotsSupported = "quiesced_snapshots_supported" + DisableSnapshotsSupported = "disable_snapshots_supported" + LockSnapshotsSupported = "lock_snapshots_supported" + ConsolePreferencesSupported = "console_preferences_supported" + CPUFeatureMaskSupported = "cpu_feature_mask_supported" + S1AcpiManagementSupported = "s1_acpi_management_supported" + SettingScreenResolutionSupported = "setting_screen_resolution_supported" + ToolsAutoUpdateSupported = "tools_auto_update_supported" + VMNpivWwnSupported = "vm_npiv_wwn_supported" + NpivWwnOnNonRdmVMSupported = "npiv_wwn_on_non_rdm_vm_supported" + VMNpivWwnDisableSupported = "vm_npiv_wwn_disable_supported" + VMNpivWwnUpdateSupported = "vm_npiv_wwn_update_supported" + SwapPlacementSupported = "swap_placement_supported" + ToolsSyncTimeSupported = "tools_sync_time_supported" + VirtualMmuUsageSupported = "virtual_mmu_usage_supported" + DiskSharesSupported = "disk_shares_supported" + BootOptionsSupported = "boot_options_supported" + BootRetryOptionsSupported = "boot_retry_options_supported" + SettingVideoRAMSizeSupported = "setting_video_ram_size_supported" + SettingDisplayTopologySupported = "setting_display_topology_supported" + RecordReplaySupported = "record_replay_supported" + ChangeTrackingSupported = "change_tracking_supported" + MultipleCoresPerSocketSupported = "multiple_cores_per_socket_supported" + HostBasedReplicationSupported = "host_based_replication_supported" + GuestAutoLockSupported = "guest_auto_lock_supported" + MemoryReservationLockSupported = "memory_reservation_lock_supported" + FeatureRequirementSupported = "feature_requirement_supported" + PoweredOnMonitorTypeChangeSupported = "powered_on_monitor_type_change_supported" + SeSparseDiskSupported = "se_sparse_disk_supported" + NestedHVSupported = "nested_hv_supported" + VPMCSupported = "vpmc_supported" + SecureBootSupported = "secure_boot_supported" + PerVMEvcSupported = "per_vm_evc_supported" + VirtualMmuUsageIgnored = "virtual_mmu_usage_ignored" + VirtualExecUsageIgnored = "virtual_exec_usage_ignored" + DiskOnlySnapshotOnSuspendedVMSupported = "disk_only_snapshot_on_suspended_vm_supported" + SuspendToMemorySupported = "suspend_to_memory_supported" + ToolsSyncTimeAllowSupported = "tools_sync_time_allow_supported" + SevSupported = "sev_supported" + PmemFailoverSupported = "pmem_failover_supported" + RequireSgxAttestationSupported = "require_sgx_attestation_supported" + ChangeModeDisksSupported = "change_mode_disks_supported" + VendorDeviceGroupSupported = "vendor_device_group_supported" + ChangeVersion = "change_version" + Firmware = "firmware" + ConfigName = "config_name" + GuestFullName = "guest_full_name" + ConfigVersion = "config_version" + InstanceUUID = "instance_uuid" + NpivWorldWideNameType = "npiv_world_wide_name_type" + NpivDesiredNodeWwns = "npiv_desired_node_wwns" + NpivDesiredPortWwns = "npiv_desired_port_wwns" + NpivTemporaryDisabled = "npiv_temporary_disabled" + NpivOnNonRdmDisks = "npiv_on_non_rdm_disks" + LocationID = "location_id" + Template = "template" + GuestID = "guest_id" + AlternateGuestName = "alternate_guest_name" + Annotation = "annotation" + FilesVMPathName = "files_vm_path_name" + MemoryHotAddEnabled = "memory_hot_add_enabled" + CPUHotAddEnabled = "cpu_hot_add_enabled" + CPUHotRemoveEnabled = "cpu_hot_remove_enabled" + SwapPlacement = "swap_placement" + VAssertsEnabled = "v_asserts_enabled" + ChangeTrackingEnabled = "change_tracking_enabled" + MaxMksConnections = "max_mks_connections" + GuestAutoLockEnabled = "guest_auto_lock_enabled" + MemoryReservationLockedToMax = "memory_reservation_locked_to_max" + NestedHVEnabled = "nested_hv_enabled" + VPMCEnabled = "vpmc_enabled" + VFlashCacheReservation = "vflash_cache_reservation" + VMxConfigChecksum = "vmx_config_checksum" + MessageBusTunnelEnabled = "message_bus_tunnel_enabled" + VMStorageObjectID = "vm_storage_object_id" + SwapStorageObjectID = "swap_storage_object_id" + MigrateEncryption = "migrate_encryption" + FtEncryptionMode = "ft_encryption_mode" + SevEnabled = "sev_enabled" + PmemFailoverEnabled = "pmem_failover_enabled" + VMxStatsCollectionEnabled = "vmx_stats_collection_enabled" + VMOpNotificationToAppEnabled = "vm_op_notification_to_app_enabled" + FixedPassthruHotPlugEnabled = "fixed_passthru_hot_plug_enabled" + MetroFtEnabled = "metro_ft_enabled" + ConfigUUID = "config_uuid" + Version = "version" + CPUAllocationExpandableReservation = "cpu_allocation_expandable_reservation" + LayoutSwapFile = "layout_swap_file" + EnvironmentBrowserType = "environment_browser_type" + EnvironmentBrowserValue = "environment_browser_value" + EnvironmentBrowserServerGUID = "environment_browser_server_guid" + ResourcePoolType = "resource_pool_type" + ResourcePoolValue = "resource_pool_value" + ResourcePoolServerGUID = "resource_pool_server_guid" + ParentVAppType = "parent_vapp_type" + ParentVAppValue = "parent_vapp_value" + ParentVAppServerGUID = "parent_vapp_server_guid" + EntityType = "entity_type" + EntityValue = "entity_value" + EntityServerGUID = "entity_server_guid" + + LastModified = "last_modified" + ScaleDescendantsShares = "scale_descendants_shares" + + VMFailoverInProgress = "vm_failover_in_progress" + MaxCPUUsage = "max_cpu_usage" + MaxMemoryUsage = "max_memory_usage" + NumMksConnections = "num_mks_connections" + CleanPowerOff = "clean_power_off" + NeedSecondaryReason = "need_secondary_reason" + OnlineStandby = "online_standby" + MinRequiredEVCModeKey = "min_required_EVC_mode_key" + ConsolidationNeeded = "consolidation_needed" + VFlashCacheAllocation = "v_flash_cache_allocation" + Paused = "paused" + SnapshotInBackground = "snapshot_in_background" + QuiescedForkParent = "quiesced_fork_parent" + InstantCloneFrozen = "instant_clone_frozen" + + SuspendedToMemory = "suspended_to_memory" + OpNotificationTimeout = "op_notification_timeout" + IommuActive = "iommu_active" + ToolsVersionStatus = "tools_version_status" + ToolsRunningStatus = "tools_running_status" + ToolsVersion = "tools_version" + ToolsInstallType = "tools_install_type" + GuestFamily = "guest_family" + + GuestDetailedData = "guest_detailed_data" + GuestHostName = "guest_host_name" + GuestIPAddress = "guest_ip_address" + GuestState = "guest_state" + AppHeartbeatStatus = "app_heartbeat_status" + GuestKernelCrashed = "guest_kernel_crashed" + AppState = "app_state" + GuestOperationsReady = "guest_operations_ready" + InteractiveGuestOperationsReady = "interactive_guest_operations_ready" + GuestStateChangeSupported = "guest_state_change_supported" + HwVersion = "hw_version" + CustomizationStatus = "customization_status" + + FaultToleranceState = "fault_tolerance_state" + DasProtected = "das_protected" + ToolsInstallerMounted = "tools_installer_mounted" + SuspendInterval = "suspend_interval" + MemoryOverhead = "memory_overhead" + VMPathName = "vm_path_name" + MemorySizeMB = "memory_size_mb" + CPUReservation = "cpu_reservation" + MemoryReservation = "memory_reservation" + NumCPU = "num_cpu" + NumEthernetCards = "num_ethernet_cards" + NumVirtualDisks = "num_virtual_disks" + InstallBootRequired = "install_boot_required" + TpmPresent = "tpm_present" + NumVMiopBackings = "num_vmiop_backings" + StorageCommitted = "storage_committed" + Uncommitted = "uncommitted" + Unshared = "unshared" + GuestHeartbeatStatus = "guest_heartbeat_status" +) + +const ( + ResourcePoolName = "name" + MemoryReservationUsed = "memory_reservation_used" + MemoryReservationUsedForVM = "memory_reservation_used_for_vm" + MemoryUnreservedForPool = "memory_unreserved_for_pool" + MemoryUnreservedForVM = "memory_unreserved_for_vm" + MemoryOverallUsage = "memory_overall_usage" + MemoryMaxUsage = "memory_max_usage" + CPUReservationUsed = "cpu_reservation_used" + CPUReservationUsedForVM = "cpu_reservation_used_for_vm" + CPUUnreservedForPool = "cpu_unreserved_for_pool" + CPUUnreservedForVM = "cpu_unreserved_for_vm" + CPUOverallUsage = "cpu_overall_usage" + CPUMaxUsage = "cpu_max_usage" + SharesScalable = "shares_scalable" + Namespace = "namespace" +) + +const ( + DatastoreName = "name" + URL = "url" + Type = "type" + FreeSpace = "free_space" + MaxFileSize = "max_file_size" + + MaxMemoryFileSize = "max_memory_file_size" + Capacity = "capacity" + + Accessible = "accessible" + MultipleHostAccess = "multiple_host_access" + HostFileSystemVolumeType = "host_file_system_volume_type" + MaintenanceMode = "maintenance_mode" + DirectoryHierarchySupported = "directory_hierarchy_supported" + RawDiskMappingsSupported = "raw_disk_mappings_supported" + PerFileThinProvisioningSupported = "per_file_thin_provisioning_supported" + StorageIORMSupported = "storage_io_rm_supported" + NativeSnapshotSupported = "native_snapshot_supported" + TopLevelDirectoryCreateSupported = "top_level_directory_create_supported" + SeSparseSupported = "se_sparse_supported" + VMfsSparseSupported = "vmfs_sparse_supported" + VsanSparseSupported = "vsan_sparse_supported" + UpitSupported = "upit_supported" + VMdkExpandSupported = "vmdk_expand_supported" + ClusteredVMdkSupported = "clustered_vmdk_supported" + IormEnabled = "enabled" + CongestionThresholdMode = "congestion_threshold_mode" + StatsCollectionEnabled = "stats_collection_enabled" + ReservationEnabled = "reservation_enabled" + StatsAggregationDisabled = "stats_aggregation_disabled" + ReservableIopsThreshold = "reservable_iops_threshold" +) + +const ( + Status = "status" + Info = "info" + ObjectString = "object" + ObjectName = "object_name" + Warning = "warning" + Error = "error" + UserName = "user_name" + Message = "message" + ChangeTag = "change_tag" + ResourceType = "resource_type" + EventKey = "event_key" + ClusterName = "name" + + NetworkCluster = "network_cluster" + EventTypeID = "event_type_id" + VMHost = "vm_host" + ChainID = "chain_id" + + DatacenterName = "datacenter_name" + VMsUsingNetwork = "vms_using_network" + HostsUsingNetwork = "hosts_using_network" + IPPoolName = "ip_pool_name" + Enabled = "enabled" +) diff --git a/internal/plugins/inputs/vsphere/export.go b/internal/plugins/inputs/vsphere/export.go new file mode 100644 index 0000000000..bddffb175a --- /dev/null +++ b/internal/plugins/inputs/vsphere/export.go @@ -0,0 +1,24 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package vsphere + +import "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs" + +func (*Input) Dashboard(lang inputs.I18n) map[string]string { + switch lang { + case inputs.I18nZh: + return map[string]string{ + "title": "vSphere 监控视图", + } + + case inputs.I18nEn: + return map[string]string{ + "title": "vSphere Monitor View", + } + default: + return nil + } +} diff --git a/internal/plugins/inputs/vsphere/finder.go b/internal/plugins/inputs/vsphere/finder.go new file mode 100644 index 0000000000..27b5090903 --- /dev/null +++ b/internal/plugins/inputs/vsphere/finder.go @@ -0,0 +1,286 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. +// Some code modified from project Telegraf (https://github.com/influxdata/telegraf.git). + +package vsphere + +import ( + "context" + "reflect" + "strings" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +var childTypes map[string][]string + +var addFields map[string][]string + +var containers map[string]interface{} + +// Finder allows callers to find resources in vCenter given a query string. +type Finder struct { + client *Client +} + +// ResourceFilter is a convenience class holding a finder and a set of paths. It is useful when you need a +// self contained object capable of returning a certain set of resources. +type ResourceFilter struct { + finder *Finder + resType string + paths []string + excludePaths []string +} + +// FindAll returns the union of resources found given the supplied resource type and paths. +func (f *Finder) FindAll(ctx context.Context, resType string, paths, excludePaths []string, dst interface{}) error { + objs := make(map[string]types.ObjectContent) + for _, p := range paths { + if err := f.findResources(ctx, resType, p, objs); err != nil { + return err + } + } + if len(excludePaths) > 0 { + excludes := make(map[string]types.ObjectContent) + for _, p := range excludePaths { + if err := f.findResources(ctx, resType, p, excludes); err != nil { + return err + } + } + for k := range excludes { + delete(objs, k) + } + } + return objectContentToTypedArray(objs, dst) +} + +// Find returns the resources matching the specified path. +func (f *Finder) Find(ctx context.Context, resType, path string, dst interface{}) error { + objs := make(map[string]types.ObjectContent) + err := f.findResources(ctx, resType, path, objs) + if err != nil { + return err + } + return objectContentToTypedArray(objs, dst) +} + +func (f *Finder) findResources(ctx context.Context, resType, path string, objs map[string]types.ObjectContent) error { + p := strings.Split(path, "/") + flt := make([]property.Match, len(p)-1) + for i := 1; i < len(p); i++ { + flt[i-1] = property.Match{"name": p[i]} + } + err := f.descend(ctx, f.client.Client.ServiceContent.RootFolder, resType, flt, 0, objs) + if err != nil { + return err + } + l.Debugf("Find(%s, %s) returned %d objects", resType, path, len(objs)) + return nil +} + +func (f *Finder) descend(ctx context.Context, root types.ManagedObjectReference, resType string, + tokens []property.Match, pos int, objs map[string]types.ObjectContent, +) error { + isLeaf := pos == len(tokens)-1 + + // No more tokens to match? + if pos >= len(tokens) { + return nil + } + + // Determine child types + + ct, ok := childTypes[root.Reference().Type] + if !ok { + // We don't know how to handle children of this type. Stop descending. + return nil + } + + m := view.NewManager(f.client.Client.Client) + v, err := m.CreateContainerView(ctx, root, ct, false) + if err != nil { + return err + } + defer v.Destroy(ctx) //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway + var content []types.ObjectContent + + fields := []string{"name"} + recurse := tokens[pos]["name"] == "**" + + objectTypes := ct + if isLeaf { + if af, ok := addFields[resType]; ok { + fields = append(fields, af...) + } + if recurse { + // Special case: The last token is a recursive wildcard, so we can grab everything + // recursively in a single call. + v2, err := m.CreateContainerView(ctx, root, []string{resType}, true) + if err != nil { + return err + } + defer v2.Destroy(ctx) //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway + err = v2.Retrieve(ctx, []string{resType}, fields, &content) + if err != nil { + return err + } + for _, c := range content { + objs[c.Obj.String()] = c + } + return nil + } + objectTypes = []string{resType} // Only load wanted object type at leaf level + } + err = v.Retrieve(ctx, objectTypes, fields, &content) + if err != nil { + return err + } + + rerunAsLeaf := false + for _, c := range content { + if !matchName(tokens[pos], c.PropSet) { + continue + } + + // Already been here through another path? Skip! + if _, ok := objs[root.Reference().String()]; ok { + continue + } + + if c.Obj.Type == resType && isLeaf { + // We found what we're looking for. Consider it a leaf and stop descending + objs[c.Obj.String()] = c + continue + } + + // Deal with recursive wildcards (**) + var inc int + if recurse { + inc = 0 // By default, we stay on this token + // Lookahead to next token. + if matchName(tokens[pos+1], c.PropSet) { + // Are we looking ahead at a leaf node that has the wanted type? + // Rerun the entire level as a leaf. This is needed since all properties aren't loaded + // when we're processing non-leaf nodes. + if pos == len(tokens)-2 { + if c.Obj.Type == resType { + rerunAsLeaf = true + continue + } + } else if _, ok := containers[c.Obj.Type]; ok { + // Tokens match and we're looking ahead at a container type that's not a leaf + // Consume this token and the next. + inc = 2 + } + } + } else { + // The normal case: Advance to next token before descending + inc = 1 + } + err := f.descend(ctx, c.Obj, resType, tokens, pos+inc, objs) + if err != nil { + return err + } + } + + if rerunAsLeaf { + // We're at a "pseudo leaf", i.e. we looked ahead a token and found that this level contains leaf nodes. + // Rerun the entire level as a leaf to get those nodes. This will only be executed when pos is one token + // before the last, to pos+1 will always point to a leaf token. + return f.descend(ctx, root, resType, tokens, pos+1, objs) + } + + return nil +} + +func objectContentToTypedArray(objs map[string]types.ObjectContent, dst interface{}) error { + rt := reflect.TypeOf(dst) + if rt == nil || rt.Kind() != reflect.Ptr { + panic("need pointer") + } + + rv := reflect.ValueOf(dst).Elem() + if !rv.CanSet() { + panic("cannot set dst") + } + for _, p := range objs { + v, err := mo.ObjectContentToType(p) + if err != nil { + return err + } + + vt := reflect.TypeOf(v) + + if !rv.Type().AssignableTo(vt) { + // For example: dst is []ManagedEntity, res is []HostSystem + if field, ok := vt.FieldByName(rt.Elem().Elem().Name()); ok && field.Anonymous { + rv.Set(reflect.Append(rv, reflect.ValueOf(v).FieldByIndex(field.Index))) + continue + } + } + + rv.Set(reflect.Append(rv, reflect.ValueOf(v))) + } + return nil +} + +// FindAll finds all resources matching the paths that were specified upon creation of +// the ResourceFilter. +func (r *ResourceFilter) FindAll(ctx context.Context, dst interface{}) error { + return r.finder.FindAll(ctx, r.resType, r.paths, r.excludePaths, dst) +} + +func matchName(f property.Match, props []types.DynamicProperty) bool { + for _, prop := range props { + if prop.Name == "name" { + return f.Property(prop) + } + } + return false +} + +// nolint: gochecknoinits +func init() { + childTypes = map[string][]string{ + "HostSystem": {"VirtualMachine"}, + "ResourcePool": {"VirtualMachine"}, + "ComputeResource": {"HostSystem", "ResourcePool", "VirtualApp"}, + "ClusterComputeResource": {"HostSystem", "ResourcePool", "VirtualApp"}, + "Datacenter": {"Folder"}, + "Folder": { + "Folder", + "Datacenter", + "VirtualMachine", + "ComputeResource", + "ClusterComputeResource", + "Datastore", + }, + } + + addFields = map[string][]string{ + "HostSystem": {"parent", "summary"}, + "ResourcePool": {"parent", "customValue"}, + "VirtualMachine": { + "runtime.host", "config.guestId", "config.uuid", "runtime.powerState", + "summary", "guest.guestId", "guest.net", "guest.hostName", "resourcePool", + "customValue", + }, + "Datastore": {"parent", "info", "customValue", "summary"}, + "ClusterComputeResource": {"parent", "customValue", "summary"}, + "Datacenter": {"parent", "customValue"}, + } + + containers = map[string]interface{}{ + "HostSystem": nil, + "ComputeResource": nil, + "Datacenter": nil, + "ResourcePool": nil, + "Folder": nil, + "VirtualApp": nil, + } +} diff --git a/internal/plugins/inputs/vsphere/input.go b/internal/plugins/inputs/vsphere/input.go new file mode 100644 index 0000000000..56dc6249e0 --- /dev/null +++ b/internal/plugins/inputs/vsphere/input.go @@ -0,0 +1,766 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +// Package vsphere collects vsphere metrics. +package vsphere + +import ( + "context" + "fmt" + "net/url" + "strconv" + "sync" + "time" + + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/config" + + "github.com/GuanceCloud/cliutils" + "github.com/GuanceCloud/cliutils/logger" + "github.com/GuanceCloud/cliutils/point" + "github.com/GuanceCloud/confd/log" + "github.com/vmware/govmomi/event" + "github.com/vmware/govmomi/performance" + "github.com/vmware/govmomi/vim25/types" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/datakit" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/goroutine" + dkio "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/io" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/metrics" + dknet "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/net" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/tailer" +) + +var ( + catalogName = "vmware" + inputName = "vsphere" + l = logger.DefaultSLogger(inputName) + + _ inputs.InputV2 = (*Input)(nil) + _ inputs.ElectionInput = &Input{} +) + +const ( + maxInterval = 1 * time.Minute + minInterval = 1 * time.Second +) + +type Input struct { + *dknet.TLSClientConfig + + Interval datakit.Duration `toml:"interval"` + Vcenter string `toml:"vcenter"` + Username string `toml:"username"` + Password string `toml:"password"` + Election bool `toml:"election"` + Timeout datakit.Duration `toml:"timeout"` + DatacenterInstances bool `toml:"datacenter_instances"` + DatacenterMetricInclude []string `toml:"datacenter_metric_include"` + DatacenterMetricExclude []string `toml:"datacenter_metric_exclude"` + DatacenterInclude []string `toml:"datacenter_include"` + DatacenterExclude []string `toml:"datacenter_exclude"` + ClusterInstances bool `toml:"cluster_instances"` + ClusterMetricInclude []string `toml:"cluster_metric_include"` + ClusterMetricExclude []string `toml:"cluster_metric_exclude"` + ClusterInclude []string `toml:"cluster_include"` + ClusterExclude []string `toml:"cluster_exclude"` + // ResourcePoolInstances bool `toml:"resource_pool_instances"` + // ResourcePoolMetricInclude []string `toml:"resource_pool_metric_include"` + // ResourcePoolMetricExclude []string `toml:"resource_pool_metric_exclude"` + // ResourcePoolInclude []string `toml:"resource_pool_include"` + // ResourcePoolExclude []string `toml:"resource_pool_exclude"` + HostInstances bool `toml:"host_instances"` + HostMetricInclude []string `toml:"host_metric_include"` + HostMetricExclude []string `toml:"host_metric_exclude"` + HostInclude []string `toml:"host_include"` + HostExclude []string `toml:"host_exclude"` + VMInstances bool `toml:"vm_instances"` + VMMetricInclude []string `toml:"vm_metric_include"` + VMMetricExclude []string `toml:"vm_metric_exclude"` + VMInclude []string `toml:"vm_include"` + VMExclude []string `toml:"vm_exclude"` + DatastoreInstances bool `toml:"datastore_instances"` + DatastoreMetricInclude []string `toml:"datastore_metric_include"` + DatastoreMetricExclude []string `toml:"datastore_metric_exclude"` + DatastoreInclude []string `toml:"datastore_include"` + DatastoreExclude []string `toml:"datastore_exclude"` + MaxQueryObjects int `toml:"max_query_objects"` + MaxQueryMetrics int `toml:"max_query_metrics"` + HistoricalInterval datakit.Duration `toml:"historical_interval"` + ObjectDiscoveryInterval datakit.Duration `toml:"object_discovery_interval"` + + Tags map[string]string `toml:"tags"` + client *Client + tail *tailer.Tailer + pause bool + pauseCh chan bool + semStop *cliutils.Sem // start stop signal + feeder dkio.Feeder + collectCache []*point.Point + collectLogs []*point.Point + collectObjects []*point.Point + g *goroutine.Group + start time.Time + mutex sync.Mutex + duration time.Duration + timeout time.Duration + vcenter *url.URL + + hostLastLogTimes map[string]time.Time + vmLastLogTimes map[string]time.Time + + datastoreLastLogTimes map[string]time.Time + networkLastLogTimes map[string]time.Time +} + +func (*Input) Catalog() string { return catalogName } + +func (*Input) AvailableArchs() []string { return datakit.AllOSWithElection } + +func (*Input) SampleMeasurement() []inputs.Measurement { + return []inputs.Measurement{ + &clusterMeasurement{}, + &datastoreMeasurement{}, + &hostMeasurement{}, + &vmMeasurement{}, + &clusterObject{}, + &datastoreObject{}, + &hostObject{}, + &vmObject{}, + &eventMeasurement{}, + } +} + +func (*Input) SampleConfig() string { return sampleConfig } + +func (ipt *Input) init() error { + if ipt.client != nil { + return nil + } + + u, err := url.Parse(ipt.Vcenter) + if err != nil { + l.Errorf("failed to parse vcenter URL %s: %s", ipt.Vcenter, err) + } + u.Path = "/sdk" + ipt.vcenter = u + + if err != nil { + ipt.feeder.FeedLastError(err.Error(), + metrics.WithLastErrorInput(inputName), + metrics.WithLastErrorCategory(point.Metric), + ) + return fmt.Errorf("failed to create vSphere client: %w", err) + } + + if ipt.client, err = ipt.getClient(); err != nil { + return fmt.Errorf("failed to create vSphere client: %w", err) + } + + return ipt.startDiscovery() +} + +func (ipt *Input) startDiscovery() error { + if ipt.ObjectDiscoveryInterval.Duration > 0 { + g := goroutine.NewGroup(goroutine.Option{Name: goroutine.GetInputName(inputName)}) + g.Go(func(ctx context.Context) error { + ticker := time.NewTicker(ipt.ObjectDiscoveryInterval.Duration) + defer ticker.Stop() + for { + select { + case <-datakit.Exit.Wait(): + return nil + case <-ipt.semStop.Wait(): + return nil + case <-ticker.C: + case ipt.pause = <-ipt.pauseCh: + } + + if !ipt.pause { + if err := ipt.client.discover(context.Background()); err != nil { + l.Errorf("failed to discover: %w", err) + } + } + } + }) + } + return nil +} + +func (ipt *Input) Collect() error { + if err := ipt.testClient(context.Background()); err != nil { + ipt.client, err = ipt.getClient() + if err != nil { + return fmt.Errorf("failed to create vsphere client: %w", err) + } + } + + if ipt.ObjectDiscoveryInterval.Duration == 0 { + if err := ipt.client.discover(context.Background()); err != nil { + return fmt.Errorf("failed to discover: %w", err) + } + } + + for k, res := range ipt.client.resourceKinds { + if res.enabled { + func(resourceType string) { + ipt.g.Go(func(ctx context.Context) error { + ipt.collectResource(resourceType) + ipt.collectResourceObject(resourceType) + ipt.collectResourceEvent(resourceType) + return nil + }) + }(k) + } + } + + return ipt.g.Wait() +} + +// collectResourceEvent collects events from vcenter. +func (ipt *Input) collectResourceEvent(resourceType string) { + client := ipt.client + res := client.resourceKinds[resourceType] + eventManager := event.NewManager(client.Client.Client) + + pts := []*point.Point{} + for _, obj := range res.objects { + latestTime := ipt.start + if obj.lastLogTime == nil { + obj.lastLogTime = make(map[string]time.Time) + } else if t, exists := obj.lastLogTime[resourceType]; exists { + latestTime = t + } + + filter := types.EventFilterSpec{} + filter.Time = &types.EventFilterSpecByTime{ + BeginTime: &latestTime, + } + filter.Entity = &types.EventFilterSpecByEntity{ + Entity: obj.ref, + Recursion: types.EventFilterSpecRecursionOptionAll, + } + + events, err := eventManager.QueryEvents(context.Background(), filter) + if err != nil { + l.Errorf("Error querying events for %s, %s: %s", resourceType, obj.name, err.Error()) + continue + } + + if len(events) == 0 { + continue + } + + for _, e := range events { + event := e.GetEvent() + if event != nil { + tags := map[string]string{ + "host": ipt.vcenter.Host, + ResourceType: resourceType, + } + client.populateTags(obj, res, tags, performance.MetricSeries{}) + + m := &Log{ + source: EventMeasurementName, + tags: tags, + election: ipt.Election, + } + + pt := m.Point() + + if eventEx, ok := e.(*types.EventEx); ok { + pt.AddTag(EventTypeID, eventEx.EventTypeId) + pt.AddTag(ObjectName, eventEx.ObjectName) + switch eventEx.Severity { + case Warning: + pt.MustAddTag(Status, Warning) + case Error: + pt.MustAddTag(Status, Error) + } + } + + pt.MustAddTag(Status, Info) + pt.AddTag(ObjectName, obj.name) + pt.AddTag(EventTypeID, fmt.Sprintf("%T", e)) + pt.AddTag(UserName, event.UserName) + pt.SetTime(event.CreatedTime) + pt.Add(ChangeTag, event.ChangeTag) + pt.Add(ChainID, event.ChainId) + pt.Add(Message, event.FullFormattedMessage) + pt.Add(EventKey, event.Key) + if event.CreatedTime.After(latestTime) { + latestTime = event.CreatedTime + } + + // custom tags + for k, v := range ipt.Tags { + pt.AddTag(k, v) + } + + pts = append(pts, pt) + } + } + obj.lastLogTime[resourceType] = latestTime + } + + if len(pts) > 0 { + ipt.mutex.Lock() + defer ipt.mutex.Unlock() + ipt.collectLogs = append(ipt.collectLogs, pts...) + } +} + +func (ipt *Input) collectResourceObject(resourceType string) { + client := ipt.client + res := client.resourceKinds[resourceType] + pts := []*point.Point{} + for _, obj := range res.objects { + tags, fields := obj.objectTags, obj.objectFields + + if len(tags) == 0 && len(fields) == 0 { + continue + } + + tags["host"] = ipt.vcenter.Host + + client.populateTags(obj, res, tags, performance.MetricSeries{}) + + m := &Object{ + class: fmt.Sprintf("vsphere_%s", resourceType), + tags: tags, + fields: fields, + election: ipt.Election, + } + pt := m.Point() + + // custom tags + for k, v := range ipt.Tags { + pt.AddTag(k, v) + } + + pts = append(pts, m.Point()) + } + if len(pts) > 0 { + ipt.mutex.Lock() + defer ipt.mutex.Unlock() + ipt.collectObjects = append(ipt.collectObjects, pts...) + } +} + +func (ipt *Input) collectResource(resourceType string) { + ctx := context.Background() + client := ipt.client + res := client.resourceKinds[resourceType] + + maxMetrics := ipt.MaxQueryMetrics + if maxMetrics < 1 { + maxMetrics = 1 + } + + if res.name == "cluster" && maxMetrics > 10 { + maxMetrics = 10 + } + + now, err := client.GetServerTime(ctx) + if err != nil { + l.Errorf("Failed to get server time: %s", err.Error()) + return + } + + // Estimate the interval at which we're invoked. Use local time (not server time) + // since this is about how we got invoked locally. + localNow := time.Now() + estInterval := time.Minute + if !res.lastColl.IsZero() { + s := time.Duration(res.sampling) * time.Second + rawInterval := localNow.Sub(res.lastColl) + paddedInterval := rawInterval + time.Duration(res.sampling/2)*time.Second + estInterval = paddedInterval.Truncate(s) + if estInterval < s { + estInterval = s + } + } + + res.lastColl = localNow + + pqs := make(queryChunk, 0, ipt.MaxQueryObjects) + numQs := 0 + + for _, obj := range res.objects { + specs := make([]*types.PerfQuerySpec, 0) + makeSpec := func() *types.PerfQuerySpec { + spec := types.PerfQuerySpec{ + Entity: obj.ref, + MaxSample: maxSampleConst, + MetricId: make([]types.PerfMetricId, 0), + IntervalId: res.sampling, + Format: "normal", + } + if res.realTime { + spec.MaxSample = 1 + } else { + start := now.Add(-2 * time.Hour) + spec.StartTime = &start + } + + return &spec + } + + var spec *types.PerfQuerySpec + + for _, metric := range res.metrics { + metricName := client.getMetricNameForID(metric.CounterId) + if metricName == "" { + l.Debugf("Unable to find metric name for counter ID %d", metric.CounterId) + continue + } + if spec == nil { + spec = makeSpec() + } + spec.MetricId = append(spec.MetricId, metric) + + if (!res.realTime && len(spec.MetricId) >= maxMetrics) || len(spec.MetricId) > maxRealtimeMetrics { + specs = append(specs, spec) + spec = nil + } + } + if spec != nil { + specs = append(specs, spec) + } + + for _, spec := range specs { + pqs = append(pqs, *spec) + numQs += len(spec.MetricId) + if (!res.realTime && numQs > ipt.MaxQueryObjects) || numQs > maxRealtimeMetrics { + ipt.collectResourcePoints(pqs, res, estInterval) + pqs = make(queryChunk, 0, ipt.MaxQueryObjects) + numQs = 0 + } + } + } + + if len(pqs) > 0 { + ipt.collectResourcePoints(pqs, res, estInterval) + } +} + +type queryChunk []types.PerfQuerySpec + +func (ipt *Input) collectResourcePoints(specs queryChunk, res *resourceKind, interval time.Duration) { + latestSample := time.Time{} + count := 0 + resourceType := res.name + prefix := "vsphere_" + resourceType + + client := ipt.client + + metricInfo, err := client.CounterInfoByName(context.Background()) + if err != nil { + l.Warnf("Failed to get counter info: %s", err.Error()) + return + } + ems, err := client.QueryMetrics(context.Background(), specs) + if err != nil { + l.Warnf("Failed to query metrics: %s", err.Error()) + return + } + + l.Debugf("Query for %s returned metrics for %d objects", resourceType, len(ems)) + + // Iterate through results + for _, em := range ems { + moid := em.Entity.Reference().Value + instInfo, found := res.objects[moid] + if !found { + l.Errorf("MOID %s not found in cache. Skipping! (This should not happen!)", moid) + continue + } + buckets := make(map[string]metricEntry) + for _, v := range em.Value { + name := v.Name + t := map[string]string{ + "host": ipt.vcenter.Host, + "source": instInfo.name, + "moid": moid, + } + + // Populate tags + objectRef, ok := res.objects[moid] + if !ok { + l.Errorf("MOID %s not found in cache. Skipping", moid) + continue + } + client.populateTags(objectRef, res, t, v) + + nValues := 0 + alignedInfo, alignedValues := client.alignSamples(em.SampleInfo, v.Value, interval) + + for idx, sample := range alignedInfo { + // According to the docs, SampleInfo and Value should have the same length, but we've seen corrupted + // data coming back with missing values. Take care of that gracefully! + if idx >= len(alignedValues) { + l.Debugf("Len(SampleInfo)>len(Value) %d > %d", len(alignedInfo), len(alignedValues)) + break + } + ts := sample.Timestamp + if ts.After(latestSample) { + latestSample = ts + } + nValues++ + + // Organize the metrics into a bucket per measurement. + mn, fn := client.makeMetricIdentifier(prefix, name) + bKey := mn + " " + v.Instance + " " + strconv.FormatInt(ts.UnixNano(), 10) + bucket, found := buckets[bKey] + if !found { + bucket = metricEntry{name: mn, ts: ts, fields: make(map[string]interface{}), tags: t} + buckets[bKey] = bucket + } + + // Percentage values must be scaled down by 100. + info, ok := metricInfo[name] + if !ok { + l.Errorf("Could not determine unit for %s. Skipping", name) + } + v := alignedValues[idx] + if info.UnitInfo.GetElementDescription().Key == "percent" { + bucket.fields[fn] = v / 100.0 + } else { + bucket.fields[fn] = v + } + count++ + } + if nValues == 0 { + l.Debugf("Missing value for: %s, %s", name, objectRef.name) + continue + } + } + + ipt.makePoints(buckets) + } + if latestSample.After(res.latestSample) && !latestSample.IsZero() { + res.latestSample = latestSample + } +} + +func (ipt *Input) makePoints(buckets map[string]metricEntry) { + pts := make([]*point.Point, 0) + + for _, bucket := range buckets { + m := &Measurement{ + name: bucket.name, + tags: bucket.tags, + fields: bucket.fields, + election: ipt.Election, + } + + pt := m.Point() + pt.SetTime(bucket.ts) + + for k, v := range ipt.Tags { + pt.AddTag(k, v) + } + + pts = append(pts, m.Point()) + } + + ipt.mutex.Lock() + defer ipt.mutex.Unlock() + ipt.collectCache = append(ipt.collectCache, pts...) +} + +func (ipt *Input) Run() { + ipt.setup() + + ipt.duration = config.ProtectedInterval(minInterval, maxInterval, ipt.Interval.Duration) + ipt.timeout = config.ProtectedInterval(10*time.Second, time.Minute, ipt.Timeout.Duration) + + tick := time.NewTicker(ipt.duration) + defer tick.Stop() + + l.Infof("%s input started", inputName) + + for { + if err := ipt.init(); err != nil { + l.Errorf("failed to init servers: %s", err.Error()) + } else { + break + } + + select { + case <-datakit.Exit.Wait(): + ipt.exit() + log.Info("vsphere input exit") + + return + case <-ipt.semStop.Wait(): + ipt.exit() + log.Info("vsphere input return") + + return + case <-tick.C: + case ipt.pause = <-ipt.pauseCh: + } + } + + for { + if !ipt.pause { + ipt.start = time.Now() + l.Debugf("vsphere input gathering...") + + if err := ipt.Collect(); err != nil { + ipt.feeder.FeedLastError(err.Error(), + metrics.WithLastErrorInput(inputName), + ) + + l.Errorf("collect failed: %s", err.Error()) + } else { + l.Debugf("collect cache length: %d", len(ipt.collectCache)) + if len(ipt.collectCache) > 0 { + if err := ipt.feeder.FeedV2(point.Metric, ipt.collectCache, + dkio.WithCollectCost(time.Since(ipt.start)), + dkio.WithElection(ipt.Election), + dkio.WithInputName(inputName), + ); err != nil { + ipt.feeder.FeedLastError(err.Error(), + metrics.WithLastErrorInput(inputName), + ) + } + } + + l.Debugf("collect log length: %d", len(ipt.collectLogs)) + if len(ipt.collectLogs) > 0 { + if err := ipt.feeder.FeedV2(point.Logging, ipt.collectLogs, + dkio.WithCollectCost(time.Since(ipt.start)), + dkio.WithElection(ipt.Election), + dkio.WithInputName(inputName), + ); err != nil { + ipt.feeder.FeedLastError(err.Error(), + metrics.WithLastErrorInput(inputName), + metrics.WithLastErrorSource(inputName), + ) + l.Errorf("feed logging: %s", err) + } + } + + l.Debugf("collect object length: %d", len(ipt.collectObjects)) + if len(ipt.collectObjects) > 0 { + if err := ipt.feeder.FeedV2(point.CustomObject, ipt.collectObjects, + dkio.WithCollectCost(time.Since(ipt.start)), + dkio.WithElection(ipt.Election), + dkio.WithInputName(inputName+"/CO"), + ); err != nil { + ipt.feeder.FeedLastError(err.Error(), + metrics.WithLastErrorInput(inputName), + ) + } + } + + ipt.collectLogs = ipt.collectLogs[:0] + ipt.collectCache = ipt.collectCache[:0] + ipt.collectObjects = ipt.collectObjects[:0] + } + } else { + l.Debugf("not leader, skipped") + } + + select { + case <-datakit.Exit.Wait(): + ipt.exit() + log.Info("vsphere input exit") + + return + case <-ipt.semStop.Wait(): + ipt.exit() + log.Info("vsphere input return") + + return + case <-tick.C: + case ipt.pause = <-ipt.pauseCh: + } + } +} + +func (ipt *Input) ElectionEnabled() bool { + return ipt.Election +} + +func (ipt *Input) setup() { + l = logger.SLogger(inputName) + + ipt.pauseCh = make(chan bool, inputs.ElectionPauseChannelLength) + ipt.semStop = cliutils.NewSem() +} + +func (ipt *Input) Pause() error { + tick := time.NewTicker(inputs.ElectionPauseTimeout) + defer tick.Stop() + select { + case ipt.pauseCh <- true: + return nil + + case <-datakit.Exit.Wait(): + log.Info("pause vsphere interrupted by global exit.") + return nil + + case <-tick.C: + return fmt.Errorf("pause %s failed", inputName) + } +} + +func (ipt *Input) Resume() error { + tick := time.NewTicker(inputs.ElectionResumeTimeout) + defer tick.Stop() + select { + case ipt.pauseCh <- false: + return nil + case <-tick.C: + return fmt.Errorf("resume %s failed", inputName) + } +} + +func (ipt *Input) exit() { + if ipt.tail != nil { + ipt.tail.Close() + log.Info("vsphere log exits") + } +} + +func (ipt *Input) Terminate() { + if ipt.semStop != nil { + ipt.semStop.Close() + } +} + +func defaultInput() *Input { + return &Input{ + DatacenterInclude: []string{"/*"}, + ClusterInclude: []string{"/*/host/**"}, + HostInstances: true, + HostInclude: []string{"/*/host/**"}, + // ResourcePoolInclude: []string{"/*/host/**"}, + VMInstances: true, + VMInclude: []string{"/*/vm/**"}, + DatastoreInclude: []string{"/*/datastore/**"}, + ObjectDiscoveryInterval: datakit.Duration{Duration: time.Second * 300}, + Timeout: datakit.Duration{Duration: time.Second * 60}, + HistoricalInterval: datakit.Duration{Duration: time.Second * 300}, + MaxQueryObjects: 256, + MaxQueryMetrics: 256, + feeder: dkio.DefaultFeeder(), + semStop: cliutils.NewSem(), + Election: true, + g: goroutine.NewGroup(goroutine.Option{Name: goroutine.GetInputName("vsphere")}), + vmLastLogTimes: make(map[string]time.Time), + hostLastLogTimes: make(map[string]time.Time), + datastoreLastLogTimes: make(map[string]time.Time), + networkLastLogTimes: make(map[string]time.Time), + } +} + +func init() { //nolint:gochecknoinits + inputs.Add(inputName, func() inputs.Input { + return defaultInput() + }) +} diff --git a/internal/plugins/inputs/vsphere/log.go b/internal/plugins/inputs/vsphere/log.go new file mode 100644 index 0000000000..ec3bf1d4ea --- /dev/null +++ b/internal/plugins/inputs/vsphere/log.go @@ -0,0 +1,35 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package vsphere + +import ( + "github.com/GuanceCloud/cliutils/point" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/datakit" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs" +) + +type Log struct { + source string + tags map[string]string + fields map[string]interface{} + election bool +} + +// Point implement MeasurementV2. +func (m *Log) Point() *point.Point { + opts := point.DefaultLoggingOptions() + if m.election { + opts = append(opts, point.WithExtraTags(datakit.GlobalElectionTags())) + } + + return point.NewPointV2(m.source, + append(point.NewTags(m.tags), point.NewKVs(m.fields)...), + opts...) +} + +func (m *Log) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{} +} diff --git a/internal/plugins/inputs/vsphere/measurement.go b/internal/plugins/inputs/vsphere/measurement.go new file mode 100644 index 0000000000..dda902116e --- /dev/null +++ b/internal/plugins/inputs/vsphere/measurement.go @@ -0,0 +1,743 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package vsphere + +import ( + "github.com/GuanceCloud/cliutils/point" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/datakit" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs" +) + +type Measurement struct { + name string + tags map[string]string + fields map[string]interface{} + election bool +} + +// Point implement MeasurementV2. +func (m *Measurement) Point() *point.Point { + opts := point.DefaultMetricOptions() + + if m.election { + opts = append(opts, point.WithExtraTags(datakit.GlobalElectionTags())) + } + + return point.NewPointV2(m.name, + append(point.NewTags(m.tags), point.NewKVs(m.fields)...), + opts...) +} + +func (m *Measurement) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_cpu", + Type: "metric", + Tags: map[string]interface{}{}, + } +} + +type clusterMeasurement struct { + Measurement +} + +func (m *clusterMeasurement) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_cluster", + Type: "metric", + Fields: map[string]interface{}{ + "cpu_usage_average": &inputs.FieldInfo{ + DataType: inputs.Float, + Type: inputs.Gauge, + Unit: inputs.Percent, + Desc: "Percentage of CPU capacity being used.", + }, + "cpu_usagemhz_average": &inputs.FieldInfo{ + DataType: inputs.Float, + Type: inputs.Gauge, + Unit: inputs.Percent, + Desc: "CPU usage, as measured in megahertz.", + }, + "mem_consumed_average": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.SizeKB, + Desc: "Amount of host physical memory consumed by a virtual machine, host, or cluster.", + }, + "mem_overhead_average": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.SizeKB, + Desc: "Host physical memory consumed by the virtualization infrastructure for running the virtual machine.", + }, + "mem_usage_average": &inputs.FieldInfo{ + DataType: inputs.Float, + Type: inputs.Gauge, + Unit: inputs.Percent, + Desc: "Memory usage as percent of total configured or available memory.", + }, + "mem_vmmemctl_average": &inputs.FieldInfo{ + DataType: inputs.Float, + Type: inputs.Gauge, + Unit: inputs.Percent, + Desc: "Amount of memory allocated by the virtual machine memory control driver (`vmmemctl`).", + }, + "vmop_numChangeDS_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of datastore change operations for powered-off and suspended virtual machines.", + }, + "vmop_numChangeHostDS_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of host and datastore change operations for powered-off and suspended virtual machines.", + }, + "vmop_numChangeHost_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of host change operations for powered-off and suspended virtual machines.", + }, + "vmop_numClone_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine clone operations.", + }, + "vmop_numCreate_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine create operations.", + }, + "vmop_numDeploy_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine template deploy operations.", + }, + "vmop_numDestroy_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine delete operations.", + }, + "vmop_numPoweroff_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine power off operations.", + }, + "vmop_numPoweron_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine power on operations.", + }, + "vmop_numRebootGuest_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine guest reboot operations.", + }, + "vmop_numReconfigure_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine reconfigure operations.", + }, + "vmop_numRegister_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine register operations.", + }, + "vmop_numReset_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine reset operations.", + }, + "vmop_numSVMotion_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of migrations with Storage vMotion (datastore change operations for powered-on VMs).", + }, + "vmop_numShutdownGuest_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine guest shutdown operations.", + }, + "vmop_numStandbyGuest_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine standby guest operations.", + }, + "vmop_numSuspend_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine suspend operations.", + }, + "vmop_numUnregister_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of virtual machine unregister operations.", + }, + "vmop_numVMotion_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of migrations with vMotion (host change operations for powered-on VMs).", + }, + "vmop_numXVMotion_latest": &inputs.FieldInfo{ + DataType: inputs.Int, + Type: inputs.Gauge, + Unit: inputs.NCount, + Desc: "Number of host and datastore change operations for powered-on and suspended virtual machines.", + }, + }, + Tags: map[string]interface{}{ + "host": &inputs.TagInfo{Desc: "The host of the vCenter"}, + "dcname": &inputs.TagInfo{Desc: "`Datacenter` name"}, + "cluster_name": &inputs.TagInfo{Desc: "Cluster name"}, + "moid": &inputs.TagInfo{Desc: "The managed object id"}, + }, + } +} + +type datastoreMeasurement struct { + Measurement +} + +//nolint:lll +func (m *datastoreMeasurement) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_datastore", + Type: "metric", + Fields: map[string]interface{}{ + "datastore_busResets_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Number of SCSI-bus reset commands issued."}, + "datastore_commandsAborted_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Number of SCSI commands aborted."}, + "datastore_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second to the datastore."}, + "datastore_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second to the datastore during the collection interval."}, + "datastore_throughput_contention.avg": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for an I/O operation to the datastore or LUN across all ESX hosts accessing it."}, + "datastore_throughput_usage_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "The current bandwidth usage for the datastore or LUN."}, + "disk_busResets_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI-bus reset commands issued."}, + "disk_capacity_contention_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "The amount of storage capacity overcommitment for the entity, measured in percent."}, + "disk_capacity_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Configured size of the datastore."}, + "disk_capacity_provisioned_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Provisioned size of the entity."}, + "disk_capacity_usage.avg": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "The amount of storage capacity currently being consumed by or on the entity."}, + "disk_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second to the datastore."}, + "disk_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second to the datastore."}, + "disk_provisioned_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of storage set aside for use by a datastore or a virtual machine. Files on the datastore and the virtual machine can expand to this size but not beyond it."}, + "disk_unshared_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of space associated exclusively with a virtual machine."}, + "disk_used_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of space actually used by the virtual machine or the datastore. May be less than the amount provisioned at any given time, depending on whether the virtual machine is powered-off, whether snapshots have been created or not, and other such factors."}, + }, + Tags: map[string]interface{}{ + "host": &inputs.TagInfo{Desc: "The host of the vCenter"}, + "dcname": &inputs.TagInfo{Desc: "`Datacenter` name"}, + "moid": &inputs.TagInfo{Desc: "The managed object id"}, + "dsname": &inputs.TagInfo{Desc: "The name of the datastore"}, + }, + } +} + +type vmMeasurement struct { + Measurement +} + +//nolint:lll +func (m *vmMeasurement) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_vm", + Type: "metric", + Fields: map[string]interface{}{ + "cpu_costop_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Time the virtual machine is ready to run, but is unable to run due to co-scheduling constraints."}, + "cpu_demand_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "The amount of CPU resources a virtual machine would use if there were no CPU contention or CPU limit."}, + "cpu_demandEntitlementRatio_latest": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU resource entitlement to CPU demand ratio (in percents)."}, + "cpu_entitlement_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "CPU resources devoted by the ESXi scheduler."}, + "cpu_idle_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Total time that the CPU spent in an idle state."}, + "cpu_latency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percent of time the virtual machine is unable to run because it is contending for access to the physical CPU(s)."}, + "cpu_maxlimited_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Time the virtual machine is ready to run, but is not running because it has reached its maximum CPU limit setting."}, + "cpu_overlap_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Time the virtual machine was interrupted to perform system services on behalf of itself or other virtual machines."}, + "cpu_readiness_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percentage of time that the virtual machine was ready, but could not get scheduled to run on the physical CPU."}, + "cpu_ready_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Milliseconds of CPU time spent in ready state."}, + "cpu_run_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Time the virtual machine is scheduled to run."}, + "cpu_swapwait_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "CPU time spent waiting for swap-in."}, + "cpu_system_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Amount of time spent on system processes on each virtual CPU in the virtual machine. This is the host view of the CPU usage, not the guest operating system view."}, + "cpu_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percentage of CPU capacity being used."}, + "cpu_usagemhz_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "CPU usage, as measured in megahertz."}, + "cpu_used_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Time accounted to the virtual machine. If a system service runs on behalf of this virtual machine, the time spent by that service (represented by cpu.system) should be charged to this virtual machine. If not, the time spent (represented by cpu.overlap) should not be charged against this virtual machine."}, + "cpu_wait_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Total CPU time spent in wait state.The wait total includes time spent the CPU Idle, CPU Swap Wait, and CPU I/O Wait states."}, + "cpu_capacity_demand_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "The amount of CPU resources a virtual machine would use if there were no CPU contention or CPU limit."}, + "cpu_capacity_usage_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "CPU usage as a percent during the interval."}, + "cpu_capacity_contention_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percent of time the virtual machine is unable to run because it is contending for access to the physical CPU(s)."}, + "datastore_maxTotalLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Highest latency value across all datastores used by the host."}, + "datastore_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second to the datastore."}, + "datastore_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second to the datastore during the collection interval."}, + "datastore_read_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of reading data from the datastore."}, + "datastore_totalReadLatency_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a read operation from the datastore."}, + "datastore_totalWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a write operation from the datastore."}, + "datastore_write_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of writing data to the datastore."}, + "disk_busResets_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI-bus reset commands issued."}, + "disk_commands_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI commands issued"}, + "disk_commandsAborted_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI commands aborted."}, + "disk_commandsAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of SCSI commands issued per second."}, + "disk_maxTotalLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Highest latency value across all disks used by the host."}, + "disk_numberRead_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of disk reads during the collection interval."}, + "disk_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second to the datastore."}, + "disk_numberWrite_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of disk writes during the collection interval."}, + "disk_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second to the datastore."}, + "disk_read_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average number of kilobytes read from the disk each second."}, + "disk_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Aggregated disk I/O rate."}, + "disk_write_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average number of kilobytes written to the disk each second."}, + "hbr_hbrNetRx_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Kilobytes per second of outgoing host-based replication network traffic (for this virtual machine or host)."}, + "hbr_hbrNetTx_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average amount of data transmitted per second."}, + "mem_active_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory that is actively used, as estimated by VMkernel based on recently touched memory pages."}, + "mem_activewrite_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Estimate for the amount of memory actively being written to by the virtual machine."}, + "mem_compressed_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory reserved by `userworlds`."}, + "mem_compressionRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of memory compression for the virtual machine."}, + "mem_consumed_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of host physical memory consumed by a virtual machine, host, or cluster."}, + "mem_decompressionRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of memory decompression for the virtual machine."}, + "mem_entitlement_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of host physical memory the virtual machine is entitled to, as determined by the ESX scheduler."}, + "mem_granted_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of host physical memory or physical memory that is mapped for a virtual machine or a host."}, + "mem_latency_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percentage of time the virtual machine is waiting to access swapped or compressed memory."}, + "mem_llSwapInRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate at which memory is being swapped from host cache into active memory."}, + "mem_llSwapOutRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate at which memory is being swapped from active memory to host cache."}, + "mem_llSwapUsed_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Space used for caching swapped pages in the host cache."}, + "mem_overhead_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Host physical memory consumed by the virtualization infrastructure for running the virtual machine."}, + "mem_overheadMax_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Host physical memory reserved for use as the virtualization overhead for the virtual machine."}, + "mem_overheadTouched_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Actively touched overhead host physical memory (KB) reserved for use as the virtualization overhead for the virtual machine."}, + "mem_shared_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of guest physical memory that is shared with other virtual machines, relative to a single virtual machine or to all powered-on virtual machines on a host."}, + "mem_swapin_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory swapped-in from disk."}, + "mem_swapinRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate at which memory is swapped from disk into active memory."}, + "mem_swapout_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory swapped-out to disk."}, + "mem_swapoutRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate at which memory is being swapped from active memory to disk."}, + "mem_swapped_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Current amount of guest physical memory swapped out to the virtual machine swap file by the VMkernel. Swapped memory stays on disk until the virtual machine needs it. This statistic refers to VMkernel swapping and not to guest OS swapping."}, + "mem_swaptarget_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Target size for the virtual machine swap file. The VMkernel manages swapping by comparing `swaptarget` against swapped."}, + "mem_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Memory usage as percent of total configured or available memory"}, + "mem_vmmemctl_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory allocated by the virtual machine memory control driver (`vmmemctl`)."}, + "mem_vmmemctltarget_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Target value set by `VMkernal` for the virtual machine's memory balloon size. In conjunction with `vmmemctl` metric, this metric is used by VMkernel to inflate and deflate the balloon for a virtual machine."}, + "mem_zero_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory that contains 0s only. Included in shared amount. Through transparent page sharing, zero memory pages can be shared among virtual machines that run the same operating system."}, + "mem_zipSaved_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory saved due to memory zipping."}, + "mem_zipped_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory zipped"}, + "mem_capacity_usage_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of physical memory actively used."}, + "mem_capacity_contention_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Percentage of time VMs are waiting to access swapped, compressed or ballooned memory."}, + "net_broadcastRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of broadcast packets received."}, + "net_broadcastTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of broadcast packets transmitted."}, + "net_bytesRx_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average amount of data received per second."}, + "net_bytesTx_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average amount of data transmitted per second."}, + "net_droppedRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of received packets dropped."}, + "net_droppedTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of transmitted packets dropped."}, + "net_multicastRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of multicast packets received."}, + "net_multicastTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of multicast packets transmitted."}, + "net_packetsRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of packets received."}, + "net_packetsTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of packets transmitted."}, + "net_pnicBytesRx_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "Average number of bytes received per second by a physical network interface card (`PNIC`) on an ESXi host."}, + "net_pnicBytesTx_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "Average number of bytes transmitted per second by a physical network interface card (`PNIC`) on an ESXi host."}, + "net_received_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average rate at which data was received during the interval. This represents the bandwidth of the network."}, + "net_throughput_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "The current network bandwidth usage for the host."}, + "net_transmitted_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average rate at which data was transmitted during the interval. This represents the bandwidth of the network."}, + "net_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Network utilization (combined transmit- and receive-rates)."}, + "power_energy_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Total energy (in joule) used since last stats reset."}, + "power_power_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Current power usage."}, + "rescpu_actav1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active average over 1 minute."}, + "rescpu_actav15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active average over 15 minutes."}, + "rescpu_actav5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active average over 5 minutes."}, + "rescpu_actpk1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active peak over 1 minute."}, + "rescpu_actpk15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active peak over 15 minutes."}, + "rescpu_actpk5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active peak over 5 minutes."}, + "rescpu_maxLimited1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Amount of CPU resources over the limit that were refused, average over 1 minute."}, + "rescpu_maxLimited15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Amount of CPU resources over the limit that were refused, average over 15 minutes."}, + "rescpu_maxLimited5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Amount of CPU resources over the limit that were refused, average over 5 minutes."}, + "rescpu_runav1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running average over 1 minute."}, + "rescpu_runav15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running average over 15 minutes."}, + "rescpu_runav5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running average over 5 minutes."}, + "rescpu_runpk1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running peak over 1 minute."}, + "rescpu_runpk15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running peak over 15 minutes."}, + "rescpu_runpk5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running peak over 5 minutes."}, + "rescpu_sampleCount_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Group CPU sample count."}, + "rescpu_samplePeriod_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Group CPU sample period."}, + "sys_heartbeat_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of heartbeats issued per virtual machine."}, + "sys_heartbeat_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of heartbeats issued per virtual machine."}, + "sys_osUptime_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationSecond, Desc: "Total time elapsed, in seconds, since last operating system boot-up."}, + "sys_uptime_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationSecond, Desc: "Total time elapsed since last system startup"}, + "virtualDisk_busResets_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI-bus reset commands issued."}, + "virtualDisk_commandsAborted_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI commands aborted"}, + "virtualDisk_largeSeeks_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of seeks during the interval that were greater than 8192 LBNs apart."}, + "virtualDisk_mediumSeeks_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of seeks during the interval that were between 64 and 8192 LBNs apart."}, + "virtualDisk_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second to the virtual disk."}, + "virtualDisk_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second to the virtual disk."}, + "virtualDisk_read_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of kilobytes read from the virtual disk each second."}, + "virtualDisk_readIOSize_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "Average read request size in bytes."}, + "virtualDisk_readLatencyUS_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationUS, Desc: "Read latency in microseconds."}, + "virtualDisk_readLoadMetric_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage DRS virtual disk metric for the read workload model."}, + "virtualDisk_readOIO_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of outstanding read requests to the virtual disk."}, + "virtualDisk_smallSeeks_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of seeks during the interval that were less than 64 LBNs apart."}, + "virtualDisk_totalReadLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a read operation from the virtual disk."}, + "virtualDisk_totalWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a write operation from the virtual disk."}, + "virtualDisk_write_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average number of kilobytes written to the virtual disk each second."}, + "virtualDisk_writeIOSize_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "Average write request size in bytes."}, + "virtualDisk_writeLatencyUS_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationUS, Desc: "Write latency in microseconds."}, + "virtualDisk_writeLoadMetric_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage DRS virtual disk metric for the write workload model."}, + "virtualDisk_writeOIO_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of outstanding write requests to the virtual disk."}, + }, + Tags: map[string]interface{}{ + "dcname": &inputs.TagInfo{Desc: "`Datacenter` name"}, + "cluster_name": &inputs.TagInfo{Desc: "Cluster name"}, + "esx_hostname": &inputs.TagInfo{Desc: "The name of the ESXi host"}, + "instance": &inputs.TagInfo{Desc: "The name of the instance"}, + "host": &inputs.TagInfo{Desc: "The host of the vCenter"}, + "moid": &inputs.TagInfo{Desc: "The managed object id"}, + "vm_name": &inputs.TagInfo{Desc: "The name of the resource"}, + }, + } +} + +type hostMeasurement struct { + Measurement +} + +//nolint:lll +func (m *hostMeasurement) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_host", + Type: "metric", + Fields: map[string]interface{}{ + "cpu_costop_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Time the virtual machine is ready to run, but is unable to run due to co-scheduling constraints."}, + "cpu_demand_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "The amount of CPU resources a virtual machine would use if there were no CPU contention or CPU limit."}, + "cpu_idle_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Total time that the CPU spent in an idle state."}, + "cpu_latency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percent of time the virtual machine is unable to run because it is contending for access to the physical CPU(s)."}, + "cpu_readiness_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percentage of time that the virtual machine was ready, but could not get scheduled to run on the physical CPU."}, + "cpu_ready_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Milliseconds of CPU time spent in ready state."}, + "cpu_swapwait_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "CPU time spent waiting for swap-in."}, + "cpu_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percentage of CPU capacity being used."}, + "cpu_usagemhz_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "CPU usage, as measured in megahertz."}, + "cpu_used_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Time accounted to the virtual machine. If a system service runs on behalf of this virtual machine, the time spent by that service (represented by cpu.system) should be charged to this virtual machine. If not, the time spent (represented by cpu.overlap) should not be charged against this virtual machine."}, + "cpu_wait_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Total CPU time spent in wait state.The wait total includes time spent the CPU Idle, CPU Swap Wait, and CPU I/O Wait states."}, + "cpu_capacity_usage_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "CPU usage as a percent during the interval."}, + "cpu_capacity_contention_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percent of time the virtual machine is unable to run because it is contending for access to the physical CPU(s)."}, + "datastore_maxTotalLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Highest latency value across all datastores used by the host."}, + "datastore_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second to the datastore."}, + "datastore_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second to the datastore during the collection interval."}, + "datastore_read_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of reading data from the datastore."}, + "datastore_totalReadLatency_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a read operation from the datastore."}, + "datastore_totalWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a write operation from the datastore."}, + "datastore_write_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of writing data to the datastore."}, + "disk_busResets_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI-bus reset commands issued."}, + "disk_commands_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI commands issued"}, + "disk_commandsAborted_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI commands aborted."}, + "disk_commandsAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of SCSI commands issued per second."}, + "disk_maxTotalLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Highest latency value across all disks used by the host."}, + "disk_numberRead_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of disk reads during the collection interval."}, + "disk_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second to the datastore."}, + "disk_numberWrite_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of disk writes during the collection interval."}, + "disk_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second to the datastore."}, + "disk_read_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average number of kilobytes read from the disk each second."}, + "disk_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Aggregated disk I/O rate."}, + "disk_write_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average number of kilobytes written to the disk each second."}, + "hbr_hbrNetRx_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Kilobytes per second of outgoing host-based replication network traffic (for this virtual machine or host)."}, + "hbr_hbrNetTx_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average amount of data transmitted per second."}, + "mem_active_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory that is actively used, as estimated by VMkernel based on recently touched memory pages."}, + "mem_activewrite_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Estimate for the amount of memory actively being written to by the virtual machine."}, + "mem_compressed_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory reserved by `userworlds`."}, + "mem_compressionRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of memory compression for the virtual machine."}, + "mem_consumed_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of host physical memory consumed by a virtual machine, host, or cluster."}, + "mem_decompressionRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of memory decompression for the virtual machine."}, + "mem_granted_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of host physical memory or physical memory that is mapped for a virtual machine or a host."}, + "mem_latency_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percentage of time the virtual machine is waiting to access swapped or compressed memory."}, + "mem_llSwapInRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate at which memory is being swapped from host cache into active memory."}, + "mem_llSwapOutRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate at which memory is being swapped from active memory to host cache."}, + "mem_llSwapUsed_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Space used for caching swapped pages in the host cache."}, + "mem_overhead_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Host physical memory consumed by the virtualization infrastructure for running the virtual machine."}, + "mem_shared_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of guest physical memory that is shared with other virtual machines, relative to a single virtual machine or to all powered-on virtual machines on a host."}, + "mem_swapin_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory swapped-in from disk."}, + "mem_swapinRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate at which memory is swapped from disk into active memory."}, + "mem_swapout_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory swapped-out to disk."}, + "mem_swapoutRate_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate at which memory is being swapped from active memory to disk."}, + "mem_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Memory usage as percent of total configured or available memory"}, + "mem_vmmemctl_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory allocated by the virtual machine memory control driver (`vmmemctl`)."}, + "mem_zero_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory that contains 0s only. Included in shared amount. Through transparent page sharing, zero memory pages can be shared among virtual machines that run the same operating system."}, + "mem_capacity_usage_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of physical memory actively used."}, + "mem_capacity_contention_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Percentage of time VMs are waiting to access swapped, compressed or ballooned memory."}, + "net_broadcastRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of broadcast packets received."}, + "net_broadcastTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of broadcast packets transmitted."}, + "net_bytesRx_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average amount of data received per second."}, + "net_bytesTx_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average amount of data transmitted per second."}, + "net_droppedRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of received packets dropped."}, + "net_droppedTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of transmitted packets dropped."}, + "net_multicastRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of multicast packets received."}, + "net_multicastTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of multicast packets transmitted."}, + "net_packetsRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of packets received."}, + "net_packetsTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of packets transmitted."}, + "net_received_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average rate at which data was received during the interval. This represents the bandwidth of the network."}, + "net_throughput_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "The current network bandwidth usage for the host."}, + "net_transmitted_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Average rate at which data was transmitted during the interval. This represents the bandwidth of the network."}, + "net_usage_average": &inputs.FieldInfo{DataType: inputs.Float, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Network utilization (combined transmit- and receive-rates)."}, + "power_energy_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Total energy (in joule) used since last stats reset."}, + "power_power_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Current power usage."}, + "rescpu_actav1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active average over 1 minute."}, + "rescpu_actav15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active average over 15 minutes."}, + "rescpu_actav5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active average over 5 minutes."}, + "rescpu_actpk1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active peak over 1 minute."}, + "rescpu_actpk15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active peak over 15 minutes."}, + "rescpu_actpk5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active peak over 5 minutes."}, + "rescpu_maxLimited1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Amount of CPU resources over the limit that were refused, average over 1 minute."}, + "rescpu_maxLimited15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Amount of CPU resources over the limit that were refused, average over 15 minutes."}, + "rescpu_maxLimited5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Amount of CPU resources over the limit that were refused, average over 5 minutes."}, + "rescpu_runav1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running average over 1 minute."}, + "rescpu_runav15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running average over 15 minutes."}, + "rescpu_runav5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running average over 5 minutes."}, + "rescpu_runpk1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running peak over 1 minute."}, + "rescpu_runpk15_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running peak over 15 minutes."}, + "rescpu_runpk5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running peak over 5 minutes."}, + "rescpu_sampleCount_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Group CPU sample count."}, + "rescpu_samplePeriod_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Group CPU sample period."}, + "sys_uptime_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationSecond, Desc: "Total time elapsed since last system startup"}, + "virtualDisk_busResets_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI-bus reset commands issued."}, + "virtualDisk_commandsAborted_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI commands aborted"}, + "cpu_coreUtilization_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU utilization of the corresponding core (if hyper-threading is enabled) as a percentage."}, + "cpu_reservedCapacity_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Total CPU capacity reserved by virtual machines."}, + "cpu_totalCapacity_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Total CPU capacity reserved by and available for virtual machines."}, + "cpu_utilization_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU utilization as a percentage during the interval (CPU usage and CPU utilization might be different due to power management technologies or hyper-threading)."}, + "datastore_datastoreIops_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage I/O Control aggregated IOPS."}, + "datastore_datastoreMaxQueueDepth_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage I/O Control datastore maximum queue depth."}, + "datastore_datastoreNormalReadLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Storage DRS datastore normalized read latency."}, + "datastore_datastoreNormalWriteLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Storage DRS datastore normalized write latency."}, + "datastore_datastoreReadBytes_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Storage DRS datastore bytes read."}, + "datastore_datastoreReadIops_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage DRS datastore read I/O rate."}, + "datastore_datastoreReadLoadMetric_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage DRS datastore metric for read workload model."}, + "datastore_datastoreReadOIO_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage DRS datastore outstanding read requests."}, + "datastore_datastoreVMObservedLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationUS, Desc: "The average datastore latency as seen by virtual machines."}, + "datastore_datastoreWriteBytes_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Storage DRS datastore bytes written."}, + "datastore_datastoreWriteIops_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage DRS datastore write I/O rate."}, + "datastore_datastoreWriteLoadMetric_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage DRS datastore metric for write workload model."}, + "datastore_datastoreWriteOIO_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Storage DRS datastore outstanding write requests."}, + "datastore_siocActiveTimePercentage_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Percentage of time Storage I/O Control actively controlled datastore latency."}, + "datastore_sizeNormalizedDatastoreLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationUS, Desc: "Storage I/O Control size-normalized I/O latency."}, + "disk_deviceLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time it takes to complete an SCSI command from physical device."}, + "disk_deviceReadLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time to read from the physical device."}, + "disk_deviceWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time to write from the physical device."}, + "disk_kernelLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time spent by VMkernel to process each SCSI command."}, + "disk_kernelReadLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time spent by VMkernel to process each SCSI read command."}, + "disk_kernelWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time spent by VMkernel to process each SCSI write command."}, + "disk_maxQueueDepth_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Maximum queue depth."}, + "disk_queueLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time spent in the VMkernel queue per SCSI command."}, + "disk_queueReadLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time spent in the VMkernel queue per SCSI read command."}, + "disk_queueWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time spent in the VMkernel queue per SCSI write command."}, + "disk_scsiReservationCnflctsPct_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Number of SCSI reservation conflicts for the LUN as a percent of total commands during the collection interval."}, + "disk_scsiReservationConflicts_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI reservation conflicts for the LUN during the collection interval."}, + "disk_totalLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time taken during the collection interval to process a SCSI command issued by the guest OS to the virtual machine."}, + "disk_totalReadLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time taken to process a SCSI read command issued from the guest OS to the virtual machine."}, + "disk_totalWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time taken to process a SCSI write command issued by the guest OS to the virtual machine."}, + "hbr_hbrNumVms_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of powered-on virtual machines running on this host that currently have host-based replication protection enabled."}, + "mem_consumed_userworlds.avg": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of physical memory consumed by `userworlds` on this host."}, + "mem_consumed_vms.avg": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of physical memory consumed by VMs on this host."}, + "mem_heap_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "VMkernel virtual address space dedicated to VMkernel main heap and related data."}, + "mem_heapfree_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Free address space in the VMkernel main heap.Varies based on number of physical devices and configuration options. There is no direct way for the user to increase or decrease this statistic. For informational purposes only: not useful for performance monitoring."}, + "mem_llSwapIn_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory swapped-in from host cache."}, + "mem_llSwapOut_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory swapped-out to host cache."}, + "mem_lowfreethreshold_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Threshold of free host physical memory below which ESX/ESXi will begin reclaiming memory from virtual machines through ballooning and swapping."}, + "mem_reservedCapacity_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeMB, Desc: "Total amount of memory reservation used by powered-on virtual machines and vSphere services on the host."}, + "mem_sharedcommon_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of machine memory that is shared by all powered-on virtual machines and vSphere services on the host."}, + "mem_state_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "One of four threshold levels representing the percentage of free memory on the host. The counter value determines swapping and ballooning behavior for memory reclamation."}, + "mem_swapused_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory that is used by swap. Sum of memory swapped of all powered on VMs and vSphere services on the host."}, + "mem_sysUsage_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of host physical memory used by VMkernel for core functionality, such as device drivers and other internal uses. Does not include memory used by virtual machines or vSphere services."}, + "mem_totalCapacity_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeMB, Desc: "Total amount of memory reservation used by and available for powered-on virtual machines and vSphere services on the host."}, + "mem_unreserved_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of memory that is unreserved. Memory reservation not used by the Service Console, VMkernel, vSphere services and other powered on VMs user-specified memory reservations and overhead memory."}, + "mem_vmfs_pbc_capMissRatio_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "Trailing average of the ratio of capacity misses to compulsory misses for the `VMFS` PB Cache."}, + "mem_vmfs_pbc_overhead_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Amount of `VMFS` heap used by the `VMFS` PB Cache."}, + "mem_vmfs_pbc_size_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeMB, Desc: "Space used for holding `VMFS` Pointer Blocks in memory."}, + "mem_vmfs_pbc_sizeMax_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeMB, Desc: "Maximum size the `VMFS` Pointer Block Cache can grow to."}, + "mem_vmfs_pbc_workingSet_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeTB, Desc: "Amount of file blocks whose addresses are cached in the `VMFS` PB Cache."}, + "mem_vmfs_pbc_workingSetMax_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeTB, Desc: "Maximum amount of file blocks whose addresses are cached in the `VMFS` PB Cache."}, + "net_errorsRx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of packets with errors received."}, + "net_errorsTx_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of packets with errors transmitted."}, + "net_unknownProtos_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Number of frames with unknown protocol received."}, + "power_powerCap_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Maximum allowed power usage."}, + "storageAdapter_commandsAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of commands issued per second by the storage adapter."}, + "storageAdapter_maxTotalLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Highest latency value across all storage adapters used by the host."}, + "storageAdapter_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second by the storage adapter."}, + "storageAdapter_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second by the storage adapter."}, + "storageAdapter_outstandingIOs_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "The number of I/Os that have been issued but have not yet completed."}, + "storageAdapter_queueDepth_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "The maximum number of I/Os that can be outstanding at a given time."}, + "storageAdapter_queueLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average amount of time spent in the VMkernel queue per SCSI command."}, + "storageAdapter_queued_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "The current number of I/Os that are waiting to be issued."}, + "storageAdapter_read_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of reading data by the storage adapter."}, + "storageAdapter_totalReadLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a read operation by the storage adapter."}, + "storageAdapter_totalWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a write operation by the storage adapter."}, + "storageAdapter_write_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of writing data by the storage adapter."}, + "storagePath_busResets_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI-bus reset commands issued."}, + "storagePath_commandsAborted_sum": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of SCSI commands aborted."}, + "storagePath_commandsAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of commands issued per second on the storage path during the collection interval."}, + "storagePath_maxTotalLatency_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Highest latency value across all storage paths used by the host."}, + "storagePath_numberReadAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of read commands issued per second on the storage path during the collection interval."}, + "storagePath_numberWriteAveraged_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Average number of write commands issued per second on the storage path during the collection interval."}, + "storagePath_read_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of reading data on the storage path."}, + "storagePath_totalReadLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a read issued on the storage path. Total latency = kernel latency + device latency."}, + "storagePath_totalWriteLatency_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.DurationMS, Desc: "Average amount of time for a write issued on the storage path. Total latency = kernel latency + device latency."}, + "storagePath_write_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Rate of writing data on the storage path."}, + "sys_resourceCpuAct1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active average over 1 minute of the system resource group."}, + "sys_resourceCpuAct5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU active average over 5 minutes of the system resource group."}, + "sys_resourceCpuAllocMax_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "CPU allocation limit (in MHz) of the system resource group."}, + "sys_resourceCpuAllocMin_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "CPU allocation reservation (in MHz) of the system resource group."}, + "sys_resourceCpuAllocShares_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "CPU allocation shares of the system resource group."}, + "sys_resourceCpuMaxLimited1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU maximum limited over 1 minute of the system resource group."}, + "sys_resourceCpuMaxLimited5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU maximum limited over 5 minutes of the system resource group."}, + "sys_resourceCpuRun1_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running average over 1 minute of the system."}, + "sys_resourceCpuRun5_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.Percent, Desc: "CPU running average over 5 minutes of the system resource group."}, + "sys_resourceCpuUsage_average": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Amount of CPU used by the Service Console and other applications during the interval by the Service Console and other applications."}, + "sys_resourceFdUsage_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Number of file descriptors used by the system resource group."}, + "sys_resourceMemAllocMax_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory allocation limit (in KB) of the system resource group."}, + "sys_resourceMemAllocMin_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory allocation reservation (in KB) of the system resource group."}, + "sys_resourceMemAllocShares_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Memory allocation shares of the system resource group."}, + "sys_resourceMemConsumed_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory consumed by the system resource group."}, + "sys_resourceMemCow_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory shared by the system resource group."}, + "sys_resourceMemMapped_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory mapped by the system resource group."}, + "sys_resourceMemOverhead_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Overhead memory consumed by the system resource group."}, + "sys_resourceMemShared_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory saved due to sharing by the system resource group."}, + "sys_resourceMemSwapped_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory swapped out by the system resource group."}, + "sys_resourceMemTouched_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Memory touched by the system resource group."}, + "sys_resourceMemZero_latest": &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeKB, Desc: "Zero filled memory used by the system resource group."}, + }, + Tags: map[string]interface{}{ + "cluster_name": &inputs.TagInfo{Desc: "Cluster name"}, + "dcname": &inputs.TagInfo{Desc: "`Datacenter` name"}, + "esx_hostname": &inputs.TagInfo{Desc: "The name of the ESXi host"}, + "instance": &inputs.TagInfo{Desc: "The name of the instance"}, + "host": &inputs.TagInfo{Desc: "The host of the vCenter"}, + "moid": &inputs.TagInfo{Desc: "The managed object id"}, + }, + } +} + +type hostObject struct{} + +// nolint: lll +func (*hostObject) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_host", + Desc: "The object of the ESXi host.", + Type: "object", + Tags: map[string]interface{}{ + Name: &inputs.TagInfo{Desc: "The name of the ESXi host"}, + Vendor: &inputs.TagInfo{Desc: "The hardware vendor identification"}, + Model: &inputs.TagInfo{Desc: "The system model identification"}, + CPUModel: &inputs.TagInfo{Desc: "The CPU model"}, + ConnectionState: &inputs.TagInfo{Desc: "The host connection state"}, + }, + Fields: map[string]interface{}{ + MemorySize: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "The physical memory size in bytes."}, + NumCPUCores: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Number of physical CPU cores on the host. Physical CPU cores are the processors contained by a CPU package."}, + NumNics: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "The number of network adapters."}, + BootTime: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.TimestampNS, Desc: "The time when the host was booted."}, + }, + } +} + +type vmObject struct{} + +// nolint: lll +func (*vmObject) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_vm", + Desc: "The object of the virtual machine.", + Type: "object", + Tags: map[string]interface{}{ + Name: &inputs.TagInfo{Desc: "The name of the virtual machine"}, + GuestFullName: &inputs.TagInfo{Desc: "Guest operating system full name, if known"}, + HostName: &inputs.TagInfo{Desc: "Hostname of the guest operating system, if known"}, + IPAddress: &inputs.TagInfo{Desc: "Primary IP address assigned to the guest operating system, if known"}, + ConnectionState: &inputs.TagInfo{Desc: "Indicates whether or not the virtual machine is available for management"}, + Template: &inputs.TagInfo{Desc: "Flag to determine whether or not this virtual machine is a template."}, + }, + Fields: map[string]interface{}{ + BootTime: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.TimestampNS, Desc: "The timestamp when the virtual machine was most recently powered on."}, + MaxCPUUsage: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Current upper-bound on CPU usage."}, + MaxMemoryUsage: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Current upper-bound on memory usage."}, + NumCPU: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Number of processors in the virtual machine."}, + NumEthernetCards: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Number of virtual network adapters."}, + NumVirtualDisks: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Number of virtual disks attached to the virtual machine."}, + MemorySizeMB: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Memory size of the virtual machine, in megabytes."}, + }, + } +} + +type clusterObject struct{} + +// nolint: lll +func (*clusterObject) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_cluster", + Desc: "The object of the cluster.", + Type: "object", + Tags: map[string]interface{}{ + Name: &inputs.TagInfo{Desc: "The name of the cluster"}, + }, + Fields: map[string]interface{}{ + TotalCPU: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "Aggregated CPU resources of all hosts, in MHz."}, + TotalMemory: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "Aggregated memory resources of all hosts, in bytes."}, + NumHosts: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Total number of hosts."}, + NumEffectiveHosts: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Total number of effective hosts."}, + NumCPUCores: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Number of physical CPU cores. Physical CPU cores are the processors contained by a CPU package."}, + NumCPUThreads: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Aggregated number of CPU threads."}, + EffectiveCPU: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.NCount, Desc: "Effective CPU resources (in MHz) available to run virtual machines."}, + EffectiveMemory: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeMB, Desc: "Effective memory resources (in MB) available to run virtual machines. "}, + }, + } +} + +type datastoreObject struct{} + +// nolint: lll +func (*datastoreObject) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: "vsphere_datastore", + Desc: "The object of the datastore.", + Type: "object", + Tags: map[string]interface{}{ + Name: &inputs.TagInfo{Desc: "The name of the datastore"}, + URL: &inputs.TagInfo{Desc: "The unique locator for the datastore"}, + Type: &inputs.TagInfo{Desc: "Type of file system volume, such as `VMFS` or NFS"}, + }, + Fields: map[string]interface{}{ + FreeSpace: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "Free space of this datastore, in bytes. The server periodically updates this value. It can be explicitly refreshed with the Refresh operation."}, + MaxFileSize: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "The maximum size of a file that can reside on this file system volume."}, + MaxMemoryFileSize: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "The maximum size of a snapshot or a swap file that can reside on this file system volume."}, + MaxVirtualDiskCapacity: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.SizeByte, Desc: "The maximum capacity of a virtual disk which can be created on this volume."}, + }, + } +} + +type eventMeasurement struct{} + +// nolint: lll +func (*eventMeasurement) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{ + Name: EventMeasurementName, + Desc: "The event of the vSphere.", + Type: "logging", + Tags: map[string]interface{}{ + Status: &inputs.TagInfo{Desc: "The status of the logging"}, + "host": &inputs.TagInfo{Desc: "The host of the vCenter"}, + EventTypeID: &inputs.TagInfo{Desc: "The type of the event"}, + ObjectName: &inputs.TagInfo{Desc: "The name of the object"}, + UserName: &inputs.TagInfo{Desc: "The user who caused the event"}, + ResourceType: &inputs.TagInfo{Desc: "The resource type, such as host, vm, datastore"}, + ChangeTag: &inputs.TagInfo{Desc: "The user entered tag to identify the operations and their side effects"}, + }, + Fields: map[string]interface{}{ + Message: &inputs.FieldInfo{DataType: inputs.String, Type: inputs.UnknownType, Unit: inputs.UnknownUnit, Desc: "A formatted text message describing the event. The message may be localized."}, + ChainID: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "The parent or group ID."}, + EventKey: &inputs.FieldInfo{DataType: inputs.Int, Type: inputs.Gauge, Unit: inputs.UnknownUnit, Desc: "The event ID."}, + }, + } +} diff --git a/internal/plugins/inputs/vsphere/object.go b/internal/plugins/inputs/vsphere/object.go new file mode 100644 index 0000000000..341fd7e3ed --- /dev/null +++ b/internal/plugins/inputs/vsphere/object.go @@ -0,0 +1,35 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package vsphere + +import ( + "github.com/GuanceCloud/cliutils/point" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/datakit" + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/plugins/inputs" +) + +type Object struct { + class string + tags map[string]string + fields map[string]interface{} + election bool +} + +// Point implement MeasurementV2. +func (m *Object) Point() *point.Point { + opts := point.DefaultObjectOptions() + if m.election { + opts = append(opts, point.WithExtraTags(datakit.GlobalElectionTags())) + } + + return point.NewPointV2(m.class, + append(point.NewTags(m.tags), point.NewKVs(m.fields)...), + opts...) +} + +func (m *Object) Info() *inputs.MeasurementInfo { + return &inputs.MeasurementInfo{} +} diff --git a/internal/plugins/inputs/vsphere/object_collect.go b/internal/plugins/inputs/vsphere/object_collect.go new file mode 100644 index 0000000000..01de86146c --- /dev/null +++ b/internal/plugins/inputs/vsphere/object_collect.go @@ -0,0 +1,116 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package vsphere + +import ( + "fmt" + + "github.com/vmware/govmomi/vim25/mo" +) + +// nolint: funlen +func getHostTagsAndFields(host *mo.HostSystem) (map[string]string, map[string]interface{}) { + tags := map[string]string{} + fields := map[string]interface{}{} + + tags[Name] = host.Name + + summary := host.Summary + + if summary.Hardware != nil { + tags[Vendor] = summary.Hardware.Vendor + tags[Model] = summary.Hardware.Model + tags[CPUModel] = summary.Hardware.CpuModel + fields[NumCPUCores] = summary.Hardware.NumCpuCores + fields[MemorySize] = summary.Hardware.MemorySize + fields[NumNics] = summary.Hardware.NumNics + } + + if summary.Runtime != nil { + tags[ConnectionState] = string(summary.Runtime.ConnectionState) + fields[BootTime] = summary.Runtime.BootTime.UnixNano() + } + + return tags, fields +} + +func getVMTagsAndFields(vm *mo.VirtualMachine) (map[string]string, map[string]interface{}) { + tags := map[string]string{} + fields := map[string]interface{}{} + + tags[Name] = vm.Name + + summary := vm.Summary + + // guest + if summary.Guest != nil { + tags[GuestFullName] = summary.Guest.GuestFullName + tags[HostName] = summary.Guest.HostName + tags[IPAddress] = summary.Guest.IpAddress + } + + // config + config := summary.Config + fields[NumCPU] = config.NumCpu + fields[NumEthernetCards] = config.NumEthernetCards + fields[NumVirtualDisks] = config.NumVirtualDisks + fields[MemorySizeMB] = config.MemorySizeMB + tags[Template] = fmt.Sprintf("%v", config.Template) + + // runtime + runtime := summary.Runtime + tags[ConnectionState] = string(runtime.ConnectionState) + fields[BootTime] = runtime.BootTime.UnixNano() + fields[MaxCPUUsage] = runtime.MaxCpuUsage + fields[MaxMemoryUsage] = runtime.MaxMemoryUsage + + return tags, fields +} + +func getClusterTagsAndFields(cluster *mo.ClusterComputeResource) (map[string]string, map[string]interface{}) { + tags := map[string]string{} + fields := map[string]interface{}{} + + tags[Name] = cluster.Name + + if cluster.Summary != nil { + s := cluster.Summary.GetComputeResourceSummary() + if s != nil { + fields[TotalCPU] = s.TotalCpu + fields[NumHosts] = s.NumHosts + fields[NumEffectiveHosts] = s.NumEffectiveHosts + fields[TotalMemory] = s.TotalMemory + fields[NumCPUCores] = s.NumCpuCores + fields[NumCPUThreads] = s.NumCpuThreads + fields[EffectiveCPU] = s.EffectiveCpu + fields[EffectiveMemory] = s.EffectiveMemory + } + } + + return tags, fields +} + +func getDatastoreTagsAndFields(ds *mo.Datastore) (map[string]string, map[string]interface{}) { + tags := map[string]string{} + fields := map[string]interface{}{} + + tags[Name] = ds.Name + + if ds.Info != nil { + info := ds.Info.GetDatastoreInfo() + if info != nil { + tags[URL] = info.Url + fields[FreeSpace] = info.FreeSpace + fields[MaxFileSize] = info.MaxFileSize + fields[MaxMemoryFileSize] = info.MaxMemoryFileSize + fields[MaxVirtualDiskCapacity] = info.MaxVirtualDiskCapacity + } + } + + tags[Type] = ds.Summary.Type + + return tags, fields +} diff --git a/internal/plugins/inputs/vsphere/util.go b/internal/plugins/inputs/vsphere/util.go new file mode 100644 index 0000000000..c852ead1cb --- /dev/null +++ b/internal/plugins/inputs/vsphere/util.go @@ -0,0 +1,42 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package vsphere + +import ( + "fmt" + "strings" + + "gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/filter" +) + +func anythingEnabled(ex []string) bool { + for _, s := range ex { + if s == "*" { + return false + } + } + return true +} + +func isSimple(include []string, exclude []string) bool { + if len(exclude) > 0 || len(include) == 0 { + return false + } + for _, s := range include { + if strings.Contains(s, "*") { + return false + } + } + return true +} + +func newFilterOrPanic(include []string, exclude []string) filter.Filter { + f, err := filter.NewIncludeExcludeFilter(include, exclude) + if err != nil { + panic(fmt.Sprintf("Include/exclude filters are invalid: %v", err)) + } + return f +} diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go index 087320da7f..0f5b8a48c6 100644 --- a/vendor/github.com/google/go-cmp/cmp/compare.go +++ b/vendor/github.com/google/go-cmp/cmp/compare.go @@ -5,7 +5,7 @@ // Package cmp determines equality of values. // // This package is intended to be a more powerful and safer alternative to -// reflect.DeepEqual for comparing whether two values are semantically equal. +// [reflect.DeepEqual] for comparing whether two values are semantically equal. // It is intended to only be used in tests, as performance is not a goal and // it may panic if it cannot compare the values. Its propensity towards // panicking means that its unsuitable for production environments where a @@ -18,16 +18,17 @@ // For example, an equality function may report floats as equal so long as // they are within some tolerance of each other. // -// - Types with an Equal method may use that method to determine equality. -// This allows package authors to determine the equality operation -// for the types that they define. +// - Types with an Equal method (e.g., [time.Time.Equal]) may use that method +// to determine equality. This allows package authors to determine +// the equality operation for the types that they define. // // - If no custom equality functions are used and no Equal method is defined, // equality is determined by recursively comparing the primitive kinds on -// both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, +// both values, much like [reflect.DeepEqual]. Unlike [reflect.DeepEqual], // unexported fields are not compared by default; they result in panics -// unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported) -// or explicitly compared using the Exporter option. +// unless suppressed by using an [Ignore] option +// (see [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported]) +// or explicitly compared using the [Exporter] option. package cmp import ( @@ -45,14 +46,14 @@ import ( // Equal reports whether x and y are equal by recursively applying the // following rules in the given order to x and y and all of their sub-values: // -// - Let S be the set of all Ignore, Transformer, and Comparer options that +// - Let S be the set of all [Ignore], [Transformer], and [Comparer] options that // remain after applying all path filters, value filters, and type filters. -// If at least one Ignore exists in S, then the comparison is ignored. -// If the number of Transformer and Comparer options in S is non-zero, +// If at least one [Ignore] exists in S, then the comparison is ignored. +// If the number of [Transformer] and [Comparer] options in S is non-zero, // then Equal panics because it is ambiguous which option to use. -// If S contains a single Transformer, then use that to transform +// If S contains a single [Transformer], then use that to transform // the current values and recursively call Equal on the output values. -// If S contains a single Comparer, then use that to compare the current values. +// If S contains a single [Comparer], then use that to compare the current values. // Otherwise, evaluation proceeds to the next rule. // // - If the values have an Equal method of the form "(T) Equal(T) bool" or @@ -66,21 +67,22 @@ import ( // Functions are only equal if they are both nil, otherwise they are unequal. // // Structs are equal if recursively calling Equal on all fields report equal. -// If a struct contains unexported fields, Equal panics unless an Ignore option -// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option -// explicitly permits comparing the unexported field. +// If a struct contains unexported fields, Equal panics unless an [Ignore] option +// (e.g., [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported]) ignores that field +// or the [Exporter] option explicitly permits comparing the unexported field. // // Slices are equal if they are both nil or both non-nil, where recursively // calling Equal on all non-ignored slice or array elements report equal. // Empty non-nil slices and nil slices are not equal; to equate empty slices, -// consider using cmpopts.EquateEmpty. +// consider using [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty]. // // Maps are equal if they are both nil or both non-nil, where recursively // calling Equal on all non-ignored map entries report equal. // Map keys are equal according to the == operator. -// To use custom comparisons for map keys, consider using cmpopts.SortMaps. +// To use custom comparisons for map keys, consider using +// [github.com/google/go-cmp/cmp/cmpopts.SortMaps]. // Empty non-nil maps and nil maps are not equal; to equate empty maps, -// consider using cmpopts.EquateEmpty. +// consider using [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty]. // // Pointers and interfaces are equal if they are both nil or both non-nil, // where they have the same underlying concrete type and recursively diff --git a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go b/vendor/github.com/google/go-cmp/cmp/export.go similarity index 94% rename from vendor/github.com/google/go-cmp/cmp/export_unsafe.go rename to vendor/github.com/google/go-cmp/cmp/export.go index e2c0f74e83..29f82fe6b2 100644 --- a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go +++ b/vendor/github.com/google/go-cmp/cmp/export.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !purego -// +build !purego - package cmp import ( @@ -12,8 +9,6 @@ import ( "unsafe" ) -const supportExporters = true - // retrieveUnexportedField uses unsafe to forcibly retrieve any field from // a struct such that the value has read-write permissions. // diff --git a/vendor/github.com/google/go-cmp/cmp/export_panic.go b/vendor/github.com/google/go-cmp/cmp/export_panic.go deleted file mode 100644 index ae851fe53f..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/export_panic.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build purego -// +build purego - -package cmp - -import "reflect" - -const supportExporters = false - -func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value { - panic("no support for forcibly accessing unexported fields") -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go similarity index 95% rename from vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go rename to vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go index 16e6860af6..e5dfff69af 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !purego -// +build !purego - package value import ( diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go deleted file mode 100644 index 1a71bfcbd3..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build purego -// +build purego - -package value - -import "reflect" - -// Pointer is an opaque typed pointer and is guaranteed to be comparable. -type Pointer struct { - p uintptr - t reflect.Type -} - -// PointerOf returns a Pointer from v, which must be a -// reflect.Ptr, reflect.Slice, or reflect.Map. -func PointerOf(v reflect.Value) Pointer { - // NOTE: Storing a pointer as an uintptr is technically incorrect as it - // assumes that the GC implementation does not use a moving collector. - return Pointer{v.Pointer(), v.Type()} -} - -// IsNil reports whether the pointer is nil. -func (p Pointer) IsNil() bool { - return p.p == 0 -} - -// Uintptr returns the pointer as a uintptr. -func (p Pointer) Uintptr() uintptr { - return p.p -} diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go index 1f9ca9c489..754496f3b3 100644 --- a/vendor/github.com/google/go-cmp/cmp/options.go +++ b/vendor/github.com/google/go-cmp/cmp/options.go @@ -13,15 +13,15 @@ import ( "github.com/google/go-cmp/cmp/internal/function" ) -// Option configures for specific behavior of Equal and Diff. In particular, -// the fundamental Option functions (Ignore, Transformer, and Comparer), +// Option configures for specific behavior of [Equal] and [Diff]. In particular, +// the fundamental Option functions ([Ignore], [Transformer], and [Comparer]), // configure how equality is determined. // -// The fundamental options may be composed with filters (FilterPath and -// FilterValues) to control the scope over which they are applied. +// The fundamental options may be composed with filters ([FilterPath] and +// [FilterValues]) to control the scope over which they are applied. // -// The cmp/cmpopts package provides helper functions for creating options that -// may be used with Equal and Diff. +// The [github.com/google/go-cmp/cmp/cmpopts] package provides helper functions +// for creating options that may be used with [Equal] and [Diff]. type Option interface { // filter applies all filters and returns the option that remains. // Each option may only read s.curPath and call s.callTTBFunc. @@ -56,9 +56,9 @@ type core struct{} func (core) isCore() {} -// Options is a list of Option values that also satisfies the Option interface. +// Options is a list of [Option] values that also satisfies the [Option] interface. // Helper comparison packages may return an Options value when packing multiple -// Option values into a single Option. When this package processes an Options, +// [Option] values into a single [Option]. When this package processes an Options, // it will be implicitly expanded into a flat list. // // Applying a filter on an Options is equivalent to applying that same filter @@ -105,16 +105,16 @@ func (opts Options) String() string { return fmt.Sprintf("Options{%s}", strings.Join(ss, ", ")) } -// FilterPath returns a new Option where opt is only evaluated if filter f -// returns true for the current Path in the value tree. +// FilterPath returns a new [Option] where opt is only evaluated if filter f +// returns true for the current [Path] in the value tree. // // This filter is called even if a slice element or map entry is missing and // provides an opportunity to ignore such cases. The filter function must be // symmetric such that the filter result is identical regardless of whether the // missing value is from x or y. // -// The option passed in may be an Ignore, Transformer, Comparer, Options, or -// a previously filtered Option. +// The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or +// a previously filtered [Option]. func FilterPath(f func(Path) bool, opt Option) Option { if f == nil { panic("invalid path filter function") @@ -142,7 +142,7 @@ func (f pathFilter) String() string { return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt) } -// FilterValues returns a new Option where opt is only evaluated if filter f, +// FilterValues returns a new [Option] where opt is only evaluated if filter f, // which is a function of the form "func(T, T) bool", returns true for the // current pair of values being compared. If either value is invalid or // the type of the values is not assignable to T, then this filter implicitly @@ -154,8 +154,8 @@ func (f pathFilter) String() string { // If T is an interface, it is possible that f is called with two values with // different concrete types that both implement T. // -// The option passed in may be an Ignore, Transformer, Comparer, Options, or -// a previously filtered Option. +// The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or +// a previously filtered [Option]. func FilterValues(f interface{}, opt Option) Option { v := reflect.ValueOf(f) if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() { @@ -192,9 +192,9 @@ func (f valuesFilter) String() string { return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt) } -// Ignore is an Option that causes all comparisons to be ignored. -// This value is intended to be combined with FilterPath or FilterValues. -// It is an error to pass an unfiltered Ignore option to Equal. +// Ignore is an [Option] that causes all comparisons to be ignored. +// This value is intended to be combined with [FilterPath] or [FilterValues]. +// It is an error to pass an unfiltered Ignore option to [Equal]. func Ignore() Option { return ignore{} } type ignore struct{ core } @@ -234,6 +234,8 @@ func (validator) apply(s *state, vx, vy reflect.Value) { name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType if _, ok := reflect.New(t).Interface().(error); ok { help = "consider using cmpopts.EquateErrors to compare error values" + } else if t.Comparable() { + help = "consider using cmpopts.EquateComparable to compare comparable Go types" } } else { // Unnamed type with unexported fields. Derive PkgPath from field. @@ -254,7 +256,7 @@ const identRx = `[_\p{L}][_\p{L}\p{N}]*` var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) -// Transformer returns an Option that applies a transformation function that +// Transformer returns an [Option] that applies a transformation function that // converts values of a certain type into that of another. // // The transformer f must be a function "func(T) R" that converts values of @@ -265,13 +267,14 @@ var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) // same transform to the output of itself (e.g., in the case where the // input and output types are the same), an implicit filter is added such that // a transformer is applicable only if that exact transformer is not already -// in the tail of the Path since the last non-Transform step. +// in the tail of the [Path] since the last non-[Transform] step. // For situations where the implicit filter is still insufficient, -// consider using cmpopts.AcyclicTransformer, which adds a filter -// to prevent the transformer from being recursively applied upon itself. +// consider using [github.com/google/go-cmp/cmp/cmpopts.AcyclicTransformer], +// which adds a filter to prevent the transformer from +// being recursively applied upon itself. // -// The name is a user provided label that is used as the Transform.Name in the -// transformation PathStep (and eventually shown in the Diff output). +// The name is a user provided label that is used as the [Transform.Name] in the +// transformation [PathStep] (and eventually shown in the [Diff] output). // The name must be a valid identifier or qualified identifier in Go syntax. // If empty, an arbitrary name is used. func Transformer(name string, f interface{}) Option { @@ -329,7 +332,7 @@ func (tr transformer) String() string { return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc)) } -// Comparer returns an Option that determines whether two values are equal +// Comparer returns an [Option] that determines whether two values are equal // to each other. // // The comparer f must be a function "func(T, T) bool" and is implicitly @@ -377,35 +380,32 @@ func (cm comparer) String() string { return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc)) } -// Exporter returns an Option that specifies whether Equal is allowed to +// Exporter returns an [Option] that specifies whether [Equal] is allowed to // introspect into the unexported fields of certain struct types. // // Users of this option must understand that comparing on unexported fields // from external packages is not safe since changes in the internal -// implementation of some external package may cause the result of Equal +// implementation of some external package may cause the result of [Equal] // to unexpectedly change. However, it may be valid to use this option on types // defined in an internal package where the semantic meaning of an unexported // field is in the control of the user. // -// In many cases, a custom Comparer should be used instead that defines +// In many cases, a custom [Comparer] should be used instead that defines // equality as a function of the public API of a type rather than the underlying // unexported implementation. // -// For example, the reflect.Type documentation defines equality to be determined +// For example, the [reflect.Type] documentation defines equality to be determined // by the == operator on the interface (essentially performing a shallow pointer -// comparison) and most attempts to compare *regexp.Regexp types are interested +// comparison) and most attempts to compare *[regexp.Regexp] types are interested // in only checking that the regular expression strings are equal. -// Both of these are accomplished using Comparers: +// Both of these are accomplished using [Comparer] options: // // Comparer(func(x, y reflect.Type) bool { return x == y }) // Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() }) // -// In other cases, the cmpopts.IgnoreUnexported option can be used to ignore -// all unexported fields on specified struct types. +// In other cases, the [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported] +// option can be used to ignore all unexported fields on specified struct types. func Exporter(f func(reflect.Type) bool) Option { - if !supportExporters { - panic("Exporter is not supported on purego builds") - } return exporter(f) } @@ -415,10 +415,10 @@ func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableO panic("not implemented") } -// AllowUnexported returns an Options that allows Equal to forcibly introspect +// AllowUnexported returns an [Option] that allows [Equal] to forcibly introspect // unexported fields of the specified struct types. // -// See Exporter for the proper use of this option. +// See [Exporter] for the proper use of this option. func AllowUnexported(types ...interface{}) Option { m := make(map[reflect.Type]bool) for _, typ := range types { @@ -432,7 +432,7 @@ func AllowUnexported(types ...interface{}) Option { } // Result represents the comparison result for a single node and -// is provided by cmp when calling Report (see Reporter). +// is provided by cmp when calling Report (see [Reporter]). type Result struct { _ [0]func() // Make Result incomparable flags resultFlags @@ -445,7 +445,7 @@ func (r Result) Equal() bool { } // ByIgnore reports whether the node is equal because it was ignored. -// This never reports true if Equal reports false. +// This never reports true if [Result.Equal] reports false. func (r Result) ByIgnore() bool { return r.flags&reportByIgnore != 0 } @@ -455,7 +455,7 @@ func (r Result) ByMethod() bool { return r.flags&reportByMethod != 0 } -// ByFunc reports whether a Comparer function determined equality. +// ByFunc reports whether a [Comparer] function determined equality. func (r Result) ByFunc() bool { return r.flags&reportByFunc != 0 } @@ -478,7 +478,7 @@ const ( reportByCycle ) -// Reporter is an Option that can be passed to Equal. When Equal traverses +// Reporter is an [Option] that can be passed to [Equal]. When [Equal] traverses // the value trees, it calls PushStep as it descends into each node in the // tree and PopStep as it ascend out of the node. The leaves of the tree are // either compared (determined to be equal or not equal) or ignored and reported diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go index a0a588502e..c3c1456423 100644 --- a/vendor/github.com/google/go-cmp/cmp/path.go +++ b/vendor/github.com/google/go-cmp/cmp/path.go @@ -14,9 +14,9 @@ import ( "github.com/google/go-cmp/cmp/internal/value" ) -// Path is a list of PathSteps describing the sequence of operations to get +// Path is a list of [PathStep] describing the sequence of operations to get // from some root type to the current position in the value tree. -// The first Path element is always an operation-less PathStep that exists +// The first Path element is always an operation-less [PathStep] that exists // simply to identify the initial type. // // When traversing structs with embedded structs, the embedded struct will @@ -29,8 +29,13 @@ type Path []PathStep // a value's tree structure. Users of this package never need to implement // these types as values of this type will be returned by this package. // -// Implementations of this interface are -// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. +// Implementations of this interface: +// - [StructField] +// - [SliceIndex] +// - [MapIndex] +// - [Indirect] +// - [TypeAssertion] +// - [Transform] type PathStep interface { String() string @@ -70,8 +75,9 @@ func (pa *Path) pop() { *pa = (*pa)[:len(*pa)-1] } -// Last returns the last PathStep in the Path. -// If the path is empty, this returns a non-nil PathStep that reports a nil Type. +// Last returns the last [PathStep] in the Path. +// If the path is empty, this returns a non-nil [PathStep] +// that reports a nil [PathStep.Type]. func (pa Path) Last() PathStep { return pa.Index(-1) } @@ -79,7 +85,8 @@ func (pa Path) Last() PathStep { // Index returns the ith step in the Path and supports negative indexing. // A negative index starts counting from the tail of the Path such that -1 // refers to the last step, -2 refers to the second-to-last step, and so on. -// If index is invalid, this returns a non-nil PathStep that reports a nil Type. +// If index is invalid, this returns a non-nil [PathStep] +// that reports a nil [PathStep.Type]. func (pa Path) Index(i int) PathStep { if i < 0 { i = len(pa) + i @@ -168,7 +175,8 @@ func (ps pathStep) String() string { return fmt.Sprintf("{%s}", s) } -// StructField represents a struct field access on a field called Name. +// StructField is a [PathStep] that represents a struct field access +// on a field called [StructField.Name]. type StructField struct{ *structField } type structField struct { pathStep @@ -204,10 +212,11 @@ func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) } func (sf StructField) Name() string { return sf.name } // Index is the index of the field in the parent struct type. -// See reflect.Type.Field. +// See [reflect.Type.Field]. func (sf StructField) Index() int { return sf.idx } -// SliceIndex is an index operation on a slice or array at some index Key. +// SliceIndex is a [PathStep] that represents an index operation on +// a slice or array at some index [SliceIndex.Key]. type SliceIndex struct{ *sliceIndex } type sliceIndex struct { pathStep @@ -247,12 +256,12 @@ func (si SliceIndex) Key() int { // all of the indexes to be shifted. If an index is -1, then that // indicates that the element does not exist in the associated slice. // -// Key is guaranteed to return -1 if and only if the indexes returned -// by SplitKeys are not the same. SplitKeys will never return -1 for +// [SliceIndex.Key] is guaranteed to return -1 if and only if the indexes +// returned by SplitKeys are not the same. SplitKeys will never return -1 for // both indexes. func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } -// MapIndex is an index operation on a map at some index Key. +// MapIndex is a [PathStep] that represents an index operation on a map at some index Key. type MapIndex struct{ *mapIndex } type mapIndex struct { pathStep @@ -266,7 +275,7 @@ func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", // Key is the value of the map key. func (mi MapIndex) Key() reflect.Value { return mi.key } -// Indirect represents pointer indirection on the parent type. +// Indirect is a [PathStep] that represents pointer indirection on the parent type. type Indirect struct{ *indirect } type indirect struct { pathStep @@ -276,7 +285,7 @@ func (in Indirect) Type() reflect.Type { return in.typ } func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } func (in Indirect) String() string { return "*" } -// TypeAssertion represents a type assertion on an interface. +// TypeAssertion is a [PathStep] that represents a type assertion on an interface. type TypeAssertion struct{ *typeAssertion } type typeAssertion struct { pathStep @@ -286,7 +295,8 @@ func (ta TypeAssertion) Type() reflect.Type { return ta.typ } func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) } -// Transform is a transformation from the parent type to the current type. +// Transform is a [PathStep] that represents a transformation +// from the parent type to the current type. type Transform struct{ *transform } type transform struct { pathStep @@ -297,13 +307,13 @@ func (tf Transform) Type() reflect.Type { return tf.typ } func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) } -// Name is the name of the Transformer. +// Name is the name of the [Transformer]. func (tf Transform) Name() string { return tf.trans.name } // Func is the function pointer to the transformer function. func (tf Transform) Func() reflect.Value { return tf.trans.fnc } -// Option returns the originally constructed Transformer option. +// Option returns the originally constructed [Transformer] option. // The == operator can be used to detect the exact option used. func (tf Transform) Option() Option { return tf.trans } diff --git a/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go index 2ab41fad3f..e39f42284e 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_reflect.go +++ b/vendor/github.com/google/go-cmp/cmp/report_reflect.go @@ -199,7 +199,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, break } sf := t.Field(i) - if supportExporters && !isExported(sf.Name) { + if !isExported(sf.Name) { vv = retrieveUnexportedField(v, sf, true) } s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs) diff --git a/vendor/github.com/google/uuid/.travis.yml b/vendor/github.com/google/uuid/.travis.yml deleted file mode 100644 index d8156a60ba..0000000000 --- a/vendor/github.com/google/uuid/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.4.3 - - 1.5.3 - - tip - -script: - - go test -v ./... diff --git a/vendor/github.com/google/uuid/CHANGELOG.md b/vendor/github.com/google/uuid/CHANGELOG.md new file mode 100644 index 0000000000..7ec5ac7ea9 --- /dev/null +++ b/vendor/github.com/google/uuid/CHANGELOG.md @@ -0,0 +1,41 @@ +# Changelog + +## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) + + +### Features + +* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) + + +### Bug Fixes + +* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) +* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) + +## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) + + +### Features + +* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) + +## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) + + +### Features + +* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) + +### Fixes + +* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) + +## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) + + +### Bug Fixes + +* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0)) + +## Changelog diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md index 04fdf09f13..a502fdc515 100644 --- a/vendor/github.com/google/uuid/CONTRIBUTING.md +++ b/vendor/github.com/google/uuid/CONTRIBUTING.md @@ -2,6 +2,22 @@ We definitely welcome patches and contribution to this project! +### Tips + +Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org). + +Always try to include a test case! If it is not possible or not necessary, +please explain why in the pull request description. + +### Releasing + +Commits that would precipitate a SemVer change, as described in the Conventional +Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) +to create a release candidate pull request. Once submitted, `release-please` +will create a release. + +For tips on how to work with `release-please`, see its documentation. + ### Legal requirements In order to protect both you and ourselves, you will need to sign the diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md index f765a46f91..3e9a61889d 100644 --- a/vendor/github.com/google/uuid/README.md +++ b/vendor/github.com/google/uuid/README.md @@ -1,6 +1,6 @@ -# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master) +# uuid The uuid package generates and inspects UUIDs based on -[RFC 4122](http://tools.ietf.org/html/rfc4122) +[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) and DCE 1.1: Authentication and Security Services. This package is based on the github.com/pborman/uuid package (previously named @@ -9,10 +9,12 @@ a UUID is a 16 byte array rather than a byte slice. One loss due to this change is the ability to represent an invalid UUID (vs a NIL UUID). ###### Install -`go get github.com/google/uuid` +```sh +go get github.com/google/uuid +``` ###### Documentation -[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid) +[![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid) Full `go doc` style documentation for the package can be viewed online without installing this package by using the GoDoc site here: diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go index b404f4bec2..dc60082d3b 100644 --- a/vendor/github.com/google/uuid/hash.go +++ b/vendor/github.com/google/uuid/hash.go @@ -17,6 +17,12 @@ var ( NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) Nil UUID // empty UUID, all zeros + + // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. + Max = UUID{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + } ) // NewHash returns a new UUID derived from the hash of space concatenated with diff --git a/vendor/github.com/google/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go index 24b78edc90..b2a0bc8711 100644 --- a/vendor/github.com/google/uuid/node_js.go +++ b/vendor/github.com/google/uuid/node_js.go @@ -7,6 +7,6 @@ package uuid // getHardwareInterface returns nil values for the JS version of the code. -// This remvoves the "net" dependency, because it is not used in the browser. +// This removes the "net" dependency, because it is not used in the browser. // Using the "net" library inflates the size of the transpiled JS code by 673k bytes. func getHardwareInterface(name string) (string, []byte) { return "", nil } diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go index e6ef06cdc8..c351129279 100644 --- a/vendor/github.com/google/uuid/time.go +++ b/vendor/github.com/google/uuid/time.go @@ -108,12 +108,23 @@ func setClockSequence(seq int) { } // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in -// uuid. The time is only defined for version 1 and 2 UUIDs. +// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. func (uuid UUID) Time() Time { - time := int64(binary.BigEndian.Uint32(uuid[0:4])) - time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 - time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 - return Time(time) + var t Time + switch uuid.Version() { + case 6: + time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110 + t = Time(time) + case 7: + time := binary.BigEndian.Uint64(uuid[:8]) + t = Time((time>>16)*10000 + g1582ns100) + default: // forward compatible + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + t = Time(time) + } + return t } // ClockSequence returns the clock sequence encoded in uuid. diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go index a57207aeb6..5232b48678 100644 --- a/vendor/github.com/google/uuid/uuid.go +++ b/vendor/github.com/google/uuid/uuid.go @@ -56,11 +56,15 @@ func IsInvalidLengthError(err error) bool { return ok } -// Parse decodes s into a UUID or returns an error. Both the standard UUID -// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the -// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex -// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. +// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both +// the standard UUID forms defined in RFC 4122 +// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, +// Parse accepts non-standard strings such as the raw hex encoding +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, +// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are +// examined in the latter case. Parse should not be used to validate strings as +// it parses non-standard encodings as indicated above. func Parse(s string) (UUID, error) { var uuid UUID switch len(s) { @@ -69,7 +73,7 @@ func Parse(s string) (UUID, error) { // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36 + 9: - if strings.ToLower(s[:9]) != "urn:uuid:" { + if !strings.EqualFold(s[:9], "urn:uuid:") { return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) } s = s[9:] @@ -101,7 +105,8 @@ func Parse(s string) (UUID, error) { 9, 11, 14, 16, 19, 21, - 24, 26, 28, 30, 32, 34} { + 24, 26, 28, 30, 32, 34, + } { v, ok := xtob(s[x], s[x+1]) if !ok { return uuid, errors.New("invalid UUID format") @@ -117,7 +122,7 @@ func ParseBytes(b []byte) (UUID, error) { switch len(b) { case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { + if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) { return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) } b = b[9:] @@ -145,7 +150,8 @@ func ParseBytes(b []byte) (UUID, error) { 9, 11, 14, 16, 19, 21, - 24, 26, 28, 30, 32, 34} { + 24, 26, 28, 30, 32, 34, + } { v, ok := xtob(b[x], b[x+1]) if !ok { return uuid, errors.New("invalid UUID format") @@ -180,6 +186,59 @@ func Must(uuid UUID, err error) UUID { return uuid } +// Validate returns an error if s is not a properly formatted UUID in one of the following formats: +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} +// It returns an error if the format is invalid, otherwise nil. +func Validate(s string) error { + switch len(s) { + // Standard UUID format + case 36: + + // UUID with "urn:uuid:" prefix + case 36 + 9: + if !strings.EqualFold(s[:9], "urn:uuid:") { + return fmt.Errorf("invalid urn prefix: %q", s[:9]) + } + s = s[9:] + + // UUID enclosed in braces + case 36 + 2: + if s[0] != '{' || s[len(s)-1] != '}' { + return fmt.Errorf("invalid bracketed UUID format") + } + s = s[1 : len(s)-1] + + // UUID without hyphens + case 32: + for i := 0; i < len(s); i += 2 { + _, ok := xtob(s[i], s[i+1]) + if !ok { + return errors.New("invalid UUID format") + } + } + + default: + return invalidLengthError{len(s)} + } + + // Check for standard UUID format + if len(s) == 36 { + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return errors.New("invalid UUID format") + } + for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { + if _, ok := xtob(s[x], s[x+1]); !ok { + return errors.New("invalid UUID format") + } + } + } + + return nil +} + // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // , or "" if uuid is invalid. func (uuid UUID) String() string { @@ -292,3 +351,15 @@ func DisableRandPool() { poolMu.Lock() poolPos = randPoolSize } + +// UUIDs is a slice of UUID types. +type UUIDs []UUID + +// Strings returns a string slice containing the string form of each UUID in uuids. +func (uuids UUIDs) Strings() []string { + var uuidStrs = make([]string, len(uuids)) + for i, uuid := range uuids { + uuidStrs[i] = uuid.String() + } + return uuidStrs +} diff --git a/vendor/github.com/google/uuid/version6.go b/vendor/github.com/google/uuid/version6.go new file mode 100644 index 0000000000..339a959a7a --- /dev/null +++ b/vendor/github.com/google/uuid/version6.go @@ -0,0 +1,56 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "encoding/binary" + +// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. +// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. +// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6 +// +// NewV6 returns a Version 6 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewV6 returns Nil and an error. +func NewV6() (UUID, error) { + var uuid UUID + now, seq, err := GetTime() + if err != nil { + return uuid, err + } + + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_high | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_mid | time_low_and_version | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |clk_seq_hi_res | clk_seq_low | node (0-1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | node (2-5) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + binary.BigEndian.PutUint64(uuid[0:], uint64(now)) + binary.BigEndian.PutUint16(uuid[8:], seq) + + uuid[6] = 0x60 | (uuid[6] & 0x0F) + uuid[8] = 0x80 | (uuid[8] & 0x3F) + + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + copy(uuid[10:], nodeID[:]) + nodeMu.Unlock() + + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version7.go b/vendor/github.com/google/uuid/version7.go new file mode 100644 index 0000000000..3167b643d4 --- /dev/null +++ b/vendor/github.com/google/uuid/version7.go @@ -0,0 +1,104 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// UUID version 7 features a time-ordered value field derived from the widely +// implemented and well known Unix Epoch timestamp source, +// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. +// As well as improved entropy characteristics over versions 1 or 6. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7 +// +// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. +// +// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). +// Uses the randomness pool if it was enabled with EnableRandPool. +// On error, NewV7 returns Nil and an error +func NewV7() (UUID, error) { + uuid, err := NewRandom() + if err != nil { + return uuid, err + } + makeV7(uuid[:]) + return uuid, nil +} + +// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). +// it use NewRandomFromReader fill random bits. +// On error, NewV7FromReader returns Nil and an error. +func NewV7FromReader(r io.Reader) (UUID, error) { + uuid, err := NewRandomFromReader(r) + if err != nil { + return uuid, err + } + + makeV7(uuid[:]) + return uuid, nil +} + +// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) +// uuid[8] already has the right version number (Variant is 10) +// see function NewV7 and NewV7FromReader +func makeV7(uuid []byte) { + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | ver | rand_a (12 bit seq) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |var| rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + _ = uuid[15] // bounds check + + t, s := getV7Time() + + uuid[0] = byte(t >> 40) + uuid[1] = byte(t >> 32) + uuid[2] = byte(t >> 24) + uuid[3] = byte(t >> 16) + uuid[4] = byte(t >> 8) + uuid[5] = byte(t) + + uuid[6] = 0x70 | (0x0F & byte(s>>8)) + uuid[7] = byte(s) +} + +// lastV7time is the last time we returned stored as: +// +// 52 bits of time in milliseconds since epoch +// 12 bits of (fractional nanoseconds) >> 8 +var lastV7time int64 + +const nanoPerMilli = 1000000 + +// getV7Time returns the time in milliseconds and nanoseconds / 256. +// The returned (milli << 12 + seq) is guarenteed to be greater than +// (milli << 12 + seq) returned by any previous call to getV7Time. +func getV7Time() (milli, seq int64) { + timeMu.Lock() + defer timeMu.Unlock() + + nano := timeNow().UnixNano() + milli = nano / nanoPerMilli + // Sequence number is between 0 and 3906 (nanoPerMilli>>8) + seq = (nano - milli*nanoPerMilli) >> 8 + now := milli<<12 + seq + if now <= lastV7time { + now = lastV7time + 1 + milli = now >> 12 + seq = now & 0xfff + } + lastV7time = now + return milli, seq +} diff --git a/vendor/github.com/vmware/govmomi/.dockerignore b/vendor/github.com/vmware/govmomi/.dockerignore new file mode 100644 index 0000000000..9f5fdc6b9e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile* +.*ignore \ No newline at end of file diff --git a/vendor/github.com/vmware/govmomi/.gitignore b/vendor/github.com/vmware/govmomi/.gitignore new file mode 100644 index 0000000000..675d86a0ad --- /dev/null +++ b/vendor/github.com/vmware/govmomi/.gitignore @@ -0,0 +1,13 @@ +secrets.yml +dist/ +.idea/ + +# ignore tools binaries +/git-chglog + +# ignore RELEASE-specific CHANGELOG +/RELEASE_CHANGELOG.md + +# Ignore editor temp files +*~ +.vscode/ diff --git a/vendor/github.com/vmware/govmomi/.golangci.yml b/vendor/github.com/vmware/govmomi/.golangci.yml new file mode 100644 index 0000000000..25242dcaf5 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/.golangci.yml @@ -0,0 +1,19 @@ +linters: + disable-all: true + enable: + - goimports + - govet + # Run with --fast=false for more extensive checks + fast: true +# override defaults +linters-settings: + goimports: + # put imports beginning with prefix after 3rd-party packages; + # it's a comma-separated list of prefixes + local-prefixes: github.com/vmware/govmomi +run: + timeout: 6m + skip-dirs: + - vim25/json + - vim25/xml + - cns/types diff --git a/vendor/github.com/vmware/govmomi/.goreleaser.yml b/vendor/github.com/vmware/govmomi/.goreleaser.yml new file mode 100644 index 0000000000..de6ced253b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/.goreleaser.yml @@ -0,0 +1,166 @@ +--- +project_name: govmomi + +builds: + - id: govc + no_main_check: true + goos: &goos-defs + - linux + - darwin + - windows + - freebsd + goarch: &goarch-defs + - amd64 + - arm + - arm64 + - mips64le + - s390x + env: + - CGO_ENABLED=0 + - PKGPATH=github.com/vmware/govmomi/govc/flags + main: ./govc/main.go + binary: govc + ldflags: + - "-X {{.Env.PKGPATH}}.BuildVersion={{.Version}} -X {{.Env.PKGPATH}}.BuildCommit={{.ShortCommit}} -X {{.Env.PKGPATH}}.BuildDate={{.Date}}" + - id: vcsim + no_main_check: true + goos: *goos-defs + goarch: *goarch-defs + env: + - CGO_ENABLED=0 + main: ./vcsim/main.go + binary: vcsim + ldflags: + - "-X main.buildVersion={{.Version}} -X main.buildCommit={{.ShortCommit}} -X main.buildDate={{.Date}}" + +nfpms: + - package_name: govmomi + builds: + - govc + - vcsim + homepage: https://github.com/vmware/govmomi + maintainer: Doug MacEachern + description: |- + vSphere CLI + formats: + - rpm + +archives: + - id: govcbuild + builds: + - govc + name_template: >- + govc_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + format_overrides: &overrides + - goos: windows + format: zip + files: &extrafiles + - CHANGELOG.md + - LICENSE.txt + - README.md + + - id: vcsimbuild + builds: + - vcsim + name_template: >- + vcsim_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + format_overrides: *overrides + files: *extrafiles + +snapshot: + name_template: "{{ .Tag }}-next" + +checksum: + name_template: "checksums.txt" + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + - Merge pull request + - Merge branch + +# upload disabled since it is maintained in homebrew-core +brews: + - name: govc + ids: + - govcbuild + repository: + owner: govmomi + name: homebrew-tap + # TODO: create token in specified tap repo, add as secret to govmomi repo and reference in release workflow + # token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}" + # enable once we do fully automated releases + skip_upload: true + commit_author: + name: Alfred the Narwhal + email: cna-alfred@vmware.com + directory: Formula + homepage: "https://github.com/vmware/govmomi/blob/main/govc/README.md" + description: "govc is a vSphere CLI built on top of govmomi." + test: | + system "#{bin}/govc version" + install: | + bin.install "govc" + - name: vcsim + ids: + - vcsimbuild + repository: + owner: govmomi + name: homebrew-tap + # TODO: create token in specified tap repo, add as secret to govmomi repo and reference in release workflow + # token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}" + # enable once we do fully automated releases + skip_upload: true + commit_author: + name: Alfred the Narwhal + email: cna-alfred@vmware.com + directory: Formula + homepage: "https://github.com/vmware/govmomi/blob/main/vcsim/README.md" + description: "vcsim is a vSphere API simulator built on top of govmomi." + test: | + system "#{bin}/vcsim -h" + install: | + bin.install "vcsim" + +dockers: + - image_templates: + - "vmware/govc:{{ .Tag }}" + - "vmware/govc:{{ .ShortCommit }}" + - "vmware/govc:latest" + dockerfile: Dockerfile.govc + ids: + - govc + build_flag_templates: + - "--pull" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.title={{.ProjectName}}" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=org.opencontainers.image.url=https://github.com/vmware/govmomi" + - "--platform=linux/amd64" + - image_templates: + - "vmware/vcsim:{{ .Tag }}" + - "vmware/vcsim:{{ .ShortCommit }}" + - "vmware/vcsim:latest" + dockerfile: Dockerfile.vcsim + ids: + - vcsim + build_flag_templates: + - "--pull" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.title={{.ProjectName}}" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=org.opencontainers.image.url=https://github.com/vmware/govmomi" + - "--platform=linux/amd64" diff --git a/vendor/github.com/vmware/govmomi/.mailmap b/vendor/github.com/vmware/govmomi/.mailmap new file mode 100644 index 0000000000..dd869e10f6 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/.mailmap @@ -0,0 +1,59 @@ +amanpaha amanpaha <84718160+amanpaha@users.noreply.github.com> +Amanda H. L. de Andrade Amanda Hager Lopes de Andrade Katz +Amanda H. L. de Andrade amandahla +Amit Bathla +Andrew Kutz +Andrew Kutz akutz +Andrew Kutz Andrew Kutz <101085+akutz@users.noreply.github.com> +Andrew Kutz akutz +Anfernee Yongkun Gui +Anfernee Yongkun Gui Yongkun Anfernee Gui +Anna Carrigan Anna +Balu Dontu BaluDontu +Bruce Downs +Bruce Downs +Bruce Downs +Bryan Venteicher +Brian Rak +Clint Greenwood +Cédric Blomart +Cédric Blomart cedric +David Stark +Doug MacEachern dougm +Deyan Popov <126056852+dekp@users.noreply.github.com> +Eric Gray +Eric Yutao eric +Fabio Rapposelli +Faiyaz Ahmed Faiyaz Ahmed +Faiyaz Ahmed Faiyaz Ahmed +Faiyaz Ahmed Faiyaz Ahmed +Hakan Halil <25109775+HakanSunay@users.noreply.github.com> +Henrik Hodne +Ian Eyberg +Jeremy Canady +Jiatong Wang jiatongw +Kiril Karaatanassov kkaraatanassov +Kiril Karaatanassov +Lintong Jiang lintongj <55512168+lintongj@users.noreply.github.com> +Lubron Zhan lubronzhan +Lubron Zhan lubronzhan +Lubron Zhan Lubron +Michael Gasch Michael Gasch +Michael Gasch <15986659+embano1@users.noreply.github.com> +Michael Gasch embano1 +Mincho Tonev matonev <31008054+matonev@users.noreply.github.com> +Parveen Chahal +Pieter Noordhuis +Ricardo Katz +Saad Malik +Stoyan Zhelyazkov <156204153+stoyanzhelyazkov@users.noreply.github.com> +Takaaki Furukawa takaaki.furukawa +Takaaki Furukawa tkak +Uwe Bessle Uwe Bessle +Uwe Bessle Uwe Bessle +Vadim Egorov +William Lam +Yun Zhou <41678287+gh05tn0va@users.noreply.github.com> +Zach G zach96guan +Zach Tucker +Zee Yang diff --git a/vendor/github.com/vmware/govmomi/CHANGELOG.md b/vendor/github.com/vmware/govmomi/CHANGELOG.md new file mode 100644 index 0000000000..254f540f1b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/CHANGELOG.md @@ -0,0 +1,4782 @@ + + +## [Release v0.36.0](https://github.com/vmware/govmomi/compare/v0.35.0...v0.36.0) + +> Release Date: 2024-03-07 + +### 🐞 Fix + +- [fd3840e3] vcsim Fetch method causes runtime panic when property is not set +- [4254c59c] Update summary.config.hwVersion in simulator +- [44610f43] govc: use session KeepAlive in library.export command + +### 💫 `vcsim` (Simulator) + +- [c46ad1af] Enhanced sim support for upgrade VM + +### 🧹 Chore + +- [ef3a3d62] Update version.go for v0.36.0 +- [01a069da] bump Go versions +- [08d2fd0b] Better support for ESXi & HW versions + +### ⚠️ BREAKING + +### 📖 Commits + +- [ef3a3d62] chore: Update version.go for v0.36.0 +- [89693ada] Updating CONTRIBUTORS +- [fd3840e3] fix: vcsim Fetch method causes runtime panic when property is not set +- [75505549] Add APIs for vLCM enablement on a cluster and base ESXi image selection +- [01a069da] chore: bump Go versions +- [7998478a] build(deps): bump github.com/stretchr/testify from 1.8.4 to 1.9.0 +- [4ad8f689] Add API for vLCM - offline depots and cluster baseline images +- [08d2fd0b] chore: Better support for ESXi & HW versions +- [c46ad1af] vcsim: Enhanced sim support for upgrade VM +- [4254c59c] fix: Update summary.config.hwVersion in simulator +- [de2ce182] test fixes +- [44610f43] fix: govc: use session KeepAlive in library.export command +- [41907150] Add service locator to CNS RelocateVolume spec +- [ef555e78] Add "AggregatedSnapshotCapacityInMb" to CnsSnapshotCreateResult and CnsSnapshotDeleteResult. + + +## [Release v0.35.0](https://github.com/vmware/govmomi/compare/v0.34.2...v0.35.0) + +> Release Date: 2024-02-12 + +### 💫 API Changes + +- [8e17e4c1] Sim vm config.changeVersion & config.modified +- [95aa2571] WaitForUpdatesEx & DestroyPropertyFilter + +### 💫 `govc` (CLI) + +- [9ddfc534] json tag camelCase fixes + +### 💫 `vcsim` (Simulator) + +- [557d2654] Fix -method-delay option to update task states + +### 📃 Documentation + +- [2d1b52ff] update release doc + +### 🧹 Chore + +- [d7c0094a] Update version.go for v0.35.0 +- [69785ff0] update CONTRIBUTORS + +### ⚠️ BREAKING + +json tag camelCase fixes [9ddfc534]: +follow up to json tags missed in PR [#3007](https://github.com/vmware/govmomi/issues/3007) and PR [#3247](https://github.com/vmware/govmomi/issues/3247) + +WaitForUpdatesEx & DestroyPropertyFilter [95aa2571]: +The semantics around the helper functions in the + property package have changed. Please review any + code that calls this package to ensure it is + compatible with the new behaviors. + +### 📖 Commits + +- [d7c0094a] chore: Update version.go for v0.35.0 +- [2d1b52ff] docs: update release doc +- [69785ff0] chore: update CONTRIBUTORS +- [9ddfc534] govc: json tag camelCase fixes +- [b137a5d2] Add "AggregatedSnapshotCapacityInMb" to cnstype. +- [b948e3cb] add -json to snapshot.tree +- [dabec6cd] build(deps): bump nokogiri from 1.14.3 to 1.16.2 in /gen +- [8e17e4c1] api: Sim vm config.changeVersion & config.modified +- [d55cf6e4] build(deps): bump peter-evans/create-pull-request from 5 to 6 +- [25cab091] Re-enable PC updates for indexed properties +- [8150eedd] build(deps): bump andstor/file-existence-action from 2 to 3 +- [bfc5d64c] build(deps): bump peter-evans/create-or-update-comment from 3 to 4 +- [42d7d711] Add new "UsedCapacityInMb" in struct "CnsBlockBackingDetails" +- [61f901eb] build(deps): bump github.com/google/uuid from 1.5.0 to 1.6.0 +- [3b5917a2] build(deps): bump actions/cache from 3 to 4 +- [78898bd2] Self identify the executable making calls to vCenter +- [95aa2571] api: WaitForUpdatesEx & DestroyPropertyFilter +- [cd8a7883] Changes to fix xml tag used for SnapshotId +- [557d2654] vcsim: Fix -method-delay option to update task states +- [98b0b77f] Fixes Missing Tags in AttachedTags +- [5410a069] Changes to add CNS fault CnsSnapshotCreatedFault +- [8c1d8f18] build(deps): bump actions/upload-artifact from 3 to 4 +- [14d35380] build(deps): bump github/codeql-action from 2 to 3 +- [f6c537d7] build(deps): bump github.com/google/uuid from 1.4.0 to 1.5.0 +- [e9a9f2c0] build(deps): bump chuhlomin/render-template from 1.8 to 1.9 + + +## [Release v0.34.2](https://github.com/vmware/govmomi/compare/v0.34.1...v0.34.2) + +> Release Date: 2024-01-08 + +### 💫 `vcsim` (Simulator) + +- [4c8ffb26] Fix -method-delay option to update task states + +### 🧹 Chore + +- [96b6eb77] Update version.go for v0.34.2 + +### ⚠️ BREAKING + +### 📖 Commits + +- [96b6eb77] chore: Update version.go for v0.34.2 +- [4c8ffb26] vcsim: Fix -method-delay option to update task states +- [1c2c1c75] Fixes Missing Tags in AttachedTags +- [55924679] Changes to fix xml tag used for SnapshotId + + +## [Release v0.34.1](https://github.com/vmware/govmomi/compare/v0.34.0...v0.34.1) + +> Release Date: 2023-12-19 + +### 🧹 Chore + +- [754cb3aa] Update version.go for v0.34.1 + +### ⚠️ BREAKING + +### 📖 Commits + +- [754cb3aa] chore: Update version.go for v0.34.1 +- [dd8bbb4d] Changes to add CNS fault CnsSnapshotCreatedFault + + +## [Release v0.34.0](https://github.com/vmware/govmomi/compare/v0.33.1...v0.34.0) + +> Release Date: 2023-12-12 + +### 🐞 Fix + +- [980d22d6] expose util for rest status return + +### 💫 API Changes + +- [31423b78] add object.Datastore.FindInventoryPath +- [d52f8ee3] add Content Library update session file APIs + +### 💫 `vcsim` (Simulator) + +- [4a09f19d] add PbmQueryAssociatedProfiles method +- [4cbd6424] Fix [BUG] vcsim raises TypeError for RemoveSnapshotTask +- [04ccf69e] handle HostNotConnected when saving inventory +- [2f1fefae] fix MAC Addresses to be unique +- [e19137f5] propagate VMwareDVSConfigSpec in CreateDVS_Task +- [a0923119] emit DVS and Portgroup create events +- [c8a2fc2e] Fix PropertyCollector to handle empty property + +### 🧹 Chore + +- [a5899afa] Update version.go for v0.34.0 + +### ⚠️ BREAKING + +### 📖 Commits + +- [a5899afa] chore: Update version.go for v0.34.0 +- [980d22d6] fix: expose util for rest status return +- [4a09f19d] vcsim: add PbmQueryAssociatedProfiles method +- [e39527d4] build(deps): bump actions/stale from 8 to 9 +- [4cbd6424] vcsim: Fix [BUG] vcsim raises TypeError for RemoveSnapshotTask +- [e9a782a9] build(deps): bump actions/setup-go from 4 to 5 +- [45188e1d] Add default Historical Intervals to the simulator +- [04ccf69e] vcsim: handle HostNotConnected when saving inventory +- [2f1fefae] vcsim: fix MAC Addresses to be unique +- [d32be098] simulator: fix dropped error +- [e19137f5] vcsim: propagate VMwareDVSConfigSpec in CreateDVS_Task +- [a0923119] vcsim: emit DVS and Portgroup create events +- [31423b78] api: add object.Datastore.FindInventoryPath +- [c8a2fc2e] vcsim: Fix PropertyCollector to handle empty property +- [d52f8ee3] api: add Content Library update session file APIs +- [3942d8f6] build(deps): bump github.com/google/uuid from 1.3.1 to 1.4.0 +- [09c72919] Add additional PBM methods + + +## [Release v0.33.1](https://github.com/vmware/govmomi/compare/v0.33.0...v0.33.1) + +> Release Date: 2023-10-30 + +### ⚠️ BREAKING + +### 📖 Commits + +- [6de69ad0] Add additional PBM methods + + +## [Release v0.33.0](https://github.com/vmware/govmomi/compare/v0.32.0...v0.33.0) + +> Release Date: 2023-10-25 + +### 💫 `govc` (CLI) + +- [5264e839] add cluster.change '-ha-admission-control-enabled' flag +- [3bcaf429] add option to enable hidden properties in import.{spec,ova} + +### 💫 `vcsim` (Simulator) + +- [db0ba920] Handle prepare guest operations when svm is nil +- [0754d758] fix ModifyListView to return unresolved references +- [7f3a0708] Remove extra devices in OVF Deploy w/ ConfigSpec + +### 🧹 Chore + +- [f3c1fca9] Update version.go for v0.33.0 +- [675eebd2] remove refs to deprecated io/ioutil + +### ⚠️ BREAKING + +fix ModifyListView to return unresolved references [0754d758]: +api: view.ListView.{Add,Remove,Reset} methods now return unresolved references + +### 📖 Commits + +- [f3c1fca9] chore: Update version.go for v0.33.0 +- [19726dc6] Add functionality for checking whether the provided thumbprint is known to the soap client +- [5264e839] govc: add cluster.change '-ha-admission-control-enabled' flag +- [db0ba920] vcsim: Handle prepare guest operations when svm is nil +- [0434fd26] vapi: add support for OperationID header +- [0754d758] vcsim: fix ModifyListView to return unresolved references +- [5569c012] build(deps): bump github.com/google/go-cmp from 0.5.9 to 0.6.0 +- [babee198] build(deps): bump chuhlomin/render-template from 1.7 to 1.8 +- [7f3a0708] vcsim: Remove extra devices in OVF Deploy w/ ConfigSpec +- [3bcaf429] govc: add option to enable hidden properties in import.{spec,ova} +- [675eebd2] chore: remove refs to deprecated io/ioutil + + +## [Release v0.32.0](https://github.com/vmware/govmomi/compare/v0.31.0...v0.32.0) + +> Release Date: 2023-09-28 + +### 🐞 Fix + +- [bed95133] case insensitive govc import.ova PropertyMapping + +### 💡 Examples + +- [f2aaee58] add ListView example for waiting on updates to tasks + +### 💫 API Changes + +- [a91eb5e5] disable HTTP Keep-Alive for direct ESX connections + +### 💫 `govc` (CLI) + +- [db5b3d8e] camelCase json output + +### 💫 `vcsim` (Simulator) + +- [524ca258] EnvironmentBrowser improvements +- [d49e401e] set HostSystem.Config.Host + +### 📃 Documentation + +- [258ee244] update govc jq examples with correct case + +### 🧹 Chore + +- [a8d705a0] Update version.go for v0.32.0 + +### ⚠️ BREAKING + +camelCase json output [db5b3d8e]: +This change adds camelCase (lower-case 1st character) json tags for govc types + +EnvironmentBrowser improvements [524ca258]: +removed object.VirtualMachine.QueryConfigTarget method +- Use object.VirtualMachine.EnvironmentBrowser().QueryConfigTarget instead + +### 📖 Commits + +- [a8d705a0] chore: Update version.go for v0.32.0 +- [f2aaee58] examples: add ListView example for waiting on updates to tasks +- [a91eb5e5] api: disable HTTP Keep-Alive for direct ESX connections +- [db5b3d8e] govc: camelCase json output +- [524ca258] vcsim: EnvironmentBrowser improvements +- [bed95133] fix: case insensitive govc import.ova PropertyMapping +- [6c19b99a] emacs: update for v0.31.0 release +- [258ee244] docs: update govc jq examples with correct case +- [d49e401e] vcsim: set HostSystem.Config.Host + + +## [Release v0.31.0](https://github.com/vmware/govmomi/compare/v0.30.7...v0.31.0) + +> Release Date: 2023-09-25 + +### 🐞 Fix + +- [8f9e5495] govc vm.clone failure when using 'cluster' option +- [b22f730e] govc datacenter.info VM count with multiple DCs +- [65814f0c] Update some goreleaser deprecated fields +- [b4eac193] check the error chain when validating if it's x509 error +- [86cadf21] Fix the gorelease +- [1711a843] avoid modifying client transport outside of NewClient +- [313aa85b] share http.Transport with service clients +- [f81f3b36] grep warnings during generating usage documentation +- [2d11115b] support `binary` and `dateTime` in JSON +- [c4ffe464] add esxcli.Fault and revert Error() string +- [93cb079b] byte, float and int (de) serialization +- [8bc2caa1] avoid govc -verbose flag panic if an UpdateSet is nil +- [9ba1b852] include StoragePod Datastore children in ContainerView +- [8b00a93f] only limit the number of samples generated to maxSample when maxSample is greater than 0 and the number of samples to generate is greater than maxSample Closes: [#3097](https://github.com/vmware/govmomi/issues/3097) +- [4ed07633] support govc ls -xml flag +- [8554329c] Pin the result limit of ssoadmin client to its MAX + +### 💡 Examples + +- [71493efa] add rest.Client.LoginByToken +- [3bf46949] add session.Manager.LoginByToken + +### 💫 API Changes + +- [a03f4735] Fix errors w 8.0U2 GA update +- [515df5df] Update generated types to vSphere 8.0U2 GA +- [b7ceedea] Prep to update types to vSphere 8.0U2 GA +- [ccd07a01] Update generated types to vSphere 8.0U1c GA +- [4c00586f] Prep to update types to vSphere 8.0U1c GA +- [5431c33a] Type/field comments for data structures; API versions +- [4b2de289] Add SDK support for VM data sets +- [25865e57] set inventory path in SearchIndex.FindByInventoryPath +- [38d0ac0d] Add JSON transport for vim25 +- [0938fba2] Add ServerGuid to gen'd MoRef +- [e09a4128] support find.NetworkList by ID +- [e8fa981e] support find.Network by cluster path +- [4e6d6424] JSON Discriminators for vim25/types +- [99200868] Generate JSON tags + +### 💫 `govc` (CLI) + +- [c4d851b2] Add CLI support for VM data sets +- [02f353dd] Command to print device/backings model as tree +- [af7833bb] Fix memory aliasing in for loop (gosec G601) +- [e17d8842] add -file flag for cluster.module.rm +- [e34c7218] Add CLI device protocol support for vm.network.add +- [48bdfada] Add --help +- [28014f9b] Add general usage message +- [e5f3cd0b] add detail error message for host.esxcli commands +- [81733d0e] add cluster.mv command +- [daaaca0f] Add support for CNS volume snapshots +- [477bf69b] Support JSON protocol using environment variable +- [b8007c4b] dont check poweredOn for vm.console vmrc requests +- [6b34770c] add sso.idp.ldap.update command +- [e5b2aa37] Add feature VM IOMMU enablement support +- [f4c678ad] Add checksum validation to govc import.ova +- [e935b5a8] Add feature to get and set default idp + +### 💫 `vcsim` (Simulator) + +- [35ec7c3f] Add simulator support for VM data sets +- [c77de71c] Introduce separation btw new service instance & infra creation +- [2b5c457e] add interactive debug github action stage +- [9b2ef986] use docker event for efficient monitoring +- [6f34f131] container backing respects changes via reconfigure +- [6248cbfe] create underlay network for pNICs in container-backed hosts +- [6b7b0dfc] per-host OptionManager instances and differentiated roles +- [387dc6e5] support container backing for hosts +- [fdb4d847] untangle container/VM to allow reuse of container logic for hosts +- [9d8380ce] Fix RefreshDatastore to return a valid response +- [47dd6e02] add PerformanceManager counter values +- [65b6c51f] add lookup.EndpointURL tests +- [cd9446c7] apply PCI UnitNumber offset of 7 for ethernet +- [11356057] set StandbyMode default to "none" +- [0a351a84] Add RUN.env flag to inject environment variables to container-backed VM +- [112777b8] Fix VM ExtraConfig +- [e6217900] make task lock handoff optional +- [6c0ed53b] async guest shutdown and standby +- [297c79bf] add VirtualMachine.StandbyGuest support +- [7a04bd00] Fix FindByInventoryPath to handle root folder +- [78a979c9] Add CSV format support to QueryPerf API +- [c62983fd] add ssoadmin user and group management +- [eb9c11c6] add guest.net.ipConfig + +### 📃 Documentation + +- [e4a36881] Add README to vendored JSON pkg + +### 🧹 Chore + +- [2fab8d53] Update version.go for v0.31.0 +- [c460f706] Dockerfile & steps for generating types +- [7e490563] add missing guest OS IDs +- [0ed91a21] bump embano1/wip +- [c6005086] Err on json.Decode for invalid type/vals +- [2f5d7c62] fix WaitForUpdates bats test race +- [03718c0f] remove sso bats test hacks +- [4aad418a] upgrade to bats-core v1.9.0 release +- [d1af63ff] fix jq query case +- [91f51cfb] sync httptest/server race fix +- [80e6b73f] add timeout to bats tests +- [3158766f] adjust cert trust checks to support newer Go versions +- [4153cba9] Update CI to Go 1.20 +- [5b3da2e4] upgrade golangci-lint +- [825c73c2] bats related fixes +- [1991de51] Remove JSON tag for "This" / ArrayOf "_value" +- [b594bf1f] Move to main +- [e639aba1] Exclude vim25/json from CodeStyle workflow +- [908aa065] Include LICENSE in vendored JSON pkg +- [5caa20a4] JSON Encoding w Discriminator Support +- [a581fd01] Vendor Go 1.17.13 encoding/json + +### ⚠️ BREAKING + + [4f9f126a]: +change string to *string for Item.Description and Library.Description in package library + +Testing done: +- Test against a VC testbed +Sending a UpdateLibraryItem request with this change, and set the new description to "". +The original item description was "virtualmachinepublishrequest.vmware.com: 6b0d06ad-8e18-4881-a806-2a7c8a7e1b4b", +after this UpdateLibraryItem request succeeded, the item description was set to "". +While before this change, it would be a no-op for the description. +- Test using govc + - Update Library +``` +Create a library: +➜ govmomi git:(issue-3048) ✗ govc library.create -d "description-1" cl-1 +495f611a-cf74-40d6-a54a-8b239cf15406 +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.info 495f611a-cf74-40d6-a54a-8b239cf15406 +Name: cl-1 + ID: 495f611a-cf74-40d6-a54a-8b239cf15406 + Path: /cl-1 + Description: description-1 + Version: 2 + Created: Fri Feb 17 19:18:22 2023 + Security Policy ID + StorageBackings: + DatastoreID: sharedVmfs-0 + Type: DATASTORE + +Update the library description with new string: +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.update -d "new description" 495f611a-cf74-40d6-a54a-8b239cf15406 +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.info 495f611a-cf74-40d6-a54a-8b239cf15406 +Name: cl-1 + ID: 495f611a-cf74-40d6-a54a-8b239cf15406 + Path: /cl-1 + Description: new description + Version: 3 + Created: Fri Feb 17 19:18:22 2023 + Security Policy ID + StorageBackings: + DatastoreID: sharedVmfs-0 + Type: DATASTORE + +Update the item name, description is not erased. +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.update -n "cl-1-new" 495f611a-cf74-40d6-a54a-8b239cf15406 +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.info 495f611a-cf74-40d6-a54a-8b239cf15406 +Name: cl-1-new + ID: 495f611a-cf74-40d6-a54a-8b239cf15406 + Path: /cl-1-new + Description: new description + Version: 4 + Created: Fri Feb 17 19:18:22 2023 + Security Policy ID + StorageBackings: + DatastoreID: sharedVmfs-0 + Type: DATASTORE + +Update the library description with empty string: +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.update -d "" +495f611a-cf74-40d6-a54a-8b239cf15406 +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.info 495f611a-cf74-40d6-a54a-8b239cf15406 +Name: cl-1-new + ID: 495f611a-cf74-40d6-a54a-8b239cf15406 + Path: /cl-1-new + Description: + Version: 5 + Created: Fri Feb 17 19:18:22 2023 + Security Policy ID + StorageBackings: + DatastoreID: sharedVmfs-0 + Type: DATASTORE +``` + - Update Library Item +``` +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.update -d "item-2" /cl-1/image-2 +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.info /cl-1/image-2 +Name: image-2 + ID: 0dc7df56-31e0-47dc-8b0a-6a33279ddccc + Path: /cl-1/image-2 + Description: item-2 + Type: ovf + Size: 2.0GB + Created: Wed Feb 15 23:05:15 2023 + Modified: Fri Feb 17 19:29:54 2023 + Version: 3 + Security Compliance: true + Certificate Status: INTERNAL + +Update item name: +govmomi git:(issue-3048) ✗ ~/go/bin/govc library.update -n "image-2-new" /cl-1/image-2 +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.info /cl-1/image-2-new +Name: image-2-new + ID: 0dc7df56-31e0-47dc-8b0a-6a33279ddccc + Path: /cl-1/image-2-new + Description: item-2 + Type: ovf + Size: 2.0GB + Created: Wed Feb 15 23:05:15 2023 + Modified: Fri Feb 17 19:31:44 2023 + Version: 4 + Security Compliance: true + Certificate Status: INTERNAL + +Update item description to empty string +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.update -d "" /cl-1/image-2-new +➜ govmomi git:(issue-3048) ✗ ~/go/bin/govc library.info /cl-1/image-2-new +Name: image-2-new + ID: 0dc7df56-31e0-47dc-8b0a-6a33279ddccc + Path: /cl-1/image-2-new + Description: + Type: ovf + Size: 2.0GB + Created: Wed Feb 15 23:05:15 2023 + Modified: Fri Feb 17 19:32:56 2023 + Version: 5 + Security Compliance: true + Certificate Status: INTERNAL +``` + +Move to main [b594bf1f]: +Changing GoVmomi's default branch from `master` to `main` will likely result +in dependents needing to repoint their clients and other integrations to +the new, default branch. + +Generate JSON tags [99200868]: +Updating the `vim25/types` with camelCased, JSON tags affects +the output of the `govc` command when using the `-json` flag +to emit results as JSON. Field names that used to be PascalCased +will now be camelCased. Queries for tools that parse JSON, such +as `jq`, will need to be updated to use the new camelCased fields. + +### 📖 Commits + +- [2fab8d53] chore: Update version.go for v0.31.0 +- [a03f4735] api: Fix errors w 8.0U2 GA update +- [515df5df] api: Update generated types to vSphere 8.0U2 GA +- [b7ceedea] api: Prep to update types to vSphere 8.0U2 GA +- [3fb5b821] Use Envoy sidecar for guest and datastore file transfer. +- [ccd07a01] api: Update generated types to vSphere 8.0U1c GA +- [4c00586f] api: Prep to update types to vSphere 8.0U1c GA +- [5431c33a] api: Type/field comments for data structures; API versions +- [c4d851b2] govc: Add CLI support for VM data sets +- [35ec7c3f] vcsim: Add simulator support for VM data sets +- [4b2de289] api: Add SDK support for VM data sets +- [02f353dd] govc: Command to print device/backings model as tree +- [8f9e5495] fix: govc vm.clone failure when using 'cluster' option +- [db076152] build(deps): bump goreleaser/goreleaser-action from 4 to 5 +- [00407ce9] build(deps): bump actions/checkout from 3 to 4 +- [c77de71c] vcsim: Introduce separation btw new service instance & infra creation +- [b22f730e] fix: govc datacenter.info VM count with multiple DCs +- [af7833bb] govc: Fix memory aliasing in for loop (gosec G601) +- [73b4535e] build(deps): bump github.com/google/uuid from 1.3.0 to 1.3.1 +- [e6bb6ce2] govc/library: fix dropped error +- [e17d8842] govc: add -file flag for cluster.module.rm +- [f636e960] Address review comments +- [2b5c457e] vcsim: add interactive debug github action stage +- [9b2ef986] vcsim: use docker event for efficient monitoring +- [6f34f131] vcsim: container backing respects changes via reconfigure +- [6248cbfe] vcsim: create underlay network for pNICs in container-backed hosts +- [6b7b0dfc] vcsim: per-host OptionManager instances and differentiated roles +- [387dc6e5] vcsim: support container backing for hosts +- [fdb4d847] vcsim: untangle container/VM to allow reuse of container logic for hosts +- [40264da9] Trim leading slash on soap path +- [9d8380ce] vcsim: Fix RefreshDatastore to return a valid response +- [47dd6e02] vcsim: add PerformanceManager counter values +- [c6a9ac8f] Bypass lookup svc for STS and SSOadmin clients +- [ddfd7eb0] remove bad spacing in new pull request template +- [65b6c51f] vcsim: add lookup.EndpointURL tests +- [c460f706] chore: Dockerfile & steps for generating types +- [4cf0b760] Allow picking datastore upload URL scheme by env +- [319e4723] build: quote golang version in release file to workaround issue in github action Close [#3179](https://github.com/vmware/govmomi/issues/3179) +- [65814f0c] fix: Update some goreleaser deprecated fields +- [b4eac193] fix: check the error chain when validating if it's x509 error +- [cd9446c7] vcsim: apply PCI UnitNumber offset of 7 for ethernet +- [3322f61b] Merge branch 'main' of github.com:vmware/govmomi into notable-user-otel-contrib +- [e34c7218] govc: Add CLI device protocol support for vm.network.add +- [eebdbefc] add opentelemetry collector contrib as notable user +- [86cadf21] fix: Fix the gorelease +- [1711a843] fix: avoid modifying client transport outside of NewClient +- [313aa85b] fix: share http.Transport with service clients +- [d648a215] add cnssyncdatastore API +- [5c7bf5f8] Remove client request log from debug tracing +- [11356057] vcsim: set StandbyMode default to "none" +- [48bdfada] govc: Add --help +- [f81f3b36] fix: grep warnings during generating usage documentation +- [28014f9b] govc: Add general usage message +- [0a351a84] vcsim: Add RUN.env flag to inject environment variables to container-backed VM +- [112777b8] vcsim: Fix VM ExtraConfig +- [e6217900] vcsim: make task lock handoff optional +- [6c0ed53b] vcsim: async guest shutdown and standby +- [7e490563] chore: add missing guest OS IDs +- [297c79bf] vcsim: add VirtualMachine.StandbyGuest support +- [833cf28e] build(deps): bump github.com/stretchr/testify from 1.8.3 to 1.8.4 +- [2d11115b] fix: support `binary` and `dateTime` in JSON +- [2731f2d5] Rm SetIndent in json.NewEncoder / JSON file name +- [0ed91a21] chore: bump embano1/wip +- [c4ffe464] fix: add esxcli.Fault and revert Error() string +- [174fb998] build(deps): bump github.com/stretchr/testify from 1.8.2 to 1.8.3 +- [e5f3cd0b] govc: add detail error message for host.esxcli commands +- [c65a8461] build(deps): bump chuhlomin/render-template from 1.6 to 1.7 +- [93cb079b] fix: byte, float and int (de) serialization +- [7a04bd00] vcsim: Fix FindByInventoryPath to handle root folder +- [81733d0e] govc: add cluster.mv command +- [685bd768] Add RUN.port.xx flag to publish ports on container backed VM +- [8bc2caa1] fix: avoid govc -verbose flag panic if an UpdateSet is nil +- [78a979c9] vcsim: Add CSV format support to QueryPerf API +- [9ba1b852] fix: include StoragePod Datastore children in ContainerView +- [8b00a93f] fix: only limit the number of samples generated to maxSample when maxSample is greater than 0 and the number of samples to generate is greater than maxSample Closes: [#3097](https://github.com/vmware/govmomi/issues/3097) +- [25865e57] api: set inventory path in SearchIndex.FindByInventoryPath +- [c6005086] chore: Err on json.Decode for invalid type/vals +- [5a2fa4fd] build(deps): bump nokogiri from 1.13.10 to 1.14.3 in /gen +- [4ed5b077] Make mounting DMI information optional with docker-backed vcsim +- [a1c8c4c8] build(deps): bump peter-evans/create-pull-request from 4 to 5 +- [8bcff40b] build(deps): bump peter-evans/create-or-update-comment from 2 to 3 +- [daaaca0f] govc: Add support for CNS volume snapshots +- [bf0510b1] build(deps): bump github.com/google/go-cmp from 0.5.7 to 0.5.9 +- [477bf69b] govc: Support JSON protocol using environment variable +- [38d0ac0d] api: Add JSON transport for vim25 +- [4ed07633] fix: support govc ls -xml flag +- [2f5d7c62] chore: fix WaitForUpdates bats test race +- [03718c0f] chore: remove sso bats test hacks +- [4aad418a] chore: upgrade to bats-core v1.9.0 release +- [d1af63ff] chore: fix jq query case +- [91f51cfb] chore: sync httptest/server race fix +- [80e6b73f] chore: add timeout to bats tests +- [49f82b8e] build(deps): bump actions/stale from 7 to 8 +- [b8007c4b] govc: dont check poweredOn for vm.console vmrc requests +- [0938fba2] api: Add ServerGuid to gen'd MoRef +- [71493efa] examples: add rest.Client.LoginByToken +- [3bf46949] examples: add session.Manager.LoginByToken +- [c62983fd] vcsim: add ssoadmin user and group management +- [3158766f] chore: adjust cert trust checks to support newer Go versions +- [4153cba9] chore: Update CI to Go 1.20 +- [5b3da2e4] chore: upgrade golangci-lint +- [b3a9e0c6] build(deps): bump actions/setup-go from 3 to 4 +- [6b34770c] govc: add sso.idp.ldap.update command +- [e5b2aa37] govc: Add feature VM IOMMU enablement support +- [1ea4b002] build(deps): bump golang.org/x/text from 0.3.7 to 0.3.8 in /hack/tools +- [4f9f126a] Use string pointer for library/item description field. +- [e09a4128] api: support find.NetworkList by ID +- [e8fa981e] api: support find.Network by cluster path +- [ea058454] lookup.EndpointURL should only save thumbprints for endpoints outside of vCenter +- [eb9c11c6] vcsim: add guest.net.ipConfig +- [825c73c2] chore: bats related fixes +- [f4c678ad] govc: Add checksum validation to govc import.ova +- [1991de51] chore: Remove JSON tag for "This" / ArrayOf "_value" +- [e935b5a8] govc: Add feature to get and set default idp +- [1970ec36] build(deps): bump actions/stale from 6 to 7 +- [8554329c] fix: Pin the result limit of ssoadmin client to its MAX +- [b594bf1f] chore: Move to main +- [4e6d6424] api: JSON Discriminators for vim25/types +- [99200868] api: Generate JSON tags +- [e639aba1] chore: Exclude vim25/json from CodeStyle workflow +- [e4a36881] docs: Add README to vendored JSON pkg +- [908aa065] chore: Include LICENSE in vendored JSON pkg +- [5caa20a4] chore: JSON Encoding w Discriminator Support +- [dc1a57ec] build(deps): bump goreleaser/goreleaser-action from 3 to 4 +- [a581fd01] chore: Vendor Go 1.17.13 encoding/json +- [9bd958aa] build(deps): bump nokogiri from 1.13.9 to 1.13.10 in /gen + + +## [Release v0.30.7](https://github.com/vmware/govmomi/compare/v0.30.6...v0.30.7) + +> Release Date: 2023-08-04 + +### 🐞 Fix + +- [cd0c259a] Update some goreleaser deprecated fields + +### 💫 `vcsim` (Simulator) + +- [3dac2e7d] Fix RefreshDatastore to return a valid response +- [fe7a0ac2] add PerformanceManager counter values + +### 🧹 Chore + +- [46fd9d2d] Update version.go for v0.30.7 + +### ⚠️ BREAKING + +### 📖 Commits + +- [46fd9d2d] chore: Update version.go for v0.30.7 +- [3dac2e7d] vcsim: Fix RefreshDatastore to return a valid response +- [fe7a0ac2] vcsim: add PerformanceManager counter values +- [552dfab2] build: quote golang version in release file to workaround issue in github action Close [#3179](https://github.com/vmware/govmomi/issues/3179) +- [cd0c259a] fix: Update some goreleaser deprecated fields + + +## [Release v0.30.6](https://github.com/vmware/govmomi/compare/v0.30.5...v0.30.6) + +> Release Date: 2023-07-17 + +### 🐞 Fix + +- [ad995d4e] check the error chain when validating if it's x509 error +- [0a77c755] Fix the gorelease + +### 💫 `govc` (CLI) + +- [4df1b85b] Add CLI device protocol support for vm.network.add + +### 🧹 Chore + +- [55614148] Update version.go for v0.30.6 +- [1079be90] adjust cert trust checks to support newer Go versions +- [64aafeb9] Update CI to Go 1.20 + +### ⚠️ BREAKING + +### 📖 Commits + +- [55614148] chore: Update version.go for v0.30.6 +- [ad995d4e] fix: check the error chain when validating if it's x509 error +- [1079be90] chore: adjust cert trust checks to support newer Go versions +- [0a77c755] fix: Fix the gorelease +- [4df1b85b] govc: Add CLI device protocol support for vm.network.add +- [64aafeb9] chore: Update CI to Go 1.20 + + +## [Release v0.30.5](https://github.com/vmware/govmomi/compare/v0.30.4...v0.30.5) + +> Release Date: 2023-06-27 + +### 🐞 Fix + +- [03aa9dca] avoid govc -verbose flag panic if an UpdateSet is nil +- [b366e940] include StoragePod Datastore children in ContainerView +- [ae6efc9f] only limit the number of samples generated to maxSample when maxSample is greater than 0 and the number of samples to generate is greater than maxSample Closes: [#3097](https://github.com/vmware/govmomi/issues/3097) +- [b1290083] support govc ls -xml flag + +### 💡 Examples + +- [46bf2408] add rest.Client.LoginByToken +- [d4e31429] add session.Manager.LoginByToken + +### 💫 API Changes + +- [afd45d68] set inventory path in SearchIndex.FindByInventoryPath + +### 💫 `govc` (CLI) + +- [ecca4141] dont check poweredOn for vm.console vmrc requests + +### 💫 `vcsim` (Simulator) + +- [844274fd] set StandbyMode default to "none" +- [a405207d] Add RUN.env flag to inject environment variables to container-backed VM +- [3466b11d] Fix FindByInventoryPath to handle root folder +- [04737364] Add CSV format support to QueryPerf API +- [d46fe80a] add ssoadmin user and group management + +### 🧹 Chore + +- [5373c143] Update version.go for v0.30.5 +- [e2f14cd9] add missing guest OS IDs + +### ⚠️ BREAKING + +### 📖 Commits + +- [5373c143] chore: Update version.go for v0.30.5 +- [844274fd] vcsim: set StandbyMode default to "none" +- [a405207d] vcsim: Add RUN.env flag to inject environment variables to container-backed VM +- [e2f14cd9] chore: add missing guest OS IDs +- [3466b11d] vcsim: Fix FindByInventoryPath to handle root folder +- [3afdbf25] Add RUN.port.xx flag to publish ports on container backed VM +- [03aa9dca] fix: avoid govc -verbose flag panic if an UpdateSet is nil +- [04737364] vcsim: Add CSV format support to QueryPerf API +- [b366e940] fix: include StoragePod Datastore children in ContainerView +- [ae6efc9f] fix: only limit the number of samples generated to maxSample when maxSample is greater than 0 and the number of samples to generate is greater than maxSample Closes: [#3097](https://github.com/vmware/govmomi/issues/3097) +- [afd45d68] api: set inventory path in SearchIndex.FindByInventoryPath +- [16a58c2f] Make mounting DMI information optional with docker-backed vcsim +- [b1290083] fix: support govc ls -xml flag +- [ecca4141] govc: dont check poweredOn for vm.console vmrc requests +- [46bf2408] examples: add rest.Client.LoginByToken +- [d4e31429] examples: add session.Manager.LoginByToken +- [d46fe80a] vcsim: add ssoadmin user and group management + + +## [Release v0.30.4](https://github.com/vmware/govmomi/compare/v0.30.3...v0.30.4) + +> Release Date: 2023-03-16 + +### 💫 API Changes + +- [23a6824e] support find.Network by cluster path +- [f4f6a5a7] support find.NetworkList by ID + +### 💫 `govc` (CLI) + +- [52328902] Add feature VM IOMMU enablement support + +### 🧹 Chore + +- [4561966a] Update version.go for v0.30.4 + +### ⚠️ BREAKING + +### 📖 Commits + +- [4561966a] chore: Update version.go for v0.30.4 +- [52328902] govc: Add feature VM IOMMU enablement support +- [23a6824e] api: support find.Network by cluster path +- [f4f6a5a7] api: support find.NetworkList by ID + + +## [Release v0.30.3](https://github.com/vmware/govmomi/compare/v0.30.2...v0.30.3) + +> Release Date: 2023-03-16 + +### 🧹 Chore + +- [0d36cdc9] Update version.go for v0.30.3 + +### ⚠️ BREAKING + +### 📖 Commits + +- [0d36cdc9] chore: Update version.go for v0.30.3 + + +## [Release v0.30.2](https://github.com/vmware/govmomi/compare/v0.30.1...v0.30.2) + +> Release Date: 2023-02-01 + +### 🐞 Fix + +- [4136fd8e] Pin the result limit of ssoadmin client to its MAX + +### 💫 `vcsim` (Simulator) + +- [997d9ddc] add guest.net.ipConfig + +### 🧹 Chore + +- [9078b0b4] Update version.go for v0.30.2 + +### ⚠️ BREAKING + +### 📖 Commits + +- [9078b0b4] chore: Update version.go for v0.30.2 +- [997d9ddc] vcsim: add guest.net.ipConfig +- [4136fd8e] fix: Pin the result limit of ssoadmin client to its MAX + + +## [Release v0.30.1](https://github.com/vmware/govmomi/compare/v0.30.0...v0.30.1) + +> Release Date: 2023-01-28 + +### 🧹 Chore + +- [76a194ea] Update version.go for v0.30.1 + +### ⚠️ BREAKING + +### 📖 Commits + +- [76a194ea] chore: Update version.go for v0.30.1 +- [5818061a] build(deps): bump goreleaser/goreleaser-action from 3 to 4 +- [fee275a6] lookup.EndpointURL should only save thumbprints for endpoints outside of vCenter + + +## [Release v0.30.0](https://github.com/vmware/govmomi/compare/v0.29.0...v0.30.0) + +> Release Date: 2022-12-12 + +### 🐞 Fix + +- [1ad33d48] Heal the broken Namespace API +- [22c48147] Update $mktemp to support macOS +- [05b0b08c] DialTLSContext / Go 1.18+ CertificateVerify support + +### 💫 API Changes + +- [58f4112b] Update types to vSphere 8.0 GA +- [ba206c5b] add Content Library security compliance support +- [4c24f821] Add SRIOV device names +- [642156dd] Adds vSphere 7.0u1-u3 support to namespace-management (Tanzu) + +### 💫 `govc` (CLI) + +- [60a18c56] about.cert was not respecting -k +- [15d1181d] bash completion improvements +- [0dbf717b] Add sso.lpp.info and sso.lpp.update commands +- [fe87cff9] host.info: use writer instead of os.stdout +- [a7196e41] host.info: use writer instead of os.stdout +- [3d6de9da] fix host.esxcli runtime error occurred when no arguments specified +- [8c7ba5ef] Add feature in sso.group.ls to list groups using FindGroupsInGroup method +- [dc3e1d79] Add feature sso.group.lsgroups using FindGroupsInGroup method +- [bf991e6e] add event key for json and plain text output +- [2017e846] Support creating content libraries with security policies + +### 💫 `vcsim` (Simulator) + +- [86f9d42a] Update test keys to be RSA 2048 +- [cedf695b] Fix duplicated name check in CloneVM_Task +- [8f4da558] add QueryNetworkHint support for LLDP and CDP details +- [1cab3254] Fix RetrieveProperties path validation to avoid panic +- [7f42a1d2] use node id for ServiceContent.InstanceUuid +- [03319493] Fix snapshot tasks to update rootSnapshot +- [b6ebcb6b] Fix disk capacity validation in ConfigureDevices +- [61032a23] Fix StorageIOAllocationInfo of VirtualDisk +- [cbfe0c93] support disconnect/reconnect host +- [b44828a4] Fix datastore freespace changed by ReconfigVM_Task + +### 📃 Documentation + +- [813a5d88] update `README.md` + +### 🧹 Chore + +- [eabc29ba] Update version.go for v0.30.0 + +### ⚠️ BREAKING + +### 📖 Commits + +- [eabc29ba] chore: Update version.go for v0.30.0 +- [1c919824] Update CONTRIBUTORS for release +- [1ad33d48] fix: Heal the broken Namespace API +- [22c48147] fix: Update $mktemp to support macOS +- [05b0b08c] fix: DialTLSContext / Go 1.18+ CertificateVerify support +- [86f9d42a] vcsim: Update test keys to be RSA 2048 +- [60a18c56] govc: about.cert was not respecting -k +- [58f4112b] api: Update types to vSphere 8.0 GA +- [15d1181d] govc: bash completion improvements +- [c018f078] perms on template files +- [813a5d88] docs: update `README.md` +- [0dbf717b] govc: Add sso.lpp.info and sso.lpp.update commands +- [fe87cff9] govc: host.info: use writer instead of os.stdout +- [a7196e41] govc: host.info: use writer instead of os.stdout +- [ba206c5b] api: add Content Library security compliance support +- [cedf695b] vcsim: Fix duplicated name check in CloneVM_Task +- [8f4da558] vcsim: add QueryNetworkHint support for LLDP and CDP details +- [3b2816ac] Add optional recommRequired PlaceVmsXCluster req arguments +- [f975908a] build(deps): bump andstor/file-existence-action from 1 to 2 +- [1373b80f] build(deps): bump chuhlomin/render-template from 1.5 to 1.6 +- [dc55a27e] build(deps): bump nokogiri from 1.13.6 to 1.13.9 in /gen +- [63980ff2] Fix: use latestPages in task HistoryCollector +- [3d6de9da] govc: fix host.esxcli runtime error occurred when no arguments specified +- [1e9eed94] Update list of projects using govmomi +- [7f4d115c] fixup! api: Add SRIOV device names +- [8f1dc575] Add API cnsreconfigpolicy bindings and static check fixes to cns/client_test.go +- [bf68e8f0] fixup! api: Add SRIOV device names +- [4c24f821] api: Add SRIOV device names +- [c1bb56db] Updated USAGE.md +- [aca677ad] build(deps): bump actions/stale from 5 to 6 +- [1cab3254] vcsim: Fix RetrieveProperties path validation to avoid panic +- [65a6f6bc] Address review comments +- [99d12605] correct new lines in group.ls +- [4d9f6e01] correct new lines in USAGE.md +- [e5bee862] move FindUsersInGroup to users.ls +- [8c7ba5ef] govc: Add feature in sso.group.ls to list groups using FindGroupsInGroup method +- [ee332ae7] Add new query selection parameters to be used for QueryAllVolume/QueryVolumeAsync API +- [dc3e1d79] govc: Add feature sso.group.lsgroups using FindGroupsInGroup method +- [201ae28f] Add common stub for hgfs for non-linux env +- [7f42a1d2] vcsim: use node id for ServiceContent.InstanceUuid +- [76e99b00] Boilerplate check requires a date range in the license. +- [bf991e6e] govc: add event key for json and plain text output +- [4a29caee] add OpenBSD build constraint +- [81bc76bc] toolbbox: add hgfs OpenBSD stub +- [03319493] vcsim: Fix snapshot tasks to update rootSnapshot +- [b6ebcb6b] vcsim: Fix disk capacity validation in ConfigureDevices +- [2017e846] govc: Support creating content libraries with security policies +- [642156dd] api: Adds vSphere 7.0u1-u3 support to namespace-management (Tanzu) +- [61032a23] vcsim: Fix StorageIOAllocationInfo of VirtualDisk +- [cbfe0c93] vcsim: support disconnect/reconnect host +- [b44828a4] vcsim: Fix datastore freespace changed by ReconfigVM_Task + + +## [Release v0.29.0](https://github.com/vmware/govmomi/compare/v0.28.5...v0.29.0) + +> Release Date: 2022-07-06 + +### 🐞 Fix + +- [d6dd8fb3] Typos in vim25/soap/client CA tests +- [e086dfe4] generate negative device key in AssignController +- [37b3b24c] avoid possible panic in govc metric commands + +### 💫 API Changes + +- [e6b5974a] Add versioned user-agent header + +### 💫 `vcsim` (Simulator) + +- [a1a36c9a] Fix disk capacity fields in ReconfigVM_Task +- [361c90ca] Remove VM Guest.Net entry when removing Ethernet card + +### 📃 Documentation + +- [5f5fb51e] Fix broken link in PR template + +### 🧹 Chore + +- [69ac8494] Update version.go for v0.29.0 +- [80489cb5] Update release automation + +### ⚠️ BREAKING + +### 📖 Commits + +- [69ac8494] chore: Update version.go for v0.29.0 +- [7d3b2b39] Update generated types +- [a1a36c9a] vcsim: Fix disk capacity fields in ReconfigVM_Task +- [5f5fb51e] docs: Fix broken link in PR template +- [d6dd8fb3] fix: Typos in vim25/soap/client CA tests +- [e086dfe4] fix: generate negative device key in AssignController +- [361c90ca] vcsim: Remove VM Guest.Net entry when removing Ethernet card +- [80489cb5] chore: Update release automation +- [e6b5974a] api: Add versioned user-agent header +- [37b3b24c] fix: avoid possible panic in govc metric commands + + +## [Release v0.28.5](https://github.com/vmware/govmomi/compare/v0.28.4...v0.28.5) + +> Release Date: 2022-09-30 + +### ⚠️ BREAKING + +### 📖 Commits + + + +## [Release v0.28.4](https://github.com/vmware/govmomi/compare/v0.28.3...v0.28.4) + +> Release Date: 2022-10-01 + +### ⚠️ BREAKING + +### 📖 Commits + + + +## [Release v0.28.3](https://github.com/vmware/govmomi/compare/v0.28.1...v0.28.3) + +> Release Date: 2022-09-30 + +### 🐞 Fix + +- [371a24a4] Interface conversion panic in pkg simulator +- [a982c033] use correct controlflag for vslm SetControlFlags API test +- [310516e2] govc: disambiguate vm/host search flags in vm.migrate +- [6af2cdc3] govc-tests in Go v1.18 +- [142cdca4] Security update golangci-lint +- [971079ba] use correct vcenter.DeploymentSpec.VmConfigSpec json tag + +### 💫 API Changes + +- [ca7ee510] add VmConfigSpec field to content library DeploymentSpec + +### 💫 `govc` (CLI) + +- [515ca29f] Use unique searchFlagKey when calling NewSearchFlag +- [9d4ca658] add library.deploy '-config' flag +- [fc17df08] add 'device.clock.add' command +- [11f2d453] Edit disk storage IO + +### 💫 `vcsim` (Simulator) + +- [578b95e5] Fix createVM to encode VM name +- [3325da0c] add content library VmConfigSpec support +- [8928a489] Update Dockerfile + +### 🧹 Chore + +- [e1f76e37] Add missing copyright header +- [6ed812fe] Add Go boilerplate check + +### ⚠️ BREAKING + +### 📖 Commits + +- [11e89157] new to go hence fixing coding errors +- [e5ffb4a6] fixed syntax errors +- [b62ddfaa] fixing header check failure +- [9e97647e] Fixing UT failures +- [2fd7d28f] adding support for LLDP and CDP details for GOVC and VCSIM +- [578b95e5] vcsim: Fix createVM to encode VM name +- [371a24a4] fix: Interface conversion panic in pkg simulator +- [a982c033] fix: use correct controlflag for vslm SetControlFlags API test +- [310516e2] fix: govc: disambiguate vm/host search flags in vm.migrate +- [5929abfb] correct SetControlFlags and ClearControlFlags APIs +- [6af2cdc3] fix: govc-tests in Go v1.18 +- [e1f76e37] chore: Add missing copyright header +- [6ed812fe] chore: Add Go boilerplate check +- [142cdca4] fix: Security update golangci-lint +- [3f4993d4] build(deps): bump chuhlomin/render-template from 1.4 to 1.5 +- [971079ba] fix: use correct vcenter.DeploymentSpec.VmConfigSpec json tag +- [892dcfcc] build(deps): bump nokogiri from 1.13.5 to 1.13.6 in /gen +- [303f0d95] build(deps): bump goreleaser/goreleaser-action from 2 to 3 +- [7eef76c3] build(deps): bump nokogiri from 1.13.4 to 1.13.5 in /gen +- [515ca29f] govc: Use unique searchFlagKey when calling NewSearchFlag +- [9d4ca658] govc: add library.deploy '-config' flag +- [c5ebd552] fix:fail to add ssd disk into allflash disk group Closes: [#2846](https://github.com/vmware/govmomi/issues/2846) +- [88f48e02] Updated USAGE.md +- [3325da0c] vcsim: add content library VmConfigSpec support +- [ca7ee510] api: add VmConfigSpec field to content library DeploymentSpec +- [8928a489] vcsim: Update Dockerfile +- [bf5d054d] Fixed docs for govc library.info w/-json +- [2f9fab55] emacs: fix json mode +- [fc17df08] govc: add 'device.clock.add' command +- [11f2d453] govc: Edit disk storage IO + + +## [Release v0.28.1](https://github.com/vmware/govmomi/compare/v0.28.0...v0.28.1) + +> Release Date: 2023-01-27 + +### 🐞 Fix + +- [c27ab6b9] use correct controlflag for vslm SetControlFlags API test + +### ⚠️ BREAKING + +### 📖 Commits + +- [205cbcdc] lookup.EndpointURL should only save thumbprints for endpoints outside of vCenter +- [c27ab6b9] fix: use correct controlflag for vslm SetControlFlags API test +- [8d43c82c] correct SetControlFlags and ClearControlFlags APIs + + +## [Release v0.28.0](https://github.com/vmware/govmomi/compare/v0.27.5...v0.28.0) + +> Release Date: 2022-04-27 + +### 🐞 Fix + +- [5ef4aaaf] DiskFileOperation must consider both capacity fields +- [3566a35d] govc guest validate username/password +- [bbbfd7bc] govc test workflow cp error +- [a587742b] avoid debug trace if http.Request.Body is nil +- [7e2ce135] Ignore concurrent deletes in GetCategories +- [a7c6f15b] Allow go 1.17 to go install +- [0f0201ad] vapi - special param encoding for edge cluster lookup +- [e5209e34] rest.Client.LoginByToken invalid signature +- [ad66761e] support govc import.spec for remote ova +- [ebeaa71b] Add IPv6 support for signing HTTP request +- [512c168e] govc vm.destroy only destroys the 1st argument +- [d25aba08] govc vcsa.net.proxy.info doesnt give output in json format +- [ac7c9bf9] avoid possible panic in HostSystem.ManagementIPs +- [10fec668] CHANGELOG sorting and generation + +### 💡 Examples + +- [c5826b8f] Add Alarm Manager Example +- [9617bded] add HostConfigManager_OptionManager +- [a1a9d848] add VirtualDeviceList_SelectByBackingInfo + +### 💫 API Changes + +- [61c40001] add GPU support to VirtualDeviceList.SelectByBackingInfo + +### 💫 `govc` (CLI) + +- [d8dd7f2b] Add CLI command cluster.module +- [49a83e71] Fix arguments validation in datastore.disk.inflate/shrink +- [01d31b53] Add Feature dvs.create '-num-uplinks' flag +- [40e6cbc8] Add Appliance access API +- [949ef572] Add Appliance shutdown API's +- [d5ed6855] Add support for VM hardware upgrade scheduling +- [742f2893] add support for supervisor services deploy +- [3ba25d70] Require full or absolute paths +- [a4ae62e7] Add library info command +- [8fde8bce] validate library.deploy arguments + +### 💫 `vcsim` (Simulator) + +- [3d8ddf16] Fix device connectivity when vm is powered off +- [111ad9fc] Use new action type in simulator PlaceVmsXCluster response +- [e92db045] Fix NFS datastore moid collision +- [16e6bace] set summary.guest.{hostName,ipAddress} in CustomizeVM +- [46a85642] add ssoadmin simulator +- [811b829c] Fix port filtering by criteria in FetchDVPorts +- [e8425be5] revert vapi.Status() method +- [451ec35a] Fix keys in DistributedVirtualPorts +- [6542ccb5] Fix CreateFolder to encode folder name +- [8629c499] Allow updating custom fields +- [93c2afd1] copy device list when cloning a VM +- [3214d97a] add support for cloning HostSystems +- [9b3d6353] Fix distribute VMs across resource pools +- [93d39917] Add TenantManager support in simulator +- [6de12ab7] allow VM PowerOff when Host is in maintenance mode +- [48f7a881] emit VmMigratedEvent in RelocateVM method + +### 📃 Documentation + +- [9ea287c2] Update documentation +- [b4a2d3b3] Add git blog post to CONTRIBUTING +- [c7e103e7] Clarify squash in CONTRIBUTING +- [9317bdaf] Update CONTIRBUTING.md file + +### 🧹 Chore + +- [d60b21d5] Optimize Go CI workflows +- [2d72f576] Add dependabot configuration +- [5c301091] Use powerclicore on ghcr.io +- [7d8af1e7] Update CI to Go 1.18 +- [205c0e0d] Add api: commit prefix +- [b6cd7c1b] Add link to Discussions in New Issue +- [15efe49f] Replace /rest with /api in vcsa.shutdown API's +- [db7edbf4] Update workflow Go versions +- [05c28f4a] upgrade go directive in go.mod to 1.17 +- [ebff29b7] Add notes to PR RELEASE workflow + +### ⚠️ BREAKING + +Fix distribute VMs across resource pools [9b3d6353]: +The name of virtual machines deployed in `vcsim` in a cluster (and +optionally child resource pools) has changed to include the +corresponding resource pool name. VM names deployed to standalone hosts +in `vcsim` are not changed. + +### 📖 Commits + +- [9ea287c2] docs: Update documentation +- [89ae0933] build(deps): bump actions/stale from 3 to 5 +- [d60b21d5] chore: Optimize Go CI workflows +- [0d1b4189] build(deps): bump peter-evans/create-or-update-comment from 1 to 2 +- [e85b164d] build(deps): bump github/codeql-action from 1 to 2 +- [5ef4aaaf] fix: DiskFileOperation must consider both capacity fields +- [3566a35d] fix: govc guest validate username/password +- [1f0f8cc8] build(deps): bump chuhlomin/render-template from 1.2 to 1.4 +- [7324f647] build(deps): bump actions/upload-artifact from 2 to 3 +- [808a439a] build(deps): bump peter-evans/create-pull-request from 3 to 4 +- [bdee9992] build(deps): bump github.com/google/uuid from 1.2.0 to 1.3.0 +- [2d72f576] chore: Add dependabot configuration +- [bbbfd7bc] fix: govc test workflow cp error +- [d8dd7f2b] govc: Add CLI command cluster.module +- [90c90a0a] build(deps): bump nokogiri from 1.13.2 to 1.13.4 in /gen +- [3cb3eff1] ConfigInfo2ConfigSpec +- [3d8ddf16] vcsim: Fix device connectivity when vm is powered off +- [b4a2d3b3] docs: Add git blog post to CONTRIBUTING +- [49a83e71] govc: Fix arguments validation in datastore.disk.inflate/shrink +- [5c301091] chore: Use powerclicore on ghcr.io +- [7d8af1e7] chore: Update CI to Go 1.18 +- [111ad9fc] vcsim: Use new action type in simulator PlaceVmsXCluster response +- [c5826b8f] examples: Add Alarm Manager Example +- [46583051] Move the ClusterClusterInitialPlacementAction to unreleased types + fix linter error +- [9b1de9c8] Fix a linter error +- [cb2b8f5c] Add a new type of cluster action used for placing a VM. This action inherits from InitialPlacement action because it conveys the resource pool and host for placing the VM. In addition, it also has the VM's ConfigSpecwhich is used for indicating the recommended datastore for each virtual disk in VM's ConfigSpec +- [9617bded] examples: add HostConfigManager_OptionManager +- [8e4054fa] adding a check that number of uplinks otherwise do default +- [aada9aa1] Reconfigure LACP API for DVS +- [a1a9d848] examples: add VirtualDeviceList_SelectByBackingInfo +- [61c40001] api: add GPU support to VirtualDeviceList.SelectByBackingInfo +- [e92db045] vcsim: Fix NFS datastore moid collision +- [01d31b53] govc: Add Feature dvs.create '-num-uplinks' flag +- [11e469a4] build(deps): bump nokogiri from 1.12.5 to 1.13.2 in /gen +- [547c63fd] Added Support for vrdma NIC Type Signed-off-by: C S P Nanda +- [205c0e0d] chore: Add api: commit prefix +- [b6cd7c1b] chore: Add link to Discussions in New Issue +- [15efe49f] chore: Replace /rest with /api in vcsa.shutdown API's +- [40e6cbc8] govc: Add Appliance access API +- [16e6bace] vcsim: set summary.guest.{hostName,ipAddress} in CustomizeVM +- [a587742b] fix: avoid debug trace if http.Request.Body is nil +- [7e2ce135] fix: Ignore concurrent deletes in GetCategories +- [1875bac1] Add PlaceVmsXCluster bindings and simulator +- [a7c6f15b] fix: Allow go 1.17 to go install +- [a5498b89] Add BackingDiskObjectId go bindings to CNS API +- [0f0201ad] fix: vapi - special param encoding for edge cluster lookup +- [46a85642] vcsim: add ssoadmin simulator +- [297a3cae] ssoadmin: add IdentitySources API bindings +- [811b829c] vcsim: Fix port filtering by criteria in FetchDVPorts +- [e5209e34] fix: rest.Client.LoginByToken invalid signature +- [c7e103e7] docs: Clarify squash in CONTRIBUTING +- [e8425be5] vcsim: revert vapi.Status() method +- [ad66761e] fix: support govc import.spec for remote ova +- [803b6362] sts: support issuing HoK token using HoK token +- [451ec35a] vcsim: Fix keys in DistributedVirtualPorts +- [949ef572] govc: Add Appliance shutdown API's +- [6542ccb5] vcsim: Fix CreateFolder to encode folder name +- [d5ed6855] govc: Add support for VM hardware upgrade scheduling +- [9317bdaf] docs: Update CONTIRBUTING.md file +- [8629c499] vcsim: Allow updating custom fields +- [93c2afd1] vcsim: copy device list when cloning a VM +- [ebeaa71b] fix: Add IPv6 support for signing HTTP request +- [b729a862] Fix typo in (simulator.Context).WithLock() comment +- [cd577f46] Fixed doc +- [ca1f45ae] Added command flag documentation +- [512240a0] Fixed goimports issues +- [ce88635f] Added vm::ExportSnapshot and snapshot flag to export.ovf +- [742f2893] govc: add support for supervisor services deploy +- [3214d97a] vcsim: add support for cloning HostSystems +- [3ba25d70] govc: Require full or absolute paths +- [db7edbf4] chore: Update workflow Go versions +- [512c168e] fix: govc vm.destroy only destroys the 1st argument +- [b51418e3] Add IsAlreadyExists error helper +- [05c28f4a] chore: upgrade go directive in go.mod to 1.17 +- [a4ae62e7] govc: Add library info command +- [d25aba08] fix: govc vcsa.net.proxy.info doesnt give output in json format +- [ac7c9bf9] fix: avoid possible panic in HostSystem.ManagementIPs +- [9b3d6353] vcsim: Fix distribute VMs across resource pools +- [1da8c5e8] Fix: Deep compare error types in simulator VM tests +- [d3eaa9b9] Support Creating/Reconfiguring a simulator VM with VApp properties +- [10fec668] fix: CHANGELOG sorting and generation +- [b05ed4e0] Independent simulator.Context per-subtask in PowerOnMultiVM. +- [a0224d91] Fix eam/simulator tests +- [e2498fb8] Change references from global Map to ctx.Map. +- [ab446838] Set the Context.Map's when global Map is set +- [3b86fd0c] Re-work TenantManager addition to ServiceContent for older clients +- [93d39917] vcsim: Add TenantManager support in simulator +- [9f737e00] fix updating stale url from Makefile +- [8fde8bce] govc: validate library.deploy arguments +- [6de12ab7] vcsim: allow VM PowerOff when Host is in maintenance mode +- [ebff29b7] chore: Add notes to PR RELEASE workflow +- [48f7a881] vcsim: emit VmMigratedEvent in RelocateVM method +- [bb4f739b] Support finding Portgroups by ID in Finder.Network + + +## [Release v0.27.5](https://github.com/vmware/govmomi/compare/v0.27.4...v0.27.5) + +> Release Date: 2022-06-02 + +### 🐞 Fix + +- [e97c9708] use correct controlflag for vslm SetControlFlags API test + +### ⚠️ BREAKING + +### 📖 Commits + +- [e97c9708] fix: use correct controlflag for vslm SetControlFlags API test +- [f8cf9ef7] correct SetControlFlags and ClearControlFlags APIs + + +## [Release v0.27.4](https://github.com/vmware/govmomi/compare/v0.27.3...v0.27.4) + +> Release Date: 2022-02-10 + +### 🐞 Fix + +- [285e80cd] avoid debug trace if http.Request.Body is nil +- [dde50904] Ignore concurrent deletes in GetCategories +- [cbc68fc0] rest.Client.LoginByToken invalid signature + +### 💫 `vcsim` (Simulator) + +- [df595d82] add ssoadmin simulator + +### ⚠️ BREAKING + +### 📖 Commits + +- [285e80cd] fix: avoid debug trace if http.Request.Body is nil +- [dde50904] fix: Ignore concurrent deletes in GetCategories +- [fc1fce62] Add PlaceVmsXCluster bindings and simulator +- [df595d82] vcsim: add ssoadmin simulator +- [9ca477aa] ssoadmin: add IdentitySources API bindings +- [24fe60f1] Add BackingDiskObjectId go bindings to CNS API +- [cbc68fc0] fix: rest.Client.LoginByToken invalid signature + + +## [Release v0.27.3](https://github.com/vmware/govmomi/compare/v0.27.2...v0.27.3) + +> Release Date: 2022-02-01 + +### 🐞 Fix + +- [2d7cd133] Add IPv6 support for signing HTTP request + +### ⚠️ BREAKING + +### 📖 Commits + +- [6b4e2391] sts: support issuing HoK token using HoK token +- [2d7cd133] fix: Add IPv6 support for signing HTTP request + + +## [Release v0.27.2](https://github.com/vmware/govmomi/compare/v0.27.1...v0.27.2) + +> Release Date: 2021-11-23 + +### 🐞 Fix + +- [f04d77d6] avoid possible panic in HostSystem.ManagementIPs + +### ⚠️ BREAKING + +### 📖 Commits + +- [f04d77d6] fix: avoid possible panic in HostSystem.ManagementIPs + + +## [Release v0.27.1](https://github.com/vmware/govmomi/compare/v0.27.0...v0.27.1) + +> Release Date: 2021-10-20 + +### ⚠️ BREAKING + +### 📖 Commits + +- [6209be5b] Support finding Portgroups by ID in Finder.Network + + +## [Release v0.27.0](https://github.com/vmware/govmomi/compare/v0.26.2...v0.27.0) + +> Release Date: 2021-10-14 + +### 🐞 Fix + +- [57c4be58] multi-value query params for vAPI methods +- [815e2d8f] avoid vNIC mapping in guest.TransferURL if URL.Host is an IP +- [81a7dbe9] avoid use of vNIC IP in guest.TransferURL if there are multiple +- [61afce31] Update CnsQueryAsync API request parameters to handle nil for QuerySelection +- [a601a8a8] generate negative device key + +### 💫 `govc` (CLI) + +- [b5426eba] Add feature to read file contents for ExtraConfig +- [85956c77] fix tasks to activate option dump/json/xml +- [f4ef4d93] Fix incorrect MoRef parsing +- [d695f4cf] Handle powered on VMs in vm.destroy +- [94f63681] add library.clone '-e' and '-m' options +- [2fcae372] add vsan info and change commands + +### 💫 `vcsim` (Simulator) + +- [fa457940] Fix PowerOnMultiVMTask() to return per-VM tasks +- [e67b1b11] check if VM host InMaintenanceMode + +### 📃 Documentation + +- [82e447d9] Update govc USAGE + +### 🧹 Chore + +- [05adcc97] Remove -i parameter in go install +- [18ea9cc5] Update PR and release docs + +### ⚠️ BREAKING + +Add task manager and collector [397c8aad]: +`event.Manager` does not embed `object.Common` anymore. Only the methods +`Client()` and `Reference()` are implemented. +`event.NewHistoryCollector()` is now unexported (to +`newHistoryCollector()`) as it was merely a helper and to comply with +the task manager implementation. + +### 📖 Commits + +- [78f30265] update contributors +- [68b54585] Refactor EAM code to use BaseAgencyConfigInfo interface instead of impl +- [d5ded1f0] Implement mo.Reference interface in task+event managers +- [038bc3d8] Update vslm types to vCenter 7.0U3 (build 18700403) +- [ae8161df] Update pbm types to vCenter 7.0U3 (build 18700403) +- [f2d167de] Update eam types to vCenter 7.0U3 (build 18700403) +- [f1c7b54d] Update vim25 types to vCenter 7.0U3 (build 18700403) +- [445fd552] Update gen.sh to vCenter 7.0U3 (build 18700403) +- [961f0ae6] example: find VirtualMachine's Cluster +- [57c4be58] fix: multi-value query params for vAPI methods +- [f7e8ed73] Set custom HTTP headers for VAPI calls +- [05adcc97] chore: Remove -i parameter in go install +- [82e447d9] docs: Update govc USAGE +- [b5426eba] govc: Add feature to read file contents for ExtraConfig +- [815e2d8f] fix: avoid vNIC mapping in guest.TransferURL if URL.Host is an IP +- [81a7dbe9] fix: avoid use of vNIC IP in guest.TransferURL if there are multiple +- [18ea9cc5] chore: Update PR and release docs +- [a66d23ed] build(deps): bump nokogiri from 1.11.4 to 1.12.5 in /gen +- [a853b300] Fix: Nil-Pointer Exception in ResourceAllocation +- [fa457940] vcsim: Fix PowerOnMultiVMTask() to return per-VM tasks +- [85956c77] govc: fix tasks to activate option dump/json/xml +- [61afce31] fix: Update CnsQueryAsync API request parameters to handle nil for QuerySelection +- [397c8aad] feat: Add task manager and collector +- [a601a8a8] fix: generate negative device key +- [f4ef4d93] govc: Fix incorrect MoRef parsing +- [e67b1b11] vcsim: check if VM host InMaintenanceMode +- [d695f4cf] govc: Handle powered on VMs in vm.destroy +- [a55fa7dc] feat: Add optional WaitOptions to WaitForUpdates +- [94f63681] govc: add library.clone '-e' and '-m' options +- [2fcae372] govc: add vsan info and change commands + + +## [Release v0.26.2](https://github.com/vmware/govmomi/compare/v0.26.1...v0.26.2) + +> Release Date: 2022-03-21 + +### 🐞 Fix + +- [76a22af3] avoid possible panic in HostSystem.ManagementIPs +- [566d2ac1] avoid use of vNIC IP in guest.TransferURL if there are multiple + +### ⚠️ BREAKING + +### 📖 Commits + +- [76a22af3] fix: avoid possible panic in HostSystem.ManagementIPs +- [566d2ac1] fix: avoid use of vNIC IP in guest.TransferURL if there are multiple + + +## [Release v0.26.1](https://github.com/vmware/govmomi/compare/v0.26.0...v0.26.1) + +> Release Date: 2021-08-16 + +### 🐞 Fix + +- [a366e352] Regenerated interface and type to include BaseAgencyConfigInfo. Closes: [#2545](https://github.com/vmware/govmomi/issues/2545). +- [d66ef551] explicitly import eam/simulator in test + +### 💡 Examples + +- [0c045a63] Add Property Wait example + +### 💫 `govc` (CLI) + +- [012f5348] support updating items in library.update command +- [5743d5b6] Allow cluster.change to set ClusterDrsConfigInfo.vmotionRate +- [03210c91] Add object.collect type flag alias help + +### 💫 `vcsim` (Simulator) + +- [ce6ed634] avoid race when fetching object Locker +- [31821de3] use 'domain-c' prefix for cluster moids +- [3625e6dd] propagate CustomizeVM MacAddress to Virtual NIC +- [389c0382] Take the host parameter into account while cloning a VM on a cluster +- [6fba1da7] Implement VSLM ExtendDisk_Task + +### 🧹 Chore + +- [ddc2b47a] Include commit details in BREAKING section + +### ⚠️ BREAKING + +### 📖 Commits + +- [a366e352] fix: Regenerated interface and type to include BaseAgencyConfigInfo. Closes: [#2545](https://github.com/vmware/govmomi/issues/2545). +- [655f8e5c] testing for lab +- [ce6ed634] vcsim: avoid race when fetching object Locker +- [31821de3] vcsim: use 'domain-c' prefix for cluster moids +- [0aa1de31] make processing of mac addresses case insensitive ([#2510](https://github.com/vmware/govmomi/issues/2510)) +- [012f5348] govc: support updating items in library.update command +- [0c045a63] examples: Add Property Wait example +- [f30cefc3] Add Reauth flag to skip loading cached sessions +- [3625e6dd] vcsim: propagate CustomizeVM MacAddress to Virtual NIC +- [5743d5b6] govc: Allow cluster.change to set ClusterDrsConfigInfo.vmotionRate +- [389c0382] vcsim: Take the host parameter into account while cloning a VM on a cluster +- [7bf48333] Added CNS querySnapshots binding, simulator testcases and client testcases +- [017ab414] Added CreateSnapshots and DeleteSnapshots methods in cns simulator as well as their test cases +- [03210c91] govc: Add object.collect type flag alias help +- [d66ef551] fix: explicitly import eam/simulator in test +- [ddc2b47a] chore: Include commit details in BREAKING section +- [6fba1da7] vcsim: Implement VSLM ExtendDisk_Task + + +## [Release v0.26.0](https://github.com/vmware/govmomi/compare/v0.25.0...v0.26.0) + +> Release Date: 2021-06-03 + +### 🐞 Fix + +- [70b92d6d] Isolate SSO govc tests + +### 💡 Examples + +- [81b1de17] add toolbox Client.Run + +### 💫 `govc` (CLI) + +- [e37e515b] fix default guest.run path for unsupported Windows guests +- [0e7012d0] Add support for getting the VC proxy and no-proxy configuration ([#2435](https://github.com/vmware/govmomi/issues/2435)) +- [6afb8ff9] Change 'Maintenance Mode' printing in host.info + +### 💫 `vcsim` (Simulator) + +- [dff7f6bb] fix panic in QueryPerfCounter method +- [df9dfde1] set VirtualMachine ChangeTrackingSupported property ([#2468](https://github.com/vmware/govmomi/issues/2468)) +- [0c0ed98a] fix race in CloneVM_Task +- [d01d0fa7] add simulator.RunContainer method +- [8ab0c99a] untie datastore capacity from local fs +- [d31941c8] Modify Usage of README. (based on v0.25.0) +- [4fea687c] include all namespaces in /about info +- [bd3467d4] avoid edit device panic when DeviceInfo is nil +- [35a42af5] add guest operations process support + +### 📃 Documentation + +- [75eee8e4] update govc/USAGE and CONTRIBUTORS +- [1f795d21] Add blog to vcsim README +- [2719c229] Document linker and GOFLAGS for build vars + +### 🧹 Chore + +- [b4e1f965] Fix CONTRIB link in greeting +- [6f2597be] Update CHANGELOG implementation +- [d3944e17] Add and reorder commits in CHANGELOG +- [a796d3fc] Add make help target +- [8bc8fd28] Add issue and PR templates +- [60e33916] Document commit prefixes +- [cac1d8d7] Add issue greeting +- [0f1c3f89] Add WIP Action +- [921ad37a] Remove dep files +- [1d4ce94a] Clean up documentation +- [991278b9] Remove unused release script +- [16d8add5] Automate CHANGELOG + +### ⚠️ BREAKING + +### 📖 Commits + +- [75eee8e4] docs: update govc/USAGE and CONTRIBUTORS +- [dff7f6bb] vcsim: fix panic in QueryPerfCounter method +- [b4e1f965] chore: Fix CONTRIB link in greeting +- [df9dfde1] vcsim: set VirtualMachine ChangeTrackingSupported property ([#2468](https://github.com/vmware/govmomi/issues/2468)) +- [8cbe64c5] Fix: Protect FileProvider.files to avoid concurrent modification +- [6f2597be] chore: Update CHANGELOG implementation +- [0c0ed98a] vcsim: fix race in CloneVM_Task +- [81b1de17] examples: add toolbox Client.Run +- [d01d0fa7] vcsim: add simulator.RunContainer method +- [9223b5ae] Add toolbox.NewClient method +- [8ab0c99a] vcsim: untie datastore capacity from local fs +- [e37e515b] govc: fix default guest.run path for unsupported Windows guests +- [d3944e17] chore: Add and reorder commits in CHANGELOG +- [83e29c69] Update GitHub Test Action to use Makefile +- [a7f2c47e] Update vslm types vC build 17986435 (7.0U2HP4) +- [067374fd] Update sms types vC build 17986435 (7.0U2HP4) +- [d9f507f0] Update pbm types vC build 17986435 (7.0U2HP4) +- [c89f8dd5] Update eam types vC build 17986435 (7.0U2HP4) +- [b72432ef] Update vim25 types vC build 17986435 (7.0U2HP4) +- [e53716dd] Update gen.sh to vC build 17986435 (7.0U2HP4) +- [1f795d21] docs: Add blog to vcsim README +- [338f5529] Ran "make fix" to correct lint issues +- [23d77ba4] Add support for golangci-lint +- [d31941c8] vcsim: Modify Usage of README. (based on v0.25.0) +- [7046a0d3] Support pre-auth handlers in vC Sim +- [2e8860d1] Add CNS Snapshot APIs in govmomi +- [13d4d376] Remove vendor +- [a796d3fc] chore: Add make help target +- [ef824a20] Fix QueryAsyncVolume API test to be invoked only for vSphere 7.0.3 +- [c1900234] Fix data race in simulator.container.id +- [3212351e] install bin doc: permalink to latest version +- [7d779833] Setup CodeQL Analysis +- [566250ff] build(deps): bump nokogiri from 1.11.1 to 1.11.4 in /gen +- [f814a9ca] ESX Agent Manager (EAM) Client and Simulator +- [0e7012d0] govc: Add support for getting the VC proxy and no-proxy configuration ([#2435](https://github.com/vmware/govmomi/issues/2435)) +- [8bc8fd28] chore: Add issue and PR templates +- [4fea687c] vcsim: include all namespaces in /about info +- [bd3467d4] vcsim: avoid edit device panic when DeviceInfo is nil +- [70b92d6d] fix: Isolate SSO govc tests +- [80c9053e] Correcting broken Kubernetes vSphere Cloud Provider links +- [60e33916] chore: Document commit prefixes +- [57a141f3] Update govc test docs with act +- [ff578914] Use "vcsim uuidgen" for bats tests +- [61e12ddb] Only greet unassociated users +- [e39dfdc8] Add chore section to CHANGELOG +- [6afb8ff9] govc: Change 'Maintenance Mode' printing in host.info +- [cac1d8d7] chore: Add issue greeting +- [0f1c3f89] chore: Add WIP Action +- [921ad37a] chore: Remove dep files +- [2719c229] docs: Document linker and GOFLAGS for build vars +- [f3645a96] Clarify SetRootCAs behavior +- [c368e57f] toolbox: add hgfs freebsd stub +- [35a42af5] vcsim: add guest operations process support +- [64e55d81] Set RoundTripper in ssoadmin.NewClient +- [1d4ce94a] chore: Clean up documentation +- [991278b9] chore: Remove unused release script +- [16d8add5] chore: Automate CHANGELOG +- [e8805c92] Add NotFoundFault in cns types +- [8576fe27] Add queryAsyncVolume in simulator +- [4b9e0813] Simplify binary download instructions +- [3062dda9] Remove Travis CI +- [0be5632f] adding rancher to projects and reorganizing in alpha order +- [4a63a28c] Add bindings for CnsQueryAsyncVolume API +- [a8c80b93] Update READMEs with artifacts and Docker images +- [26c9690c] Fix VM Guest test and vet warnings +- [a32cd0b3] Add RELEASE documentation +- [cc660b0e] Increase govc tests timeout +- [d7bfaf4f] toolbox: move process management to its own package +- [e86da96e] Exclude go files in release tarball + + +## [Release v0.25.0](https://github.com/vmware/govmomi/compare/v0.24.2...v0.25.0) + +> Release Date: 2021-04-16 + +### 💡 Examples + +- [38da87ff] add NetworkReference.EthernetCardBackingInfo + +### 💫 `govc` (CLI) + +- [1ac314c3] add vm.customize -dns-suffix flag +- [60e0e895] update test images URL +- [cdf3ace6] log invalid NetworkMapping.Name with import.ova command +- [f8b3d8a8] revert pretty print pruning optimization +- [35481467] add library.update command +- [749c2239] add session.ls -S flag +- [93245c1e] add tree command +- [790f9ce6] include sub task fault messages on failure +- [d2a353ba] remove device.boot -firmware default +- [de6032e0] add '-trace' and '-verbose' flags +- [63bb5c1e] metric command enhancements and fixes +- [7844a8c2] fix vm.migrate search index flags +- [5dacf627] fix cluster.usage Free field +- [f71bcf25] fix session curl when given a URL query +- [c954c2a5] validate license.remove +- [3b25c3f1] validate required library.clone NAME arg +- [344b7a30] note 'disk.ls -R' in volume.rm help +- [8942055a] add device.info examples to get disk UUID and vmdk +- [1b0af949] fix vm.markasvm examples +- [add8be5a] fix incorrect DeviceID value in device.pci.add +- [1f4f5640] add IPv6 support to vm.customize + +### 💫 `vcsim` (Simulator) + +- [27d8d2e4] put verbose logging behind '-trace' flag +- [0ef4ae22] add moid value mapping mappings +- [082f9927] add vsan simulator +- [25970530] fix Task.Info.Entity in RevertToSnapshot_Task +- [f0a045ac] set VirtualMachine.Config.CreateDate property +- [e51eb2b9] support EventFilterSpec.Time +- [8e45fa4a] emit CustomizationSucceeded event from CustomizeVM +- [c000bd6e] add DistributedVirtualSwitchManager +- [bcd5fa87] set VirtualDisk backing UUID +- [ccdcbe89] move product suffix in ServiceContent.About +- [393e7330] use linked list for EventHistoryCollector +- [9c4dc1a1] escape datastore name +- [9c2fe70f] record/replay EnvironmentBrowser.QueryConfigOption +- [5fd7e264] fix EventHistoryCollector fixes +- [0b755a59] switch bats tests from esx to vcsim env +- [3f1caf82] fixes for PowerCLI Get-VirtualNetwork + +### 📃 Documentation + +- [e18b601f] update for 0.25 release + +### ⚠️ BREAKING + +### 📖 Commits + +- [6fe8d60a] Fix folder write for govc container +- [e18b601f] docs: update for 0.25 release +- [1ac314c3] govc: add vm.customize -dns-suffix flag +- [22d911f6] Add Cron Docker Login Action +- [60e0e895] govc: update test images URL +- [3385b3e0] Add action to automate release +- [cdf3ace6] govc: log invalid NetworkMapping.Name with import.ova command +- [27d8d2e4] vcsim: put verbose logging behind '-trace' flag +- [f8b3d8a8] govc: revert pretty print pruning optimization +- [0ef4ae22] vcsim: add moid value mapping mappings +- [df08d4b2] First step towards release automation +- [f9b79a4f] export simulator.task.Wait() +- [917c4ec8] Ensure lock hand-off to simulator.Task goroutine +- [b45b228f] Simulator Task Delay +- [4b59b652] Make Simulator Tasks Async +- [bc52c793] Associate every registry lock with a Context. +- [054971ee] Wait until VM creation completes before adding to folder +- [35481467] govc: add library.update command +- [7403b470] Fix race in simulator's PropertyCollector +- [aadb2082] Add action to block WIP PRs +- [749c2239] govc: add session.ls -S flag +- [bc297330] [3ad0f415] Update Dockerfiles and .goreleaser.yml +- [082f9927] vcsim: add vsan simulator +- [8c38d56d] Add a stretched cluster conversion command. +- [408c531a] gofmt +- [e8a6b126] Update govc/flags/output.go +- [bf54a7c4] Add more badges +- [93245c1e] govc: add tree command +- [790f9ce6] govc: include sub task fault messages on failure +- [07e6e923] Use Github Actions Status Badges +- [d2a353ba] govc: remove device.boot -firmware default +- [4ed615f6] Add chainable RoundTripper support to endpoint clients +- [bab95d26] Add the vSAN stretched cluster reference. +- [6ff33db7] Fix events example +- [de6032e0] govc: add '-trace' and '-verbose' flags +- [7aae8dfb] Add support for calling vCenter for VLSM ExtendDisk and InflateDisk +- [7a276bf6] Add client test file for vslm package to validate register disk and cns create volume +- [dc29aa29] Fix performance.Manager.SampleByName truncation +- [18b53fd2] Added UpdateServiceMessage to Session Manager +- [63bb5c1e] govc: metric command enhancements and fixes +- [7844a8c2] govc: fix vm.migrate search index flags +- [7ab111bd] Drop clusterDistribution from vSAN 7.0 update and create spec elements +- [2c57a8a3] Use Github Actions +- [52631496] Marshal soapFaultError as JSON +- [f9e323a6] fix tab indentation +- [ae129ba0] add tests and implement HA Ready Condition +- [f34b3fa2] implement vSphere HA additional delay to VM HA overrides in govc +- [25970530] vcsim: fix Task.Info.Entity in RevertToSnapshot_Task +- [5dacf627] govc: fix cluster.usage Free field +- [0d155a61] Handling invalid reader size +- [b70542a5] Using progress reader in WriteFile +- [b7f9e034] use correct enum for vm restart priority +- [d3d49a36] Add support for snapshot size calculations +- [61bfa072] Use a dash to indicate empty address +- [f0a045ac] vcsim: set VirtualMachine.Config.CreateDate property +- [4d9a9000] vim25: fix race in TemporaryNetworkError retry func +- [2f14e4b2] ovf: add Config and ExtraConfig to VirtualHardwareSection +- [50328780] Add vSAN 7.0U1 release constant +- [886573de] Update .goreleaser.yml +- [1cdb3164] Change the address type to automatic +- [667a3791] Remove duplicate cns bindings from vsan directory +- [f71bcf25] govc: fix session curl when given a URL query +- [d92f41de] Update volume ACL spec to add delete field +- [c954c2a5] govc: validate license.remove +- [2a4f8c8a] Update ConfigureVolumeACLs bindings in cns types +- [3b25c3f1] govc: validate required library.clone NAME arg +- [344b7a30] govc: note 'disk.ls -R' in volume.rm help +- [8942055a] govc: add device.info examples to get disk UUID and vmdk +- [1b0af949] govc: fix vm.markasvm examples +- [543e52ea] govc-env --save default +- [0a5f2a99] Little fix for "govc-env --save without config name" +- [4a7a0b45] gen: require nokogiri 1.11.0 or higher +- [add8be5a] govc: fix incorrect DeviceID value in device.pci.add +- [e51eb2b9] vcsim: support EventFilterSpec.Time +- [1f4f5640] govc: add IPv6 support to vm.customize +- [8e45fa4a] vcsim: emit CustomizationSucceeded event from CustomizeVM +- [c000bd6e] vcsim: add DistributedVirtualSwitchManager +- [bcd5fa87] vcsim: set VirtualDisk backing UUID +- [ccdcbe89] vcsim: move product suffix in ServiceContent.About +- [393e7330] vcsim: use linked list for EventHistoryCollector +- [9c4dc1a1] vcsim: escape datastore name +- [9c2fe70f] vcsim: record/replay EnvironmentBrowser.QueryConfigOption +- [5fd7e264] vcsim: fix EventHistoryCollector fixes +- [40a2cf0b] Skip tests that require docker on TravisCI +- [00ee2911] toolbox: skip tests that require Linux +- [0b755a59] vcsim: switch bats tests from esx to vcsim env +- [c6d5264a] Updated projects to include VMware Event Broker Appliance +- [ae44a547] ExampleCollector_Retrieve: Add missing err return +- [38da87ff] examples: add NetworkReference.EthernetCardBackingInfo +- [3f1caf82] vcsim: fixes for PowerCLI Get-VirtualNetwork +- [041a98b8] Fix DvsNetworkRuleQualifier interface +- [44e05fe4] SHA-1 deprecated in 2011, sha256sum for releases + + +## [Release v0.24.2](https://github.com/vmware/govmomi/compare/v0.24.1...v0.24.2) + +> Release Date: 2021-10-14 + +### 🐞 Fix + +- [b18f06b5] avoid vNIC mapping in guest.TransferURL if URL.Host is an IP +- [5a2a8aba] avoid use of vNIC IP in guest.TransferURL if there are multiple + +### ⚠️ BREAKING + +### 📖 Commits + +- [b18f06b5] fix: avoid vNIC mapping in guest.TransferURL if URL.Host is an IP +- [5a2a8aba] fix: avoid use of vNIC IP in guest.TransferURL if there are multiple + + +## [Release v0.24.1](https://github.com/vmware/govmomi/compare/v0.24.0...v0.24.1) + +> Release Date: 2021-03-17 + +### 💡 Examples + +- [38da87ff] add NetworkReference.EthernetCardBackingInfo + +### 💫 `govc` (CLI) + +- [63bb5c1e] metric command enhancements and fixes +- [7844a8c2] fix vm.migrate search index flags +- [5dacf627] fix cluster.usage Free field +- [f71bcf25] fix session curl when given a URL query +- [c954c2a5] validate license.remove +- [3b25c3f1] validate required library.clone NAME arg +- [344b7a30] note 'disk.ls -R' in volume.rm help +- [8942055a] add device.info examples to get disk UUID and vmdk +- [1b0af949] fix vm.markasvm examples +- [add8be5a] fix incorrect DeviceID value in device.pci.add +- [1f4f5640] add IPv6 support to vm.customize + +### 💫 `vcsim` (Simulator) + +- [25970530] fix Task.Info.Entity in RevertToSnapshot_Task +- [f0a045ac] set VirtualMachine.Config.CreateDate property +- [e51eb2b9] support EventFilterSpec.Time +- [8e45fa4a] emit CustomizationSucceeded event from CustomizeVM +- [c000bd6e] add DistributedVirtualSwitchManager +- [bcd5fa87] set VirtualDisk backing UUID +- [ccdcbe89] move product suffix in ServiceContent.About +- [393e7330] use linked list for EventHistoryCollector +- [9c4dc1a1] escape datastore name +- [9c2fe70f] record/replay EnvironmentBrowser.QueryConfigOption +- [5fd7e264] fix EventHistoryCollector fixes +- [0b755a59] switch bats tests from esx to vcsim env +- [3f1caf82] fixes for PowerCLI Get-VirtualNetwork + +### ⚠️ BREAKING + +### 📖 Commits + +- [7a276bf6] Add client test file for vslm package to validate register disk and cns create volume +- [dc29aa29] Fix performance.Manager.SampleByName truncation +- [18b53fd2] Added UpdateServiceMessage to Session Manager +- [63bb5c1e] govc: metric command enhancements and fixes +- [7844a8c2] govc: fix vm.migrate search index flags +- [7ab111bd] Drop clusterDistribution from vSAN 7.0 update and create spec elements +- [52631496] Marshal soapFaultError as JSON +- [f9e323a6] fix tab indentation +- [ae129ba0] add tests and implement HA Ready Condition +- [f34b3fa2] implement vSphere HA additional delay to VM HA overrides in govc +- [25970530] vcsim: fix Task.Info.Entity in RevertToSnapshot_Task +- [5dacf627] govc: fix cluster.usage Free field +- [b7f9e034] use correct enum for vm restart priority +- [d3d49a36] Add support for snapshot size calculations +- [61bfa072] Use a dash to indicate empty address +- [f0a045ac] vcsim: set VirtualMachine.Config.CreateDate property +- [4d9a9000] vim25: fix race in TemporaryNetworkError retry func +- [2f14e4b2] ovf: add Config and ExtraConfig to VirtualHardwareSection +- [50328780] Add vSAN 7.0U1 release constant +- [886573de] Update .goreleaser.yml +- [1cdb3164] Change the address type to automatic +- [667a3791] Remove duplicate cns bindings from vsan directory +- [f71bcf25] govc: fix session curl when given a URL query +- [d92f41de] Update volume ACL spec to add delete field +- [c954c2a5] govc: validate license.remove +- [2a4f8c8a] Update ConfigureVolumeACLs bindings in cns types +- [3b25c3f1] govc: validate required library.clone NAME arg +- [344b7a30] govc: note 'disk.ls -R' in volume.rm help +- [8942055a] govc: add device.info examples to get disk UUID and vmdk +- [1b0af949] govc: fix vm.markasvm examples +- [543e52ea] govc-env --save default +- [0a5f2a99] Little fix for "govc-env --save without config name" +- [4a7a0b45] gen: require nokogiri 1.11.0 or higher +- [add8be5a] govc: fix incorrect DeviceID value in device.pci.add +- [e51eb2b9] vcsim: support EventFilterSpec.Time +- [1f4f5640] govc: add IPv6 support to vm.customize +- [8e45fa4a] vcsim: emit CustomizationSucceeded event from CustomizeVM +- [c000bd6e] vcsim: add DistributedVirtualSwitchManager +- [bcd5fa87] vcsim: set VirtualDisk backing UUID +- [ccdcbe89] vcsim: move product suffix in ServiceContent.About +- [393e7330] vcsim: use linked list for EventHistoryCollector +- [9c4dc1a1] vcsim: escape datastore name +- [9c2fe70f] vcsim: record/replay EnvironmentBrowser.QueryConfigOption +- [5fd7e264] vcsim: fix EventHistoryCollector fixes +- [40a2cf0b] Skip tests that require docker on TravisCI +- [00ee2911] toolbox: skip tests that require Linux +- [0b755a59] vcsim: switch bats tests from esx to vcsim env +- [c6d5264a] Updated projects to include VMware Event Broker Appliance +- [ae44a547] ExampleCollector_Retrieve: Add missing err return +- [38da87ff] examples: add NetworkReference.EthernetCardBackingInfo +- [3f1caf82] vcsim: fixes for PowerCLI Get-VirtualNetwork +- [041a98b8] Fix DvsNetworkRuleQualifier interface +- [44e05fe4] SHA-1 deprecated in 2011, sha256sum for releases + + +## [Release v0.24.0](https://github.com/vmware/govmomi/compare/v0.23.1...v0.24.0) + +> Release Date: 2020-12-21 + +### 💡 Examples + +- [7178588c] add Folder.CreateVM +- [b4f7243b] add ContainerView retrieve clusters +- [1d21fff9] use session.Cache +- [8af8cef6] add events +- [e153061f] fix simulator.RunContainer on MacOSX + +### 💫 `govc` (CLI) + +- [1ec59a7c] fix build.sh git tag injection +- [31c0836e] add cluster.usage command +- [79514c81] add volume.ls -ds option +- [5e57b3f6] add device.boot -firmware option +- [4d82f0ff] add dvs.portgroup.{add,change} '-auto-expand' flag +- [4a1d05ac] fix object.collect ContainerView updates +- [e84d0d18] document vm.disk.attach -link behavior +- [70a9ced4] fix vm.clone panic when target VM already exists +- [a97e6168] support sparse backing in vm.disk.change +- [3380cd30] add CNS volume ls and rm commands +- [f7170fd2] add find -p flag +- [b40cdd8a] add storage.policy commands +- [d0111d28] add vm.console -wss flag +- [86374ea2] support multi value flags in host.esxcli command +- [ebcfa3d4] add namespace.cluster.ls command + +### 💫 `vcsim` (Simulator) + +- [bf80efab] include stderr in log message when volume import fails +- [1f3fb17c] include stderr in log message when container fails to start +- [e1c4b06e] rewrite vmfs path from saved model +- [bcdfb298] QueryConfigOptionEx Spec is optional +- [73e1af55] support inventory updates in ContainerView +- [a76123b2] set VirtualDevice.Connectable default for removable devices +- [b195dd57] add AuthorizationManager methods +- [a71f6c77] set VirtualDisk backing option defaults +- [fbde3866] add CloneVApp_Task support +- [aae78223] fix ListView.Modify +- [9cca13ab] avoid ViewManager.ModifyListView race +- [156b1cb0] add ListView to race test +- [55f6f952] add mechanism for modeling methods +- [69942fe2] fix save/load property collection for VmwareDistributedVirtualSwitch +- [33121b87] Honoring the instance uuid provided in spec by caller ([#2052](https://github.com/vmware/govmomi/issues/2052)) + +### ⚠️ BREAKING + +### 📖 Commits + +- [1ec59a7c] govc: fix build.sh git tag injection +- [164b9217] Update docs for 0.24 release +- [bf80efab] vcsim: include stderr in log message when volume import fails +- [4080e177] Add batch APIs for multiple tags to object +- [31c0836e] govc: add cluster.usage command +- [7178588c] examples: add Folder.CreateVM +- [2b962f3f] Add test for vsan host config +- [165d7cb4] Add function to get vsan host config +- [79514c81] govc: add volume.ls -ds option +- [f7ff79df] Add Configure ACL go bindings +- [1f3fb17c] vcsim: include stderr in log message when container fails to start +- [3b83040a] Add wrappers for retrieving vsan properties +- [12e8969c] Use gofmt +- [6454dbd4] Add vSAN 7.0 API bindings +- [6a216a52] Add vSAN 7.0 API bindings +- [be15ad6c] Regenerate against vSphere 7.0U1 release +- [5e57b3f6] govc: add device.boot -firmware option +- [e1c4b06e] vcsim: rewrite vmfs path from saved model +- [26635452] Change CnsCreateVolume to return PlacementResult for static volume provisioning. Also add unit test for this case. +- [4d82f0ff] govc: add dvs.portgroup.{add,change} '-auto-expand' flag +- [bcdfb298] vcsim: QueryConfigOptionEx Spec is optional +- [8b194c23] Add Placement object in CNS CreateVolume response. Add corresponding test. +- [b085fc33] Use available ctx in enable cluster network lookup +- [f6f336ab] Cleanup some redundant code for cluster namespace enabling +- [d04f2b49] change negative one to rand neg int32 +- [f819befd] go binding for CNS RelocateVolume API +- [ed93ea7d] fix the goimports validation error +- [f402c0e1] support trunk mode port group +- [ff575977] change key default from -1 to rand neg int32 vsphere 7 introduced a key collision detection error when adding devices com.vmware.vim.vpxd.vmprov.duplicateDeviceKey which causes -1 keys to return an error of duplicate if you try and add two devices in the same AddDevice call +- [39acef43] Add option to disable secure cookies with non-TLS endpoints +- [ae19e30f] simulator: fix container vm example +- [73e1af55] vcsim: support inventory updates in ContainerView +- [593cd20d] Add namespace.cluster.disable cmd + formatting fixes +- [782ed95c] Add namespace.cluster.enable cmd to govc +- [e7403032] Make ListStorageProfiles public -> for enabling clusters in govc +- [53965796] Adds support for enabling cluster namespaces via API +- [4a1d05ac] govc: fix object.collect ContainerView updates +- [e84d0d18] govc: document vm.disk.attach -link behavior +- [a76123b2] vcsim: set VirtualDevice.Connectable default for removable devices +- [b4f7243b] examples: add ContainerView retrieve clusters +- [b195dd57] vcsim: add AuthorizationManager methods +- [a71f6c77] vcsim: set VirtualDisk backing option defaults +- [1d21fff9] examples: use session.Cache +- [8af8cef6] examples: add events +- [3e2a8071] Add ClusterDistribution field for CNS telemetry and Drop optional fields not known to the prior releases +- [4acfb726] Fix for fatal error: concurrent map iteration and map write +- [01610887] Adding VsanQueryObjectIdentities and QueryVsanObjects +- [fbde3866] vcsim: add CloneVApp_Task support +- [70a9ced4] govc: fix vm.clone panic when target VM already exists +- [a97e6168] govc: support sparse backing in vm.disk.change +- [3380cd30] govc: add CNS volume ls and rm commands +- [f9d7bfdf] sts: fix SignRequest bodyhash for non-empty request body +- [7b4e997b] vapi: add WCP support bundle bindings +- [aae78223] vcsim: fix ListView.Modify +- [0e4bce43] Add AuthorizationManager.HasUserPrivilegeOnEntities wrapper +- [81207eab] vim25/xml: sync with Go 1.15 encoding/xml +- [f7170fd2] govc: add find -p flag +- [d49123c9] Add internal.InventoryPath helper +- [b40cdd8a] govc: add storage.policy commands +- [0c5cdd5d] add / remove pci passthrough device for one VM +- [d0111d28] govc: add vm.console -wss flag +- [94bc8497] Add sms generated types and methods +- [e153061f] examples: fix simulator.RunContainer on MacOSX +- [99fe9954] finder: simplify direct use of InventoryPath func +- [3760bd6c] Added Instant Clone feature Resolves: [#1392](https://github.com/vmware/govmomi/issues/1392) +- [86374ea2] govc: support multi value flags in host.esxcli command +- [9cca13ab] vcsim: avoid ViewManager.ModifyListView race +- [156b1cb0] vcsim: add ListView to race test +- [f903d5da] Add ExtendDisk and InflateDisk wrappers to vlsm/object_manager +- [073cc310] Add AttachDisk and DetachDisk wrappers for the virtualMachine object. +- [a0c7e829] vapi: add tags.Manager.GetAttachedTagsOnObjects example +- [378a24c4] Vsan Performance Data Collection API ([#2021](https://github.com/vmware/govmomi/issues/2021)) +- [55f6f952] vcsim: add mechanism for modeling methods +- [69942fe2] vcsim: fix save/load property collection for VmwareDistributedVirtualSwitch +- [fe3becfa] bats: test fixes for running on MacOSX +- [0422a070] Merge branch 'master' into pc/HardwareInfoNotReplicatingInCloning +- [9f12aae4] vapi: add Content Library example +- [33121b87] vcsim: Honoring the instance uuid provided in spec by caller ([#2052](https://github.com/vmware/govmomi/issues/2052)) +- [9a07942b] Setting hardware properties in clone VM spec from template VM +- [ebcfa3d4] govc: add namespace.cluster.ls command +- [11d45e54] vapi: add namespace management client and vcsim support +- [cdc44d5e] vapi: add helper support "/api" endpoint + + +## [Release v0.23.1](https://github.com/vmware/govmomi/compare/v0.23.0...v0.23.1) + +> Release Date: 2020-07-02 + +### 💡 Examples + +- [0bbb6a7d] add property.Collector.Retrieve example + +### 💫 `vcsim` (Simulator) + +- [0697d33f] add HostNetworkSystem.QueryNetworkHint +- [d7f4bba6] use HostNetworkSystem wrapper with -load flag +- [916b12e6] set HostSystem IP in cluster AddHost_Task +- [e63ec002] add PbmQueryAssociatedProfile method + +### ⚠️ BREAKING + +### 📖 Commits + +- [b7add48c] check if config isn't nil before returning an uuid +- [12955a6c] added support for returning array of BaseCnsVolumeOperationResult for QueryVolumeInfo API +- [0697d33f] vcsim: add HostNetworkSystem.QueryNetworkHint +- [a5c9e1f0] Merge branch 'master' into master +- [c14e3bc5] adding in link to OPS +- [d7f4bba6] vcsim: use HostNetworkSystem wrapper with -load flag +- [916b12e6] vcsim: set HostSystem IP in cluster AddHost_Task +- [e63ec002] vcsim: add PbmQueryAssociatedProfile method +- [0bbb6a7d] examples: add property.Collector.Retrieve example + + +## [Release v0.23.0](https://github.com/vmware/govmomi/compare/v0.22.2...v0.23.0) + +> Release Date: 2020-06-11 + +### 💡 Examples + +- [0e4b487e] Fixed error is not logging in example.go +- [c17eb769] add ContainerView.Find + +### 💫 `govc` (CLI) + +- [10c22fd1] support raw object references in import.ova NetworkMapping +- [4f19eb6d] ipath search flag does not require a Datacenter +- [414c548d] support find with -customValue filter +- [0bf0e761] support VirtualApp with -pool flag +- [f1ae45f5] add -version flag to datastore.create command +- [43e4f8c2] add session.login -X flag +- [70b7e1b4] vm.clone ResourcePool is optional when -cluster is specified +- [2c5ff385] add REST support for session.login -cookie flag +- [7d66cf9a] fix host.info CPU usage +- [244a8369] add session.ls -r flag +- [6c68ccf2] add a VM template clone example +- [bb6ae4ab] ignore ManagedObjectNotFound errors in 'find' command +- [210541fe] remove ClientFlag.WithRestClient +- [75e9e80d] do not try to start a VM template +- [667e6fbe] add guest directory upload/download examples +- [167f5d83] add vm.change -uuid flag +- [bcd06cee] enable library.checkout and library.checkin by default +- [6f087ded] avoid truncation in object.collect +- [e9bb4772] add import.spec support for remote URLs +- [692c1008] support optional compute.policy.ls argument +- [814e4e5c] add vm.change '-memory-pin' flag +- [56e878a5] support nested groups in sso.group.update +- [84346733] add content library helpers +- [0ccfd912] add cluster.group.ls -l flag +- [ae84c494] use OutputFlag for import.spec +- [2dda4daa] add library.clone -ovf flag +- [519d302d] fix doc for -g flag (guest id) choices +- [e582cbd1] add object.collect -o flag +- [d2e6b7df] output formatting enhancements +- [e64c2423] add find -l flag +- [4db4430c] save sessions using sha256 ID + +### 💫 `vcsim` (Simulator) + +- [c3fe4f84] CreateSnapshotTask now returns moref in result +- [b0af443c] add lookup ServiceRegistration example +- [34734712] add AuthorizationManager.HasPrivilegeOnEntities +- [228e0a8f] traverse configManager.datastoreSystem in object.save +- [8acac02a] traverse configManager.virtualNicManager in object.save +- [8a4ab564] traverse configManager.networkSystem in object.save +- [4b8a5988] add extraConfigAlias table +- [a0fe825a] add EventHistoryCollector.ResetCollector implementation +- [558747b3] fixes for PowerCLI +- [9ae04495] apply ExtraConfig after devices +- [4286d7cd] add another test/example for DVS host member validation +- [7e24bfcb] validate DVS membership +- [853656fd] fix flaky library subscriber test +- [7426e2fd] avoid panic if ovf:capacityAllocationUnits is not present +- [55599668] support QueryConfigOptionEx GuestId param +- [67d593cc] VM templates do not have a ResourcePool +- [469e11b9] validate session key in TerminateSession method +- [88d298ff] unique MAC address for VM NICs +- [c4f820dd] create vmdk directory if needed +- [488205f0] support VMs with the same name +- [68349a27] support Folder in RelocateVM spec +- [ab1298d5] add guest operations support +- [7ffb9255] add HostStorageSystem support +- [77b31b84] avoid possible panic in UnregisterVM_Task +- [617c18e7] support tags with the same name +- [dfcf9437] add docs on generated inventory names +- [4cfc2905] add support for NSX backed networks + +### ⚠️ BREAKING + +### 📖 Commits + +- [b639ab4c] Update docs for 0.23 release +- [be7742f2] vapi: use header authentication in file Upload/Download +- [50846878] provided examples for vm.clone and host.esxcli +- [aa97c4d3] Add appliance log forwarding config handler and govc verb ([#1994](https://github.com/vmware/govmomi/issues/1994)) +- [7cdad997] Finder: support DistributedVirtualSwitch traversal +- [10c22fd1] govc: support raw object references in import.ova NetworkMapping +- [c3fe4f84] vcsim: CreateSnapshotTask now returns moref in result +- [4f19eb6d] govc: ipath search flag does not require a Datacenter +- [b0af443c] vcsim: add lookup ServiceRegistration example +- [84f1b733] simulator: fix handling of nil Reference in container walk +- [b5b434b0] Adding sunProfileName in pbm.CapabilityProfileCreateSpec +- [2111324a] providing examples for govc guest.run +- [0eef3b29] Bump to vSphere version 7 +- [b277903e] go binding for CNS QueryVolumeInfo API +- [a048ea52] Move simulator lookupservice registration into ServiceInstance +- [30f1a71a] modify markdown link at simulator.Model +- [7881f541] Add REST session keep alive support +- [3aa9aaba] vapi: sync access to rest.Client.SessionID +- [0a53ac4b] simulator: refactor folder children operations +- [b9152f85] simulator: relax ResourcePool constraint for createVM operation +- [70e9d821] simulator: relax typing condition on RP parent +- [502b7efa] simulator: relax ViewManager typing constraints +- [634fdde1] simulator: remove data race in VM creation flow +- [6eda0169] simulator: protect datastore freespace updates against data races +- [414c548d] govc: support find with -customValue filter +- [487ca0d6] Add logic to return default HealthStatus in CnsCreateVolume. +- [0bf0e761] govc: support VirtualApp with -pool flag +- [f1ae45f5] govc: add -version flag to datastore.create command +- [d0751307] Add support for attach-tag-to-multiple-objects +- [5682b1f2] simulator: relax excessive type assertions in SearchIndex +- [39a4da90] Modify parenthesis for markdown link +- [34734712] vcsim: add AuthorizationManager.HasPrivilegeOnEntities +- [92d464b9] 1. Add retry for CNS Create API with backing disk url 2. Fix binding for CnsAlreadyRegisteredFault +- [235582fe] Add sample test for Create CNS API using backing disk Url path +- [b187863a] 1. Add BackingDiskUrlPath and CnsAlreadyFault go bindings to CNS APIs 2. Update CreateVolume CNS Util to include BackingDiskUrlPath +- [409279fa] Add GetProfileNameByID functionality to PBM +- [228e0a8f] vcsim: traverse configManager.datastoreSystem in object.save +- [8acac02a] vcsim: traverse configManager.virtualNicManager in object.save +- [8a4ab564] vcsim: traverse configManager.networkSystem in object.save +- [43e4f8c2] govc: add session.login -X flag +- [70b7e1b4] govc: vm.clone ResourcePool is optional when -cluster is specified +- [2c5ff385] govc: add REST support for session.login -cookie flag +- [6ccaf303] Add guest.FileManager.TransferURL test +- [03c7611e] Avoid possible nil pointer dereference in guest TransferURL +- [44a78f96] Fix delegated Holder-of-Key token signature +- [11b2aa1a] Update to vSphere 7 APIs +- [4b8a5988] vcsim: add extraConfigAlias table +- [a0fe825a] vcsim: add EventHistoryCollector.ResetCollector implementation +- [558747b3] vcsim: fixes for PowerCLI +- [9ae04495] vcsim: apply ExtraConfig after devices +- [7d66cf9a] govc: fix host.info CPU usage +- [4286d7cd] vcsim: add another test/example for DVS host member validation +- [515621d1] Revert to using sha1 for session cache file names +- [f103a87a] Default to separate session cache directories +- [7e24bfcb] vcsim: validate DVS membership +- [244a8369] govc: add session.ls -r flag +- [6c68ccf2] govc: add a VM template clone example +- [bb6ae4ab] govc: ignore ManagedObjectNotFound errors in 'find' command +- [853656fd] vcsim: fix flaky library subscriber test +- [571f64e7] Fix existing goimport issue +- [7426e2fd] vcsim: avoid panic if ovf:capacityAllocationUnits is not present +- [9e57f983] Add non-null HostLicensableResourceInfo to HostSystem +- [210541fe] govc: remove ClientFlag.WithRestClient +- [75e9e80d] govc: do not try to start a VM template +- [d9220e5d] simulator: add interface for VirtualDiskManager +- [55599668] vcsim: support QueryConfigOptionEx GuestId param +- [67d593cc] vcsim: VM templates do not have a ResourcePool +- [667e6fbe] govc: add guest directory upload/download examples +- [167f5d83] govc: add vm.change -uuid flag +- [bcd06cee] govc: enable library.checkout and library.checkin by default +- [9d4faa6d] Refactor govc session persistence into session/cache package +- [6f087ded] govc: avoid truncation in object.collect +- [7a1fef65] Remove Task from function names in Task struct receiver methods +- [dd839655] Add SetTaskState SetTaskDescription UpdateProgress to object package +- [469e11b9] vcsim: validate session key in TerminateSession method +- [af41ae09] Revert compute policy support +- [ad612b3e] Fix the types of errors returned from VSLM tasks to be their originl vim faults rather than just wrappers of localized error msg +- [9e82230f] Remove extra err check +- [e9bb4772] govc: add import.spec support for remote URLs +- [273aaf71] skip tests when env is not set +- [159c423c] removing usage of spew package +- [76caec95] vapi: prefer header authn to cookie authn +- [6c04cfa0] Dropping fields in entity metadata for 6.7u3 +- [8d15081f] using right version and namespace from sdk/vsanServiceVersions.xml for cns client. making cns/client.go backward compatible to vsan67u3 by dropping unknown elements +- [8dfb29f5] Add nil check for taskInfo result before typecasting CnsVolumeOperationBatchResult +- [d68bbf9b] fixing CnsFault go binding +- [5482bd07] syncing vmodl changes +- [3bcace84] fixing go binding for CnsVolumeOperationResult and CnsFault +- [3c756cbd] Fixing govmomi binding for CNS as per latest VMODL for CnsVsanFileShareBackingDetails. Also fixed cns/client_test.go accordingly. +- [4254df70] Adding new API to get cluster configuration +- [0eacb4ed] removing space before omitempty tag +- [59ce7e4a] Resolve bug in Simulator regarding BackingObjectDetails +- [6ad7e87d] Change the backingObjectDetails attribute to point to interface BaseCnsBackingObjectDetails +- [601f1ded] Add resize support +- [56049aa4] Updating go binding for vsan fileshare vmodl updates +- [af798c01] Add CnsQuerySelectionNameType and CnsKubernetesEntityType back +- [af2723fd] Add bindings for vSANFS and extend CNS bindings to support file volume +- [4e7b9b00] update taskClientVersion for vsphere 7.0 +- [692c1008] govc: support optional compute.policy.ls argument +- [a7d4a77d] Modified return type for Get policy +- [4007484e] Compute Policy support +- [88d298ff] vcsim: unique MAC address for VM NICs +- [814e4e5c] govc: add vm.change '-memory-pin' flag +- [de8bcf25] reset all for recursive calls fix format error +- [57efe91f] Fixed ContainerView.RetrieveWithFilter fetch all specs if empty list of properties given +- [5af5ac8d] Avoid possible panic in Filter.MatchProperty +- [85889777] Add vAPI create binding for compute policy +- [56e878a5] govc: support nested groups in sso.group.update +- [6f46ef8a] Added prefix toggle parameter to govc export.ovf +- [6d3196e4] Disk mode should override default value in vm.disk.attach +- [4be7a425] Replaced ClassOvfParams with ClassDeploymentOptionParams +- [c4f820dd] vcsim: create vmdk directory if needed +- [1ab6fe09] Add Content Library subscriptions support +- [488205f0] vcsim: support VMs with the same name +- [68349a27] vcsim: support Folder in RelocateVM spec +- [6a6a7875] Update CONTRIBUTING to have more info about running CI tests, checks. +- [a73c0d4f] Expose Soap client default transport (a.k.a. its http client default transport) +- [84346733] govc: add content library helpers +- [a225a002] build(deps): bump nokogiri from 1.10.4 to 1.10.8 in /gen +- [b4395d65] Avoid ServiceContent requirement in lookup.NewClient +- [c1e828cb] fix blog links +- [863430ba] toolbox: bump test VM memory for current CoreOS release +- [0ccfd912] govc: add cluster.group.ls -l flag +- [1af6ec1d] Add Namespace support to UseServiceVersion +- [ab1298d5] vcsim: add guest operations support +- [0e4b487e] examples: Fixed error is not logging in example.go +- [f36e13fc] Add Content Library item copy support +- [7ffb9255] vcsim: add HostStorageSystem support +- [ae84c494] govc: use OutputFlag for import.spec +- [2dda4daa] govc: add library.clone -ovf flag +- [77b31b84] vcsim: avoid possible panic in UnregisterVM_Task +- [519d302d] govc: fix doc for -g flag (guest id) choices +- [617c18e7] vcsim: support tags with the same name +- [e582cbd1] govc: add object.collect -o flag +- [0c6eafc1] Apply gomvomi vim25/xml changes +- [4da54375] Simplify ObjectName method +- [d2e6b7df] govc: output formatting enhancements +- [dfcf9437] vcsim: add docs on generated inventory names +- [e64c2423] govc: add find -l flag +- [4db4430c] govc: save sessions using sha256 ID +- [4cfc2905] vcsim: add support for NSX backed networks +- [c17eb769] examples: add ContainerView.Find +- [36056ae6] Import golang/go/src/encoding/xml v1.13.6 +- [346cf59a] Avoid encoding/xml import +- [9cbe57db] fix simulator disk manager fault message. +- [7f685c23] Add permissions for NoCryptoAdmin + + +## [Release v0.22.2](https://github.com/vmware/govmomi/compare/v0.22.1...v0.22.2) + +> Release Date: 2020-02-13 + +### ⚠️ BREAKING + +### 📖 Commits + +- [e7df0c11] Avoid ServiceContent requirement in lookup.NewClient + + +## [Release v0.22.1](https://github.com/vmware/govmomi/compare/v0.22.0...v0.22.1) + +> Release Date: 2020-01-13 + +### ⚠️ BREAKING + +### 📖 Commits + +- [da368950] Release version 0.22.1 +- [a62b12cf] Fix AttributeValue.C14N for 6.7u3 +- [c3d102b1] Add finder example for MultipleFoundError +- [802e5899] vapi: add CreateTag example +- [15630b90] vapi: Add cluster modules client and simulator + + +## [Release v0.22.0](https://github.com/vmware/govmomi/compare/v0.21.0...v0.22.0) + +> Release Date: 2020-01-10 + +### 💡 Examples + +- [72b1cd92] output VM names in performance example +- [f4b3cda7] add Common.Rename +- [dab4ab0d] add VirtualMachine.Customize +- [1828eee9] add VirtualMachine.CreateSnapshot +- [6ff7040e] fix flag parsing +- [cad9a8e2] add ExampleVirtualMachine_Reconfigure + +### 💫 `govc` (CLI) + +- [aed39212] guest -i flag only applies to ProcessManager +- [704b335f] add 5.0 to vm.create hardware version map +- [965109ae] guest.run improvements +- [ee28fcfd] add vm.customize multiple IP support +- [68b3ea9f] fix library.info output formatting +- [5bb7f391] add optional library.info details +- [d8ac7e51] handle xsd:string responses +- [31d3e357] add library.info details +- [182c84a3] fixup tasks formatting +- [08fb2b02] remove guest.run toolbox dependency +- [a727283f] default to simple esxcli format when hints fields is empty +- [204af3c5] add datacenter create/delete examples +- [f6c57ee7] fix vm.create doc regarding -on flag +- [8debfcc3] add device.boot -secure flag +- [2bb2a6ed] add doc on vm.info -r flag +- [e50368c6] avoid env for -cluster placement flag +- [f16eb276] add default library.create thumbprint +- [d8325f34] add thumbprint flag to library.create +- [0bad2bc2] add vm.power doc +- [45d322ea] support vm.customize without a managed spec +- [0a058e0f] fixup usage suggestions +- [3185f7bc] add vm.customize command +- [1b159e27] fix datacenter.info against nested folders +- [149ba7ad] add vm.change -latency flag +- [c35a532d] validate moref argument +- [3fb02b52] add guest.df command + +### 💫 `vcsim` (Simulator) + +- [198b97ca] propagate VirtualMachineCloneSpec.Template +- [168a6a04] add -trace-file option +- [32eeeb24] Get IP address on non-default container network +- [1427d581] avoid possible panic in VirtualMachine.Destroy_Task +- [067d58be] automatically set Context.Caller +- [9e8e9a5a] remove container volumes +- [6cc814b8] bind mount BIOS UUID DMI files +- [9aec1386] validate VirtualDisk UnitNumber +- [d7e43b4e] add Floppy Drive support to OVF manager +- [8646dace] properly initialize portgroup portKeys field +- [286bd5e9] add vim25 client helper to vapi simulator +- [c3163247] use VMX_ prefix for guestinfo env vars +- [a3a09c04] don't allow duplicate names for Folder/StoragePod +- [a0a2296e] pass guestinfo vars as env vars to container vms +- [903fe182] add CustomizationSpecManager support +- [eda6bf3b] simplify container vm arguments input +- [0ce9b0a1] update docs +- [7755fbda] add record/playback functionality +- [fe000674] add VirtualMachine.Rename_Task support +- [d87cd5ac] add feature examples +- [2cc33fa8] Ensure that extraConfig from clone spec is added to VM being cloned +- [70ad060e] use exported response helpers in vapi/simulator +- [1e7aa6c2] avoid ViewManager.ViewList +- [9b0db1c2] avoid race in ViewManager +- [28b5fc6c] use TLS in simulator.Run +- [f962095f] rename Example to Run +- [43d69860] add endpoint registration mechanism +- [c183577b] add PlaceVm support ([#1589](https://github.com/vmware/govmomi/issues/1589)) +- [b17f3a51] DefaultDatastoreID is optional in library deploy + +### ⏮ Reverts + +- [7914609d] gen: retain omitempty field tag with int pointer types + +### ⚠️ BREAKING + +### 📖 Commits + +- [317707be] Update docs for 0.22 release +- [aed39212] govc: guest -i flag only applies to ProcessManager +- [22308123] Clarify DVS EthernetCardBackingInfo error message +- [a1c98f14] Add Content Library synchronization support +- [704b335f] govc: add 5.0 to vm.create hardware version map +- [4e907d99] Clarify System.Read privilege requirement for PortGroup backing +- [554d9284] Fix guest.FileManager.TransferURL cache +- [9b8da88a] Remove toolbox specific guest run implementation +- [965109ae] govc: guest.run improvements +- [ee28fcfd] govc: add vm.customize multiple IP support +- [40001828] Add OVF properties to library deploy ([#1755](https://github.com/vmware/govmomi/issues/1755)) +- [68b3ea9f] govc: fix library.info output formatting +- [198b97ca] vcsim: propagate VirtualMachineCloneSpec.Template +- [5bb7f391] govc: add optional library.info details +- [2509e907] Added the missing RetrieveSnapshotDetails API in VSLM ([#1763](https://github.com/vmware/govmomi/issues/1763)) +- [d8ac7e51] govc: handle xsd:string responses +- [45b3685d] Add library ItemType constants +- [f3e2c3ce] Add retry support for HTTP status codes +- [31d3e357] govc: add library.info details +- [182c84a3] govc: fixup tasks formatting +- [08fb2b02] govc: remove guest.run toolbox dependency +- [b10bcbf3] VSLM: fixed the missing param in the QueryChangedDiskArea API impl +- [168a6a04] vcsim: add -trace-file option +- [72b1cd92] examples: output VM names in performance example +- [32eeeb24] vcsim: Get IP address on non-default container network +- [f9f69237] Move to cs.identity service type for sso admin endpoint +- [1427d581] vcsim: avoid possible panic in VirtualMachine.Destroy_Task +- [067d58be] vcsim: automatically set Context.Caller +- [a727283f] govc: default to simple esxcli format when hints fields is empty +- [08adb5d6] Move to cs.identity service type for sts endpoint +- [9e8e9a5a] vcsim: remove container volumes +- [6cc814b8] vcsim: bind mount BIOS UUID DMI files +- [e793289c] Content Library: add CheckOuts support +- [66c9b10c] Content Library: VM Template support +- [f4b3cda7] examples: add Common.Rename +- [19a726f7] Pass vm.Config.Uuid into the "VM" container via an env var +- [204af3c5] govc: add datacenter create/delete examples +- [dab4ab0d] examples: add VirtualMachine.Customize +- [f6c57ee7] govc: fix vm.create doc regarding -on flag +- [8debfcc3] govc: add device.boot -secure flag +- [9aec1386] vcsim: validate VirtualDisk UnitNumber +- [7914609d] Revert "gen: retain omitempty field tag with int pointer types" +- [9b2c5cc6] Add CustomizationSpecManager.Info method and example +- [d7e43b4e] vcsim: add Floppy Drive support to OVF manager +- [0bf21ec2] Implement some missing methods ("*All*" variants) on SearchIndex MOB +- [2bb2a6ed] govc: add doc on vm.info -r flag +- [8646dace] vcsim: properly initialize portgroup portKeys field +- [e50368c6] govc: avoid env for -cluster placement flag +- [91b1e0a7] Add ability to set DVS discovery protocol on create and change +- [1e130141] Move to Go 1.13 +- [f16eb276] govc: add default library.create thumbprint +- [d8325f34] govc: add thumbprint flag to library.create +- [62c20113] Fix hostsystem ManagementIPs call +- [c4a3908f] Update DVS change to use finder.Network for a single object +- [ee6fe09d] Fix usage instructions +- [5e6f5e3f] gen: retain omitempty field tag with int pointer types +- [286bd5e9] vcsim: add vim25 client helper to vapi simulator +- [841386f1] Add ability to change a vnic on a host +- [391dd80b] Add ability to change the MTU on a DVS that has already been created +- [26a45d61] Change MTU param to use flags.NewInt32 as the type +- [dbcfc3a8] Add MTU flag for DVS creation +- [0399353f] Generate pointer type for ResourceReductionToToleratePercent +- [3f6b8ef5] Add nil checks for all HostConfigManager references +- [c3163247] vcsim: use VMX_ prefix for guestinfo env vars +- [5381f171] Add option to follow all struct fields in mo.References +- [04e4835c] Refactor session KeepAlive tests to use vcsim +- [7391c241] Avoid possible deadlock in KeepAliveHandler +- [41422ea4] build(deps): bump nokogiri from 1.6.3.1 to 1.10.4 in /gen +- [a3a09c04] vcsim: don't allow duplicate names for Folder/StoragePod +- [4c72d2e9] Add a method to update ports on a distributed virtual switch +- [0bad2bc2] govc: add vm.power doc +- [45d322ea] govc: support vm.customize without a managed spec +- [0a058e0f] govc: fixup usage suggestions +- [a0a2296e] vcsim: pass guestinfo vars as env vars to container vms +- [903fe182] vcsim: add CustomizationSpecManager support +- [eda6bf3b] vcsim: simplify container vm arguments input +- [0ce9b0a1] vcsim: update docs +- [c538d867] adding managed obj type to table +- [3185f7bc] govc: add vm.customize command +- [b2a7b47e] Include object.save directory in output +- [e8281f87] Initial support for hybrid Model.Load +- [7755fbda] vcsim: add record/playback functionality +- [8a3fa4f2] set stable vsan client version +- [9eaac5cb] Avoid empty principal in HoK token request +- [4a8da68d] Allow sending multiple characters through -c and name the keys +- [3e3d3515] add simple command list filter +- [fe000674] vcsim: add VirtualMachine.Rename_Task support +- [9166bbdb] support two tags with the same name +- [344653c1] added log type and password scrubber +- [d87cd5ac] vcsim: add feature examples +- [30fc2225] Report errors when cdrom.insert fails +- [a94f2d3a] vslm: fix to throw errors on tasks that are completed with error state +- [37054f03] added IsTemplate vm helper +- [d7aeb628] Fix object.collect with moref argument +- [0765aa63] add GetInventoryPath to NetworkReference interface +- [9fb975b0] Fix description of vm.keystrokes +- [234aaf53] vapi: support DeleteLibrary with subscribed libraries +- [2cc33fa8] vcsim: Ensure that extraConfig from clone spec is added to VM being cloned +- [70ad060e] vcsim: use exported response helpers in vapi/simulator +- [b069efc0] vapi: refactor for external API implementations +- [1e7aa6c2] vcsim: avoid ViewManager.ViewList +- [9b0db1c2] vcsim: avoid race in ViewManager +- [bd298f43] a failing testcase that triggers with -race test +- [03422dd2] vapi: expand internal path constants +- [d296a5f8] Support HoK tokens with Interactive Users +- [c6226542] Fix error check in session.Secret +- [28b5fc6c] vcsim: use TLS in simulator.Run +- [f9b4bb05] Replace LoadRetrievePropertiesResponse with LoadObjectContent +- [d84679eb] Add VirtualHardwareSection.StorageItem +- [a23a5cb1] Check whether there's a NIC before updating guest.ipAddress +- [8a069c27] Add interactiveSession flag +- [25526b21] vm.keystrokes -s (Allow spaces) +- [1828eee9] examples: add VirtualMachine.CreateSnapshot +- [ca3763e7] vapi: return info with current session query +- [f962095f] vcsim: rename Example to Run +- [43d69860] vcsim: add endpoint registration mechanism +- [1b159e27] govc: fix datacenter.info against nested folders +- [c183577b] vcsim: add PlaceVm support ([#1589](https://github.com/vmware/govmomi/issues/1589)) +- [3e71d6be] Add ResourcePool.Owner method +- [b17f3a51] vcsim: DefaultDatastoreID is optional in library deploy +- [68980704] Update generated code to vSphere 6.7u3 +- [7416741c] Add VirtualMachine.QueryChangedDiskAreas(). +- [8ef87890] Content library: support library ID in Finder +- [e373feb8] Add option to propagate MissingSet faults in property.WaitForUpdates +- [6ff7040e] examples: fix flag parsing +- [149ba7ad] govc: add vm.change -latency flag +- [c35a532d] govc: validate moref argument +- [54df157b] Add content library subscription support +- [b86466b7] Fix deadlock for keep alive handlers that attempt log in +- [9ad64557] CNS go bindings +- [9de3b854] Add simulator.Model.Run example +- [4285b614] Include url in Client.Download error +- [caf0b6b3] vcsa: update to 6.7 U3 +- [7ac56b64] Update vcsim Readme.md +- [48ef35df] Update README.md +- [a40837d8] Use gnu xargs in bats tests on Darwin +- [51ad97e1] Add FetchCapabilityMetadata method to Pbm client +- [d124bece] Add v4 option to VirtualMachine.WaitForIP +- [a5a429c0] Add support for the cis session get method +- [4513735f] Don't limit library.Finder to local libraries +- [cad9a8e2] examples: add ExampleVirtualMachine_Reconfigure +- [3fb02b52] govc: add guest.df command + + +## [Release v0.21.0](https://github.com/vmware/govmomi/compare/v0.20.3...v0.21.0) + +> Release Date: 2019-07-24 + +### 💡 Examples + +- [9495f0d8] add CustomFieldManager.Set + +### 💫 `govc` (CLI) + +- [fa755779] support library paths in tags.attach commands +- [2ddfb86b] add datastore.info -H flag +- [b3adfff2] add sso.group commands +- [b5372b0c] host.vnic.info -json support +- [4c41c167] add context to LoadX509KeyPair error +- [910dac72] add vm.change hot-add options +- [746c314e] change logs.download -default=false +- [05f946d4] increase guest.ps -X poll interval +- [cc10a075] add -options support to library.deploy +- [fe372923] rename vcenter.deploy to library.deploy +- [436d7a04] move library.item.update commands to library.session +- [e6514757] consolidate library commands +- [f8249ded] export Archive Path field +- [d2ab2782] add vm.change vpmc-enabled flag +- [e7b801c6] fix vm.change against templates +- [8a856429] fix option.set for int32 type values +- [81391309] add datastore.maintenance.{enter,exit} commands +- [18cb9142] FCD workarounds +- [665affe5] add datastore.cluster.info Description +- [7b7f2013] add permission.remove -f flag + +### 💫 `vcsim` (Simulator) + +- [774f3800] add support to override credentials +- [ecd7312b] fix host uuid +- [c25c41c1] use stable UUIDs for inventory objects +- [1345eeb8] Press any key to exit +- [ee14bd3d] Update NetworkInfo.Portgroup in simulator +- [5b5eaa70] remove httptest.serve flag +- [20c1873e] add library.deploy support +- [0b1ad552] add ovf manager +- [6684016f] fork httptest server package +- [48c1e0a5] add content library support +- [8543ea4f] set guest.toolsRunningStatus property + +### ⚠️ BREAKING + +### 📖 Commits + +- [a0fef816] Update docs for 0.21 release +- [a38f6e87] Content library related cleanups +- [e4024e9c] Fix library AddLibraryItemFileFromURI fingerprint +- [fa755779] govc: support library paths in tags.attach commands +- [5e8cb495] Fixed type bug in global_object_manager Task.QueryResult +- [4a67dc73] govcsim: Support Default UplinkTeamingPolicy in DVSPG +- [9da2362d] Added missing field in VslmExtendDisk_Task in ExtendDisk method +- [91377d77] Add Juju to projects using govmomi +- [f9026a84] VSLM FCD Global Object Manager client for 6.7U2+ +- [9495f0d8] examples: add CustomFieldManager.Set +- [bb170705] govcsim: Create datastore as accessible +- [35d0b7d3] Set the InventoryPath of the folder object in DefaultFolder ([#1515](https://github.com/vmware/govmomi/issues/1515)) +- [2d13a357] Add govmomi performance example +- [2ddfb86b] govc: add datastore.info -H flag +- [55da29e5] govcsim: Set datastore status as normal +- [600e9f7c] Add various govmomi client examples +- [5cccd732] Add http source support to library.import +- [99dd5947] Goreleaser update for multiple archives +- [b3adfff2] govc: add sso.group commands +- [5889d091] tags API: add methods for association of multiple tags/objects +- [b5372b0c] govc: host.vnic.info -json support +- [9b7688e0] Add method that sets vim version to the endpoint service version +- [fe3488f5] Fix tls config in soap.NewServiceClient +- [4c41c167] govc: add context to LoadX509KeyPair error +- [d7430825] Support external PSC lookup service +- [774f3800] vcsim: add support to override credentials +- [47c9c070] Fix HostNetworkSystem.QueryNetworkHint return value +- [910dac72] govc: add vm.change hot-add options +- [4606125e] Fix json request tracing +- [746c314e] govc: change logs.download -default=false +- [05f946d4] govc: increase guest.ps -X poll interval +- [77cb9df5] Add library export support +- [cc10a075] govc: add -options support to library.deploy +- [ecd7312b] vcsim: fix host uuid +- [c25c41c1] vcsim: use stable UUIDs for inventory objects +- [322d9629] Fix pbm field type lookup +- [1345eeb8] vcsim: Press any key to exit +- [a4f58ac6] Update examples to use examples.Run method +- [a31db862] Add permanager example +- [384b1b95] Fix port signature in REST endpoint token auth +- [c222666f] Default to running against vcsim in examples +- [199e737b] Add generated vslm types and methods +- [ee14bd3d] vcsim: Update NetworkInfo.Portgroup in simulator +- [dc631a2d] Format import statement +- [f133c9e9] Fix paths in vsan/methods +- [d8e7cc75] Update copy rights +- [62412641] Add vsan bindings +- [fc3f0e9d] Support resignature of vmfs snapshots ([#1442](https://github.com/vmware/govmomi/issues/1442)) +- [fe372923] govc: rename vcenter.deploy to library.deploy +- [436d7a04] govc: move library.item.update commands to library.session +- [e6514757] govc: consolidate library commands +- [f8249ded] govc: export Archive Path field +- [8a823c52] vcsa: bump to 6.7u2 +- [5b5eaa70] vcsim: remove httptest.serve flag +- [466dc5b2] Update to vSphere 6.7u2 API +- [e9f80882] Add error check to VirtualMachine.WaitForNetIP +- [5611aaa2] Add ovftool support +- [20c1873e] vcsim: add library.deploy support +- [0b1ad552] vcsim: add ovf manager +- [d2ab2782] govc: add vm.change vpmc-enabled flag +- [e7b801c6] govc: fix vm.change against templates +- [8a856429] govc: fix option.set for int32 type values +- [9155093e] Typo and->an +- [81391309] govc: add datastore.maintenance.{enter,exit} commands +- [1a857b94] Add support to reconcile FCD datastore inventory +- [18cb9142] govc: FCD workarounds +- [499a8828] Fix staticcheck issues value of `XXX` is never used +- [665affe5] govc: add datastore.cluster.info Description +- [546e8897] Add error check for deferred functions +- [367c8743] Fix bug with multiple tags in category +- [7b7f2013] govc: add permission.remove -f flag +- [87bc0c85] Makefile: Fix govet target using go1.12 +- [791e5434] travis.yml: Update from golang 1.11 to 1.12 +- [a86a42a2] travis.yml: Update from Ubuntu Trusty to Xenial +- [d92ee75e] Report local Datastore back as type OTHER +- [6684016f] vcsim: fork httptest server package +- [48c1e0a5] vcsim: add content library support +- [69faa2de] Make PostEvent TaskInfo param optional +- [608ad29f] Omit namespace tag in generated method body response types +- [a7c03228] Fix codespell issues +- [728e77db] Fix a race in NewServer(). +- [8543ea4f] vcsim: set guest.toolsRunningStatus property +- [e3143407] Fix elseif gocritic issues +- [89b53312] Fix gocritic emptyStringTest issues +- [63ba9232] Fix some trivial gocritic issues +- [0b8d0ee7] simulator/host_datastore_browser.go: remove commented out code +- [6c17d66c] Fix some staticcheck issues +- [d45b5f34] Fix some gosimple issues +- [90e501a6] Correct the year in the govc changelog +- [8082a261] Update XDR to use fork +- [e94ec246] govc/USAGE.md: Update documentation +- [3fde3319] snapshot.tree: Show snapshots description +- [1d6f743b] Fix year in changelog +- [39b2c871] support customize vm folder in ovf deploy +- [3ad203d3] Use rest.Client for library uploads +- [5d24c38c] lib/finder: Support filenames with "/" +- [087f09f9] govc library: use govc/flags for Datastore and ResourcePool +- [d1a7f491] Remove nested progress.Tee usage +- [7312711e] govc/vm/*: Fix some gosec Errors unhandled issues +- [88601bb7] vcsim/*: Fix Errors unhandled issues +- [61d04b46] session/*: Fix Errors unhandled issues +- [f9a22349] vmdk/*: Fix gosec Errors unhandled issues +- [ca9b71a9] Fix gosec Expect directory permissions to be 0750 or less issues +- [6083e891] Fix gosec potential file inclusion via variable issues +- [38091bf8] Build changes needed for content library +- [885d4b44] Content library additions/finder +- [3fb72d1a] Add support for content library +- [64f2a5ea] Fix API Version check. +- [718331e3] govc/*: Fix some staticcheck issues +- [ba7923ae] Fix all staticcheck "error strings should not be capitalized" issues +- [ed32a917] simulator/*: Fix some staticcheck issues +- [f71d4efb] govc/vm/*: Fix staticcheck issues +- [3d77e2b1] vim25/*: Fix staticcheck issues +- [d711005a] .gitignore: add editor files *~ +- [43ff04f1] Fix [#1173](https://github.com/vmware/govmomi/issues/1173) +- [562aa0db] Go Mod Support + + +## [Release v0.20.3](https://github.com/vmware/govmomi/compare/v0.20.2...v0.20.3) + +> Release Date: 2019-10-08 + +### ⚠️ BREAKING + +### 📖 Commits + +- [fdd27786] Fix tls config in soap.NewServiceClient + + +## [Release v0.20.2](https://github.com/vmware/govmomi/compare/v0.20.1...v0.20.2) + +> Release Date: 2019-07-03 + +### ⚠️ BREAKING + +### 📖 Commits + +- [bd9cfd18] Set the InventoryPath of the folder object in DefaultFolder ([#1515](https://github.com/vmware/govmomi/issues/1515)) + + +## [Release v0.20.1](https://github.com/vmware/govmomi/compare/v0.20.1-vsan-65a0d6ab...v0.20.1) + +> Release Date: 2019-05-20 + +### ⚠️ BREAKING + +### 📖 Commits + +- [4514987f] Fix port signature in REST endpoint token auth + + +## [Release v0.20.1-vsan-65a0d6ab](https://github.com/vmware/govmomi/compare/v0.20.1-vsan-199e737b...v0.20.1-vsan-65a0d6ab) + +> Release Date: 2021-02-19 + +### ⚠️ BREAKING + +### 📖 Commits + +- [536a78e2] Add function to get vsan host config +- [58e6303b] Add test for vsan host config +- [74f25ae7] Adding VsanQueryObjectIdentities and QueryVsanObjects +- [e43fff34] skip tests when env is not set +- [43532740] Adding new API to get cluster configuration +- [9a53dde4] Add CnsQuerySelectionNameType and CnsKubernetesEntityType back +- [bac56c3b] Add bindings for vSANFS and extend CNS bindings to support file volume + + +## [Release v0.20.1-vsan-199e737b](https://github.com/vmware/govmomi/compare/v0.20.0...v0.20.1-vsan-199e737b) + +> Release Date: 2019-05-13 + +### 💫 `govc` (CLI) + +- [fe372923] rename vcenter.deploy to library.deploy +- [436d7a04] move library.item.update commands to library.session +- [e6514757] consolidate library commands +- [f8249ded] export Archive Path field +- [d2ab2782] add vm.change vpmc-enabled flag +- [e7b801c6] fix vm.change against templates +- [8a856429] fix option.set for int32 type values +- [81391309] add datastore.maintenance.{enter,exit} commands +- [18cb9142] FCD workarounds +- [665affe5] add datastore.cluster.info Description +- [7b7f2013] add permission.remove -f flag + +### 💫 `vcsim` (Simulator) + +- [83e068c5] fix ListView.Modify +- [3a6a02c0] add ListView to race test +- [89678493] avoid ViewManager.ModifyListView race +- [3661c9b4] add PlaceVm support ([#1589](https://github.com/vmware/govmomi/issues/1589)) +- [5b5eaa70] remove httptest.serve flag +- [20c1873e] add library.deploy support +- [0b1ad552] add ovf manager +- [6684016f] fork httptest server package +- [48c1e0a5] add content library support +- [8543ea4f] set guest.toolsRunningStatus property + +### ⚠️ BREAKING + +### 📖 Commits + +- [b3c1d778] Add generated vslm types and methods +- [67f65ce0] Remove duplicate cns bindings from vsan directory +- [42ba0d6e] Add test for vsan host config +- [45e77063] Add function to get vsan host config +- [668f7bcb] Add wrappers for retrieving vsan properties +- [001df6f8] Use gofmt +- [f51a8ca4] Add vSAN 7.0 API bindings +- [f08fb2a3] Add vSAN 7.0 API bindings +- [6eec064a] Adding VsanQueryObjectIdentities and QueryVsanObjects +- [d17598e4] Vsan Performance Data Collection API ([#2021](https://github.com/vmware/govmomi/issues/2021)) +- [7406f2dc] skip tests when env is not set +- [c32d3619] removing usage of spew package +- [e247d675] Adding new API to get cluster configuration +- [65160c8e] Add CnsQuerySelectionNameType and CnsKubernetesEntityType back +- [2b954493] Add bindings for vSANFS and extend CNS bindings to support file volume +- [6e27e035] Merge branch 'topic/georgek/cherrypick' into 'vmware-internal' +- [83e068c5] vcsim: fix ListView.Modify +- [3a6a02c0] vcsim: add ListView to race test +- [89678493] vcsim: avoid ViewManager.ModifyListView race +- [86ad2937] Merge branch 'topic/desaiy/vmware-internal' into 'vmware-internal' +- [79a6eb29] Add ExtendDisk and InflateDisk wrappers to vlsm/object_manager +- [6e531650] Add AttachDisk and DetachDisk wrappers for the virtualMachine object. +- [599c291f] Merge branch 'faiyaza/vmware-internal' into 'vmware-internal' +- [5ff5d327] Update to vSphere 7 APIs +- [c41c4577] Update generated code to vSphere 6.7u3 +- [4b803b94] Update to vSphere 6.7u2 API +- [51cd0cee] adds error check before returning value +- [3088c640] adds code to query for license description +- [77932350] adds client code to add license description spec +- [da94d023] Merge branch 'topic/rvembuli/fix_client_method' into 'vmware-internal' +- [1a4b19ad] adds error check before returning value +- [95605ad3] Merge branch 'topic/rvembuli/add_product_search' into 'vmware-internal' +- [29b5b751] adds code to query for license description +- [38855369] Merge branch 'topic/rvembuli/2590835/add_client_dlf' into 'vmware-internal' +- [1c8979ee] adds client code to add license description spec +- [aeafc880] Merge branch 'topic/rvembuli/update_bindings_license_service' into 'vmware-internal' +- [56e5babf] adds client bindings generated from wsdl file in http://build-squid.eng.vmware.com/build/mts/release/sb-37722446/publish/wsdl/license-cis-vmodl-bindings.wsdl +- [6a920510] Merge branch 'topic/nmadanapalli/ls-persistent-client-PR2594868' into 'vmware-internal' +- [5eb03816] Keepalive handling for ls.Client +- [9901834a] Merge branch 'topic/nmadanapalli/ls-cookie-PR2591635' into 'vmware-internal' +- [57a072fb] Instantiating a new cookie jar for every LS client instance +- [01cf5cca] Merge branch 'topic/faiyaza/guestopscherrypick' into 'vmware-internal' +- [97012c79] Avoid possible nil pointer dereference in guest TransferURL +- [a8ed5502] Merge branch 'topic/nmadanapalli/license-asset-bindings' into 'vmware-internal' +- [876137ae] Adding AssetService bindings +- [2407e148] Merge branch 'topic/nmadanapalli/backport-322d962' into 'vmware-internal' +- [9c89ff53] Fix pbm field type lookup +- [7e26d088] Merge branch 'cherry-pick-a355f576' into 'vmware-internal' +- [80c6a727] Switch VAPI cluster modules to using NewResource to fix URLs to start with /rest/vcenter/ +- [e4872724] Local cherry-pick of Cluster Module API support without simulator testing. +- [94f7310e] Merge branch 'topic/pradyumnaa/nsxt-status' into 'vmware-internal' +- [b1c7b0f3] Add the NsxtStatus field to HostProxySwitch +- [fd246c9e] Merge branch 'topic/mansia/license' into 'vmware-internal' +- [8d40f673] Enhance govmomi license bindings to accept null NotificationSearchSpec +- [c07aa445] Merge branch 'topic/ljoyce/lifecycle-managed' into 'vmware-internal' +- [f9c0e4fb] Add lifecycleManaged property to ComputeResource object +- [6f8ae93b] Cherry-pick 62c20113 and b916904 +- [dcd17fc6] Merge branch 'topic/mansia/license' into 'vmware-internal' +- [1f5c0b19] Add cis.license client +- [fa03c5db] Merge branch 'cherry-pick-97c24006' into 'vmware-internal' +- [a2c9e16e] Merge branch 'cherry-pick-674286cb' into 'vmware-internal' +- [318eaf6d] Add support for appliance/logging/forwarding VAPI [1/3] +- [ffcb0eca] Merge branch 'cherry-pick-d296a5f8' into 'vmware-internal' +- [00e53090] Support HoK tokens with Interactive Users +- [f71af4d0] Merge branch 'cherry-pick-c183577b' into 'vmware-internal' +- [3661c9b4] vcsim: add PlaceVm support ([#1589](https://github.com/vmware/govmomi/issues/1589)) +- [c81eab04] Merge branch 'cherry-pick-384b1b95' into 'vmware-internal' +- [2751a42a] Fix port signature in REST endpoint token auth +- [25117583] Merge branch 'topic/anubhabm/wcp-license' into 'vmware-internal' +- [44d91635] Adding API bindings for isFeatureAvailable internal API +- [5f837dc8] Added support for HostSystem InternalConfigManager property +- [d7abbdbb] Add bindings for NetworkSystem.PerformHostOpaqueNetworkDataOperation to vim25 +- [4f441128] Merge branch 'topic/echu/cis-session-get' into 'vmware-internal' +- [a3ba80dc] cherry-pick cis-session-get change from master +- [aba0bbae] Add vAPI create binding for compute policy +- [fe292fa4] Add vAPI create binding for compute policy +- [c64008ad] Always use the service version when possible. +- [9ff64cfe] Add method that sets vim version to the endpoint service version +- [218f7ef5] Add TenantManager helper +- [ce5f283c] Fix deadlock for keep alive handlers that attempt log in +- [3c702b66] Add TenantManager bindings to vim25 +- [a6b86c92] Adding API bindings for scalable shares +- [16823c9b] Adding API bindings for createNamespaceFolder and createNamespaceResourcePool internal APIs +- [fe42604f] Pulling changes from master and resolving conflicts +- [dc631a2d] Format import statement +- [f133c9e9] Fix paths in vsan/methods +- [d8e7cc75] Update copy rights +- [62412641] Add vsan bindings +- [605b62fa] Adding bindings for placeMultiVms API +- [fc3f0e9d] Support resignature of vmfs snapshots ([#1442](https://github.com/vmware/govmomi/issues/1442)) +- [fe372923] govc: rename vcenter.deploy to library.deploy +- [436d7a04] govc: move library.item.update commands to library.session +- [e6514757] govc: consolidate library commands +- [1445cab3] Merge branch 'cherry-pick-0b097847' into 'vmware-internal' +- [ee087144] Added SphereletManager bindings +- [f8249ded] govc: export Archive Path field +- [8a823c52] vcsa: bump to 6.7u2 +- [5b5eaa70] vcsim: remove httptest.serve flag +- [e9f80882] Add error check to VirtualMachine.WaitForNetIP +- [5611aaa2] Add ovftool support +- [20c1873e] vcsim: add library.deploy support +- [0b1ad552] vcsim: add ovf manager +- [d2ab2782] govc: add vm.change vpmc-enabled flag +- [e7b801c6] govc: fix vm.change against templates +- [8a856429] govc: fix option.set for int32 type values +- [9155093e] Typo and->an +- [81391309] govc: add datastore.maintenance.{enter,exit} commands +- [1a857b94] Add support to reconcile FCD datastore inventory +- [18cb9142] govc: FCD workarounds +- [499a8828] Fix staticcheck issues value of `XXX` is never used +- [665affe5] govc: add datastore.cluster.info Description +- [546e8897] Add error check for deferred functions +- [367c8743] Fix bug with multiple tags in category +- [7b7f2013] govc: add permission.remove -f flag +- [87bc0c85] Makefile: Fix govet target using go1.12 +- [791e5434] travis.yml: Update from golang 1.11 to 1.12 +- [a86a42a2] travis.yml: Update from Ubuntu Trusty to Xenial +- [d92ee75e] Report local Datastore back as type OTHER +- [6684016f] vcsim: fork httptest server package +- [48c1e0a5] vcsim: add content library support +- [69faa2de] Make PostEvent TaskInfo param optional +- [608ad29f] Omit namespace tag in generated method body response types +- [a7c03228] Fix codespell issues +- [728e77db] Fix a race in NewServer(). +- [8543ea4f] vcsim: set guest.toolsRunningStatus property +- [e3143407] Fix elseif gocritic issues +- [89b53312] Fix gocritic emptyStringTest issues +- [63ba9232] Fix some trivial gocritic issues +- [0b8d0ee7] simulator/host_datastore_browser.go: remove commented out code +- [6c17d66c] Fix some staticcheck issues +- [d45b5f34] Fix some gosimple issues +- [90e501a6] Correct the year in the govc changelog +- [8082a261] Update XDR to use fork +- [e94ec246] govc/USAGE.md: Update documentation +- [3fde3319] snapshot.tree: Show snapshots description +- [1d6f743b] Fix year in changelog +- [39b2c871] support customize vm folder in ovf deploy +- [3ad203d3] Use rest.Client for library uploads +- [5d24c38c] lib/finder: Support filenames with "/" +- [087f09f9] govc library: use govc/flags for Datastore and ResourcePool +- [d1a7f491] Remove nested progress.Tee usage +- [7312711e] govc/vm/*: Fix some gosec Errors unhandled issues +- [88601bb7] vcsim/*: Fix Errors unhandled issues +- [61d04b46] session/*: Fix Errors unhandled issues +- [f9a22349] vmdk/*: Fix gosec Errors unhandled issues +- [ca9b71a9] Fix gosec Expect directory permissions to be 0750 or less issues +- [6083e891] Fix gosec potential file inclusion via variable issues +- [38091bf8] Build changes needed for content library +- [885d4b44] Content library additions/finder +- [3fb72d1a] Add support for content library +- [64f2a5ea] Fix API Version check. +- [718331e3] govc/*: Fix some staticcheck issues +- [ba7923ae] Fix all staticcheck "error strings should not be capitalized" issues +- [ed32a917] simulator/*: Fix some staticcheck issues +- [f71d4efb] govc/vm/*: Fix staticcheck issues +- [3d77e2b1] vim25/*: Fix staticcheck issues +- [d711005a] .gitignore: add editor files *~ +- [43ff04f1] Fix [#1173](https://github.com/vmware/govmomi/issues/1173) +- [562aa0db] Go Mod Support + + +## [Release v0.20.0](https://github.com/vmware/govmomi/compare/v0.19.0...v0.20.0) + +> Release Date: 2019-02-06 + +### 💫 `govc` (CLI) + +- [308dbf99] fix object.collect error for multiple objects with same path +- [4635c1cc] add device name match support to device.ls and device.remove +- [c36eb50f] add vm.disk.attach -mode flag +- [b234cdbc] add category option to relevant tags commands +- [afe5f42d] add vm.create -version option +- [b733db99] fields.set can now add missing fields +- [cad627a6] add fields.info command + +### 💫 `vcsim` (Simulator) + +- [957ef0f7] require authentication in vapi simulator +- [32148187] Resolve issue making device changes on clone (resolves [#1355](https://github.com/vmware/govmomi/issues/1355)) +- [cbb4abc9] fix SearchDatastore task info entity +- [2682c021] add EnvironmentBrowser support +- [3b9a4c9f] avoid zero IP address in GOVC_URL output +- [1921f73a] avoid panic when event template is not defined +- [d79013aa] implement RefreshStorageInfo method for virtual machine +- [69dfdd77] configure HostSystem port +- [bba50b40] datastore.upload now creates missing directories in destination path. +- [d2506759] add option to run container as vm +- [47284860] add SessionIsActive support +- [c5ee00bf] fix fault detail encoding +- [1284300c] support base types in property filter +- [25ae5c67] PropertyCollector should not require PathSet +- [4f1c89e5] allow '.' in vm name +- [b8c04142] populate VM guest.net field +- [223b2a2a] add SearchIndex FindByDnsName support +- [b26e10f0] correct property update in RemoveSnapshotTask +- [693f3fb6] update VM snapshot methods to change VM properties with UpdateObject +- [06e13bbe] support setting vm fields via extraConfig +- [a4330365] update VM configureDevices method to change VM properties with UpdateObject +- [5f8acb7a] update VM device add operation - stricter key generation, new InvalidDeviceSpec condition +- [846ae27a] add PBM support +- [d41d18aa] put VM into registry earlier during CreateVM +- [89b4c2ce] add datastore access check for vm host placement +- [f9f9938e] add task_manager description property templates +- [9bb5bde2] fix defaults when generating vmdk paths +- [0b650fd3] fix custom_fields_manager test +- [588bc224] replace HostSystem template IP with vcsim listen address +- [7066f8dc] Change CustomFieldsManager SetField to use ctx.WithLock and add InvalidArgument fault check. +- [fe070811] update DVS methods to use UpdateObject instead of setting fields directly +- [03939cce] add vslm support +- [c02efc3d] add setCustomValue support +- [94804159] add fault message to PropertyCollector RetrieveProperties +- [36035f5b] add HistoryCollector scrollable view support + +### ⚠️ BREAKING + +### 📖 Commits + +- [da7af247] Fix for govc/build.sh wrong dir +- [90a863be] Update docs for 0.20 release +- [957ef0f7] vcsim: require authentication in vapi simulator +- [32148187] vcsim: Resolve issue making device changes on clone (resolves [#1355](https://github.com/vmware/govmomi/issues/1355)) +- [a7563c4d] Use path id for tag-association requests +- [cbb4abc9] vcsim: fix SearchDatastore task info entity +- [2682c021] vcsim: add EnvironmentBrowser support +- [3b9a4c9f] vcsim: avoid zero IP address in GOVC_URL output +- [b261f25d] Add 2x blog posts about vcsim +- [1921f73a] vcsim: avoid panic when event template is not defined +- [308dbf99] govc: fix object.collect error for multiple objects with same path +- [d79013aa] vcsim: implement RefreshStorageInfo method for virtual machine +- [69dfdd77] vcsim: configure HostSystem port +- [4f50681f] Fix of the missing http body close under soap client upload +- [bba50b40] vcsim: datastore.upload now creates missing directories in destination path. +- [8ac7c5a8] Fixed 64-bit aligment issues with atomic counters +- [7ca12ea2] fix device.info Write output +- [3a82237c] device.ls -json doesn't work for now +- [86f4ba29] ssoadmin:create local group and add users to group ([#1327](https://github.com/vmware/govmomi/issues/1327)) +- [2d8ef2c6] Format with latest version of goimports +- [4635c1cc] govc: add device name match support to device.ls and device.remove +- [d7857a13] Updated the examples for the correct format +- [71e19136] Updated to reflect PR feedback +- [d2506759] vcsim: add option to run container as vm +- [61b7fe3e] Added string support +- [a72a4c42] Initial Support for PutUsbScanCodes +- [47284860] vcsim: add SessionIsActive support +- [c5ee00bf] vcsim: fix fault detail encoding +- [aaf83275] Summary of changes: 1. Changing the pbm client's path as java client is expecting /pbm. 2. Added PbmRetrieveServiceContent method in the unauthorized list. +- [c36eb50f] govc: add vm.disk.attach -mode flag +- [1284300c] vcsim: support base types in property filter +- [25ae5c67] vcsim: PropertyCollector should not require PathSet +- [b234cdbc] govc: add category option to relevant tags commands +- [138f30f8] Makefiles for govc/vcsim; updates govc/build.sh +- [4f1c89e5] vcsim: allow '.' in vm name +- [afe5f42d] govc: add vm.create -version option +- [b8c04142] vcsim: populate VM guest.net field +- [223b2a2a] vcsim: add SearchIndex FindByDnsName support +- [b26e10f0] vcsim: correct property update in RemoveSnapshotTask +- [693f3fb6] vcsim: update VM snapshot methods to change VM properties with UpdateObject +- [e5948f44] build: Refactored Travis-CI to use containers +- [06e13bbe] vcsim: support setting vm fields via extraConfig +- [651d4881] Allow pointer values in mo.ApplyPropertyChange +- [546a7df6] Tags support for First Class Disks +- [a4330365] vcsim: update VM configureDevices method to change VM properties with UpdateObject +- [5f8acb7a] vcsim: update VM device add operation - stricter key generation, new InvalidDeviceSpec condition +- [86375ceb] Merge branch 'master' into fields-info +- [bf962f18] Update govc/fields/add.go +- [98575e0c] Update govc/fields/add.go +- [b733db99] govc: fields.set can now add missing fields +- [cad627a6] govc: add fields.info command +- [ed2a4cff] vm.power: Make waiting for op completion optional +- [846ae27a] vcsim: add PBM support +- [d41d18aa] vcsim: put VM into registry earlier during CreateVM +- [1926071e] Datastore Cluster placement support for First Class Disks +- [89b4c2ce] vcsim: add datastore access check for vm host placement +- [f9f9938e] vcsim: add task_manager description property templates +- [9bb5bde2] vcsim: fix defaults when generating vmdk paths +- [0b650fd3] vcsim: fix custom_fields_manager test +- [588bc224] vcsim: replace HostSystem template IP with vcsim listen address +- [7066f8dc] vcsim: Change CustomFieldsManager SetField to use ctx.WithLock and add InvalidArgument fault check. +- [ef517cae] Display category name instead of ID in govc tags.info +- [d69c9787] goimports updates +- [fe070811] vcsim: update DVS methods to use UpdateObject instead of setting fields directly +- [03939cce] vcsim: add vslm support +- [accb2863] Add vslm package and govc disk commands +- [478ebae6] [doc] add an example for cpu and memory hotplug +- [c02efc3d] vcsim: add setCustomValue support +- [c3c79d16] goimports updates +- [ce71b6c2] vcsa: bump to 6.7.0 U1 +- [94804159] vcsim: add fault message to PropertyCollector RetrieveProperties +- [1ad0d87d] Removed NewWithDelay (not needed anymore) +- [5900feef] Updated documentation +- [5a87902b] Added delay functionality +- [c0518fd2] Add LoginByToken to session KeepAliveHandler +- [e0736431] Update Ansible link in README +- [36035f5b] vcsim: add HistoryCollector scrollable view support +- [bc2636fe] Move govc tags rest.Client helper to ClientFlag +- [54a181af] Add SSO support for vAPI +- [8817c27b] replace * by client's host+port +- [ac898b50] change hostname only if set to * and still set thumbprint +- [7a5cc6b7] replace hostname only if unset + + +## [Release v0.19.0](https://github.com/vmware/govmomi/compare/v0.18.0...v0.19.0) + +> Release Date: 2018-09-30 + +### 💫 `govc` (CLI) + +- [6b4a62b1] fix test case for new cluster.rule.info command +- [1350eea6] add new command cluster.rule.info + +### 💫 `vcsim` (Simulator) + +- [f3260968] add dvpg networks to HostSystem.Parent +- [17352fce] add support for tags API +- [c29d4b12] Logout should not unregister PropertyCollector singleton +- [11fb0d58] add ResetVM and SuspendVM support +- [39e6592d] add support for PropertyCollector incremental updates +- [619fbe28] do not include DVS in HostSystem.Network + +### ⚠️ BREAKING + +### 📖 Commits + +- [3617f28d] Update docs for 0.19 release +- [4316838a] vcsa: bump to 6.7.0d +- [64d875b9] Added PerformanceManager simulator +- [f3260968] vcsim: add dvpg networks to HostSystem.Parent +- [862da065] Allowing the use of STS for exchanging tokens +- [83ce863a] Handle empty file name in import.spec +- [a99f702d] Bump travis golang version from 1.10 to 1.11 +- [e4e8e2d6] Clean up unit test messaging +- [8e04e3c7] Run goimports on go source files +- [2431ae00] Add mailmap for bruceadowns +- [e805b4ea] Updates per dep ensure integration +- [70589fb6] Add ignore of intellij project settings directory +- [d114fa69] Print action for dvs security groups +- [d458266a] fix double err check +- [3f0e0aa7] remove providerSummary cache +- [cf9c16c4] Avoid use of Finder all param in govc +- [c4face4f] Print DVS rules for dvportgroup +- [91a33dd4] Finalize tags API +- [7d54bf9f] README: Fix path to LICENSE.txt file +- [17352fce] vcsim: add support for tags API +- [c29d4b12] vcsim: Logout should not unregister PropertyCollector singleton +- [8bda0ee1] Fix format in test +- [8be5207c] Add test for WaitOption.MaxWaitSeconds == 0 behaviour in simulator +- [900e1a35] Fix the WaitOption.MaxWaitSeconds == 0 behaviour in simulator +- [056ad0d4] vcsa: bump to 6.7.0c release +- [6b4a62b1] govc: fix test case for new cluster.rule.info command +- [1350eea6] govc: add new command cluster.rule.info +- [a05cd4b0] add output in cluster.rule.ls -name for ClusterVmHostRuleInfo and ClusterDependencyRuleInfo rules, add -l Option to cluster.rule.ls +- [11fb0d58] vcsim: add ResetVM and SuspendVM support +- [3e6b2d6e] Add ability to move multiple hosts into a cluster +- [e9f9920f] Add method to move host into cluster +- [39e6592d] vcsim: add support for PropertyCollector incremental updates +- [b7c270c6] Add testing support for govc tags commands +- [619fbe28] vcsim: do not include DVS in HostSystem.Network +- [6b6060dc] show rule details for ClusterVmHostRuleInfo rules in cluster.rule.ls +- [0c28a25d] Use govc find instead of ls to assign licenses +- [c1377063] Only test with Go 1.10 on Travis CI +- [4cfadda5] Avoid panic if fault detail is nil +- [d06874e1] Upgrade for govc tags commands +- [fdfaec9c] Better documentation for VirtualMachine.UUID +- [e1285a03] Add UUID helper for VirtualMachine +- [919b728c] Complete tags management APIs ([#1162](https://github.com/vmware/govmomi/issues/1162)) +- [b3251638] vcsa: bump to 6.7.0a release +- [a1fbb6ef] Optionally check root CAs for validity ([#1154](https://github.com/vmware/govmomi/issues/1154)) +- [add38bed] Fixed govc host.info logical CPU count +- [1ddfb011] Tags Categories cmd available ([#1150](https://github.com/vmware/govmomi/issues/1150)) +- [83ae35fb] default MarkAsTemplate to false in import spec +- [49f0dea7] add option to mark VM as template on OVX import +- [1f9e19f4] example: uniform unit for host memory +- [4cfd1376] fix example output. + + +## [Release v0.18.0](https://github.com/vmware/govmomi/compare/v0.17.1...v0.18.0) + +> Release Date: 2018-05-24 + +### 💫 `govc` (CLI) + +- [b841ae01] import.ovf pool flag should be optional if host is specified +- [f5c84b98] avoid Login() attempt if username is not set +- [d91fcbf4] add json support to find command +- [ba2d2323] fix host.esxcli error handling + +### 💫 `vcsim` (Simulator) + +- [8a5438b0] add STS simulator +- [c0337740] use VirtualDisk CapacityInKB for device summary +- [3d7fbac2] add property collector field type mapping for integer arrays + +### ⚠️ BREAKING + +### 📖 Commits + +- [e4b69fab] Update docs for 0.18 release +- [1dbfb317] Bump versions +- [b841ae01] govc: import.ovf pool flag should be optional if host is specified +- [96a905c1] Add -sharing option to vm.disk.create and vm.disk.attach +- [4b4e2aaa] Add VirtualDiskManager wrapper to set UUID +- [40a565b3] adjust datastore size when vm is added or updated or deleted +- [7f6479ba] update datastore capacity and free space when it is started +- [76dfefd3] Avoid recursive root path search in govc find command +- [623c7fa9] Change key name according to Datacenter object +- [24d0cf1b] added check for `InstanceUuid` when `VmSearch` is true in `FindByUuid` +- [25fc474c] Issue token if needed for govc sso commands +- [822fd1c0] Fixed leading "/" requirement in FindByInventoryPath +- [59d9f6a0] Add devbox scripts +- [fd45d81c] Add -U option to sso.service.ls +- [f5c84b98] govc: avoid Login() attempt if username is not set +- [8a5438b0] vcsim: add STS simulator +- [93f7fbbd] Fix govc vm.clone -annotation flag +- [bcff5383] save CapacityInKB in thousand delimited format +- [db12d4cb] Avoid possible panic in portgroup EthernetCardBackingInfo +- [d120efcb] Add STS support for token renewal +- [76b1ceaf] Add vmxnet2, pcnet32 and sriov to VirtualDeviceList.EthernetCardTypes +- [c0337740] vcsim: use VirtualDisk CapacityInKB for device summary +- [3d7fbac2] vcsim: add property collector field type mapping for integer arrays +- [42b30bb6] Finder.DefaultHostSystem should find hosts in nested folders +- [b8323d6b] Avoid property.Filter matching against unset properties +- [64788667] Update to vSphere 6.7 API +- [d3ae3004] Bump vCenter and ESXi builds to the latest release +- [098fc449] Add ssoadmin client and commands +- [80a9c20e] vm.Snapshot should be 'nil' instead of an empty 'vim.vm.SnapshotInfo' when there are no snapshots +- [1b1b428e] added failing tests for when vm.Snapshot should / shouldn't be 'nil' +- [a34ab4ba] Refactor LoginExtensionByCertificate tunnel usage +- [5b36033f] Lookup Service support +- [3f07eb74] add empty fields, but don't return them in the case of 'RetrievePropertiesEx' +- [05bdabe0] added failing test case for issue 1061 +- [903e8644] SAML token authentication support +- [d91fcbf4] govc: add json support to find command +- [ba2d2323] govc: fix host.esxcli error handling +- [ff687746] Dep Support +- [5f701460] Add -firmware parameter to 'govc vm.create' with values bios|efi + + +## [Release v0.17.1](https://github.com/vmware/govmomi/compare/v0.17.0...v0.17.1) + +> Release Date: 2018-03-19 + +### 💫 `vcsim` (Simulator) + +- [0502ee9b] add Destroy method for Folder and Datacenter types +- [0636dc8c] add EventManager.QueryEvents + +### ⚠️ BREAKING + +### 📖 Commits + +- [123ed177] govc release 0.17.1 +- [24d88451] Avoid possible panic in QueryVirtualDiskInfo +- [82129fb7] Add goreleaser to automate release process +- [ce88b296] Fix dvs.portgroup.info filtering +- [0502ee9b] vcsim: add Destroy method for Folder and Datacenter types +- [1620160d] In progress.Reader emit final report on EOF. +- [0636dc8c] vcsim: add EventManager.QueryEvents + + +## [Release v0.17.0](https://github.com/vmware/govmomi/compare/v0.16.0...v0.17.0) + +> Release Date: 2018-02-28 + +### 💫 `govc` (CLI) + +- [29498644] fix vm.clone to use -net flag when source does not have a NIC +- [d12b8f25] object.collect support for raw filters +- [6cb9fef8] fix host.info CPU usage +- [5786e7d2] add -cluster flag to license.assign command +- [d4ee331c] allow columns in guest login password ([#972](https://github.com/vmware/govmomi/issues/972)) + +### 💫 `vcsim` (Simulator) + +- [d2ba47d6] add simulator.Datastore type +- [937998a1] set VirtualMachine summary.config.instanceUuid +- [1c76c63d] update HostSystem.Summary.Host reference +- [274f3d63] add EventManager support +- [cc21a5ab] stats related fixes +- [fa2bee10] avoid data races +- [ca6f5d1d] respect VirtualDeviceConfigSpec FileOperation +- [7811dfce] avoid keeping the VM log file open +- [828ce5ec] add UpdateOptions support +- [d03f38fa] add session support +- [a3c9ed2b] Add VM.MarkAsTemplate support +- [50735461] more input spec honored in ReConfig VM +- [638d972b] Initialize VM fields properly +- [aa0382c1] Honor the input spec in ReConfig VM +- [42f9a133] Add HostLocalAccountManager +- [76f376a3] workaround xml ns issue with pyvsphere ([#958](https://github.com/vmware/govmomi/issues/958)) +- [45c5269b] add MakeDirectoryResponse ([#938](https://github.com/vmware/govmomi/issues/938)) +- [b4e77bd2] copy RoleList for AuthorizationManager ([#932](https://github.com/vmware/govmomi/issues/932)) +- [2a8a5168] apply vm spec NumCoresPerSocket ([#930](https://github.com/vmware/govmomi/issues/930)) +- [3a61d85f] Configure dvs with the dvs config spec +- [5f0f4004] Add VirtualMachine guest ID validation ([#921](https://github.com/vmware/govmomi/issues/921)) +- [ef571547] add QueryVirtualDiskUuid ([#920](https://github.com/vmware/govmomi/issues/920)) +- [27229ab7] update ServiceContent to 6.5 ([#917](https://github.com/vmware/govmomi/issues/917)) + +### ⚠️ BREAKING + +### 📖 Commits + +- [1d63da8d] govc release 0.17 +- [3017acf8] Print Table of Contents in usage.md Found good example of toc using markdown here: https://stackoverflow.com/a/448929/1572363 +- [ce54fe2c] Fix typo +- [201fc601] Implement Destroy task for HostSystem +- [92ce4244] Init PortKeys in DistributedVirtualPortgroup +- [795f2cc7] Avoid json encoding error in Go 1.10 +- [e805389e] Add 'Type' field to device.info -json output +- [d622f149] Use VirtualDiskManager in datastore cp and mv commands +- [f219bf3b] object: Return correct helper object for OpaqueNetwork +- [29498644] govc: fix vm.clone to use -net flag when source does not have a NIC +- [43c95b21] Fix build on Windows +- [38124002] Fix session persistence in session.login command +- [144bb1cf] Add support for Datacenter.PowerOnMultiVM +- [d2ba47d6] vcsim: add simulator.Datastore type +- [937998a1] vcsim: set VirtualMachine summary.config.instanceUuid +- [1c76c63d] vcsim: update HostSystem.Summary.Host reference +- [d12b8f25] govc: object.collect support for raw filters +- [274f3d63] vcsim: add EventManager support +- [cc21a5ab] vcsim: stats related fixes +- [2d30cde3] Fix broken datastore link in VM +- [54b160b2] Several context changes: +- [f643f0ae] Leverage contexts in http uploads +- [fa2bee10] vcsim: avoid data races +- [29bd00ec] Remove omitempty tag from AffinitySet field +- [ca6f5d1d] vcsim: respect VirtualDeviceConfigSpec FileOperation +- [7811dfce] vcsim: avoid keeping the VM log file open +- [6cb9fef8] govc: fix host.info CPU usage +- [5786e7d2] govc: add -cluster flag to license.assign command +- [63c86f29] Add datastore.disk.cp command +- [828ce5ec] vcsim: add UpdateOptions support +- [a13ad164] Bump vcsa scripts to use 6.5U1 EP5 +- [c447244d] Add CloneSession support to govc and vcsim +- [d03f38fa] vcsim: add session support +- [44e8d85e] Added AttachScsiLun function ([#987](https://github.com/vmware/govmomi/issues/987)) +- [a3c9ed2b] vcsim: Add VM.MarkAsTemplate support +- [3f8349f3] Add cluster vm override commands ([#977](https://github.com/vmware/govmomi/issues/977)) +- [91fbd1f7] Add option to filter events by type ([#976](https://github.com/vmware/govmomi/issues/976)) +- [1d8b92d9] User server clock in session.ls ([#973](https://github.com/vmware/govmomi/issues/973)) +- [50735461] vcsim: more input spec honored in ReConfig VM +- [638d972b] vcsim: Initialize VM fields properly +- [2892ed50] Add '-rescan-vmfs' option to host.storage.info ([#966](https://github.com/vmware/govmomi/issues/966)) +- [d4ee331c] govc: allow columns in guest login password ([#972](https://github.com/vmware/govmomi/issues/972)) +- [e15ff586] Use IsFileNotFound helper in Datastore.Stat ([#969](https://github.com/vmware/govmomi/issues/969)) +- [aa0382c1] vcsim: Honor the input spec in ReConfig VM +- [465bd948] Hook AccountManager to UserDirectory +- [aef2d795] Destroy event history collectors ([#962](https://github.com/vmware/govmomi/issues/962)) +- [42f9a133] vcsim: Add HostLocalAccountManager +- [76f376a3] vcsim: workaround xml ns issue with pyvsphere ([#958](https://github.com/vmware/govmomi/issues/958)) +- [a1c49292] Ignore AcquireLocalTicket errors ([#955](https://github.com/vmware/govmomi/issues/955)) +- [bb150d50] Add missing dependency in gen script +- [0eacf959] toolbox: validate request offset in ListFiles ([#946](https://github.com/vmware/govmomi/issues/946)) +- [1d6aed22] Corrects datastore.disk usage which had not been generated ([#951](https://github.com/vmware/govmomi/issues/951)) +- [de717389] Corrects vm.info usage with required args ([#950](https://github.com/vmware/govmomi/issues/950)) +- [c5ea3fb2] Add datastore.disk inflate and shrink commands ([#943](https://github.com/vmware/govmomi/issues/943)) +- [adf4530b] Corrects host.shutdown ([#939](https://github.com/vmware/govmomi/issues/939)) +- [45c5269b] vcsim: add MakeDirectoryResponse ([#938](https://github.com/vmware/govmomi/issues/938)) +- [b4e77bd2] vcsim: copy RoleList for AuthorizationManager ([#932](https://github.com/vmware/govmomi/issues/932)) +- [426a675a] Fix [#933](https://github.com/vmware/govmomi/issues/933) ([#936](https://github.com/vmware/govmomi/issues/936)) +- [3be5f1d9] Add cluster.group and cluster.rule commands ([#928](https://github.com/vmware/govmomi/issues/928)) +- [2a8a5168] vcsim: apply vm spec NumCoresPerSocket ([#930](https://github.com/vmware/govmomi/issues/930)) +- [3a61d85f] vcsim: Configure dvs with the dvs config spec +- [3b25c720] CreateChildDisk 6.7 support ([#926](https://github.com/vmware/govmomi/issues/926)) +- [933ee3b2] Add VirtualDiskManager.CreateChildDisk ([#925](https://github.com/vmware/govmomi/issues/925)) +- [5f0f4004] vcsim: Add VirtualMachine guest ID validation ([#921](https://github.com/vmware/govmomi/issues/921)) +- [ef571547] vcsim: add QueryVirtualDiskUuid ([#920](https://github.com/vmware/govmomi/issues/920)) +- [0ea3b9bd] Implemened vm.upgrade operation. ([#918](https://github.com/vmware/govmomi/issues/918)) +- [27229ab7] vcsim: update ServiceContent to 6.5 ([#917](https://github.com/vmware/govmomi/issues/917)) +- [46c79c93] Add support for cpu + mem allocation to vm.change command ([#916](https://github.com/vmware/govmomi/issues/916)) + + +## [Release v0.16.0](https://github.com/vmware/govmomi/compare/v0.15.0...v0.16.0) + +> Release Date: 2017-11-08 + +### 💫 `govc` (CLI) + +- [0295f1b0] Fix VM clone when source doesn't have vNics +- [4fea6863] add tasks and task.cancel commands +- [ddd32366] add reboot option to host.shutdown + +### 💫 `vcsim` (Simulator) + +- [4543f4b6] preserve order in QueryIpPools ([#914](https://github.com/vmware/govmomi/issues/914)) +- [b385183e] return moref from Task.Run ([#913](https://github.com/vmware/govmomi/issues/913)) +- [e29ab54a] Implement IpPoolManager lifecycle +- [b227a258] add autostart option to power on VMs ([#906](https://github.com/vmware/govmomi/issues/906)) +- [ecde4a89] use soapenv namespace for Fault types +- [b1318195] various property additions +- [c19ec714] Generate similar ref value like VC +- [f3046058] Add moref to vm's summary +- [5f3fba94] validate authz privilege ids +- [c2caa6d7] AuthorizationManager additions +- [2cb741f2] Add IpPoolManager +- [a46ab163] VirtualDisk file backing datastore is optional +- [d347175f] add PerformanceManager +- [df3763d5] Implement add/update/remove roles +- [ed18165d] Generate device filename in CreateVM +- [e8741bf0] add AuthorizationManager +- [8961efc1] populate vm snapshot fields +- [add0245e] Add UpdateNetworkConfig to HostNetworkSystem +- [2aa746c6] Implement virtual machine snapshot +- [104ddfb7] set VirtualDisk backing datastore +- [505b5c65] Implement enter/exit maintenance mode +- [a1f8a328] Implement add/remove license +- [585cf5e1] add portgroup related operations +- [a7e79a7e] add fields support +- [895573a5] remove use of df program for datastore info +- [defe810c] add FileQuery support to datastore search +- [5fcca79e] add HostConfigInfo template +- [920a70c1] add HostSystem hardware property +- [0833484e] Fix merging of default devices +- [f6a734f5] Add cdrom and scsi controller to Model VMs + +### ⚠️ BREAKING + +### 📖 Commits + +- [7d879bac] Doc updates ([#915](https://github.com/vmware/govmomi/issues/915)) +- [4543f4b6] vcsim: preserve order in QueryIpPools ([#914](https://github.com/vmware/govmomi/issues/914)) +- [b385183e] vcsim: return moref from Task.Run ([#913](https://github.com/vmware/govmomi/issues/913)) +- [c8738903] Remove tls-handshake-timeout flag ([#911](https://github.com/vmware/govmomi/issues/911)) +- [e29ab54a] vcsim: Implement IpPoolManager lifecycle +- [3619c1d9] Use ProgressLogger for vm.clone command ([#909](https://github.com/vmware/govmomi/issues/909)) +- [13f2aba4] readme: fix formatting of listing ([#908](https://github.com/vmware/govmomi/issues/908)) +- [b227a258] vcsim: add autostart option to power on VMs ([#906](https://github.com/vmware/govmomi/issues/906)) +- [79934451] Add installation procedure in README.md ([#902](https://github.com/vmware/govmomi/issues/902)) +- [ecde4a89] vcsim: use soapenv namespace for Fault types +- [b1318195] vcsim: various property additions +- [4d8737c9] Switch to kr/pretty package for the -dump flag +- [e050b1b6] Couple of fixes for import.spec result +- [017138ca] import.spec not to assign deploymentOption +- [c19ec714] vcsim: Generate similar ref value like VC +- [0295f1b0] govc: Fix VM clone when source doesn't have vNics +- [f3046058] vcsim: Add moref to vm's summary +- [bfed5eea] [govc] Introduce TLSHandshakeTimeout parameter ([#890](https://github.com/vmware/govmomi/issues/890)) +- [1c1291ca] Support import ova/ovf by URL +- [3cb5cc96] Remove BaseResourceAllocationInfo +- [5f3fba94] vcsim: validate authz privilege ids +- [c91b9605] Add clone methods to session manager +- [c2caa6d7] vcsim: AuthorizationManager additions +- [2cb741f2] vcsim: Add IpPoolManager +- [644c1859] Updates to vm.clone link + snapshot flags +- [cf624f1a] Add linked clone and snapshot support to vm.clone +- [024c09fe] Fix govc events output +- [d4d94f44] govc/events: read -json flag and output events as json +- [24e71ea4] Fix vm.register command template flag +- [5209daf2] Fix object name suffix matching in Finder +- [a46ab163] vcsim: VirtualDisk file backing datastore is optional +- [d347175f] vcsim: add PerformanceManager +- [df3763d5] vcsim: Implement add/update/remove roles +- [8d5c1558] Support clearing vm boot order +- [ed18165d] vcsim: Generate device filename in CreateVM +- [df93050a] Fix CustomFieldsManager.FindKey method signature +- [e8741bf0] vcsim: add AuthorizationManager +- [8961efc1] vcsim: populate vm snapshot fields +- [17fb12a5] Add method to find a CustomFieldDef by Key +- [bc395ef0] vscim: Implement UserDirectory +- [add0245e] vcsim: Add UpdateNetworkConfig to HostNetworkSystem +- [2aa746c6] vcsim: Implement virtual machine snapshot +- [104ddfb7] vcsim: set VirtualDisk backing datastore +- [f3f51c58] Add support for VM export +- [505b5c65] vcsim: Implement enter/exit maintenance mode +- [a1f8a328] vcsim: Implement add/remove license +- [585cf5e1] vcsim: add portgroup related operations +- [a7e79a7e] vcsim: add fields support +- [e2944227] vim25: Move internal stuff to internal package +- [c4cab690] Add support for SOAP request operation ID header +- [895573a5] vcsim: remove use of df program for datastore info +- [4dd9a518] Skip version check when using 6.7-dev API +- [cc2ed7db] Change optional ResourceAllocationInfo fields to pointers +- [3f145230] Use base type for DVS backing info +- [df1c3132] Add vm.console command +- [829b3f99] Fixup recent tasks output +- [c4e473af] Add '-refresh' option to host.storage.info +- [3df440c8] toolbox: avoid race when closing channels on stop +- [badad9a1] toolbox: reset session when invalidated by the vmx +- [a1a96c8f] Include "Name" in device.info -json +- [defe810c] vcsim: add FileQuery support to datastore search +- [93f62ef7] Default vm.migrate pool to the host pool +- [5fcca79e] vcsim: add HostConfigInfo template +- [4fea6863] govc: add tasks and task.cancel commands +- [596e51a0] Use ovf to import vmdk +- [920a70c1] vcsim: add HostSystem hardware property +- [9e2f8a78] Add info about maintenance mode in host.info +- [78f3fc19] Avoid panic if ova import task is canceled +- [11827c7a] toolbox: default to tar format for directory archives +- [8811f9bf] toolbox: make gzip optional for directory archive transfer +- [9703fe19] toolbox: avoid blocking the RPC channel when transferring process IO +- [d6f60304] Add view and filter support to object.collect command +- [3527a5f8] Tolerate repeated Close for file follower +- [ddd32366] govc: add reboot option to host.shutdown +- [4d9061ac] toolbox: use host management IP for guest file transfer +- [7d956b6b] toolbox: add Client Upload and Download methods +- [c7111c63] toolbox: support single file download via archive handler +- [ebb77d7c] Use vcsim in bats tests +- [4bb89668] vCenter cluster testbed automation +- [ad960e95] toolbox: SendGuestInfo before the vmx asks us to +- [bdea7ff3] toolbox: update vmw-guestinfo +- [51d12609] toolbox: remove receiver from DefaultStartCommand +- [114329fc] Add host thumbprint for use with guest file transfer +- [5083a277] Add FindByUuid method for Virtual Machine +- [e1ab84af] toolbox: map exec.ErrNotFound to vix.FileNotFound +- [d1091087] toolbox: pass URL to ArchiveHandler Read/Write methods +- [cddc353c] toolbox: make directory archive read/write customizable +- [ba6720ce] toolbox: add http and exec round trippers +- [b35abbc8] Handle object names containing a '/' +- [ac4891fb] toolbox: fix ListFiles when given a symlink +- [60a6510f] Minor correction in README.md +- [0c583dbc] toolbox: support transferring /proc files from guest +- [0833484e] vcsim: Fix merging of default devices +- [c9aaa3fa] Move toolbox from vmware/vic to govmomi +- [f6a734f5] vcsim: Add cdrom and scsi controller to Model VMs +- [9d47dd13] Move vcsim from vmware/vic to govmomi + + +## [Release v0.15.0](https://github.com/vmware/govmomi/compare/v0.14.0...v0.15.0) + +> Release Date: 2017-06-19 + +### ⚠️ BREAKING + +### 📖 Commits + +- [b63044e5] Release 0.15.0 +- [3d357ef2] Add dvs.portgroup.info usage +- [72977afb] Add support for guest.FileManager directory download +- [94837bf7] Update examples +- [e1bbcf52] Update wsdl generator +- [b16a3d81] fix the WaitOptions struct, MaxWaitSeconds is optional, but we can set the value 0 +- [9ca7a2b5] Support removal of ExtraConfig entries +- [86cc210c] Guest command updates +- [9c5f63e9] Doc updates +- [6d714f9e] New examples: datastores, hosts and virtualmachines using view package +- [f48e1151] update spew to be inline with testify +- [6f5c037c] Adjust message slice passed to include +- [48509bc3] Fix package name +- [6f635b73] Add host.shutdown command +- [67b13b52] Add doc on metric.sample instance flag ([#726](https://github.com/vmware/govmomi/issues/726)) +- [8bff8355] Fix tail n=0 case ([#725](https://github.com/vmware/govmomi/issues/725)) +- [10e6ced9] Update copyright ([#723](https://github.com/vmware/govmomi/issues/723)) +- [6f8ebd89] Allow caller to supply custom tail behavior ([#722](https://github.com/vmware/govmomi/issues/722)) +- [35caa01b] Add options to host.autostart.add ([#719](https://github.com/vmware/govmomi/issues/719)) +- [2030458d] Add VC options command ([#717](https://github.com/vmware/govmomi/issues/717)) +- [0ccad10c] Exported FindSnapshot() Method ([#715](https://github.com/vmware/govmomi/issues/715)) +- [34202aca] Additional wrapper functions for SPBM +- [c7f718b1] Add AuthorizationManager {Enable,Disable}Methods +- [d5e08cd2] Add PBM client and wrapper methods +- [58019ca9] Add generated types and methods for PBM +- [58960380] Regenerate against current vmodl.db +- [f736458f] Support non-Go clients in xml decoder + + +## [Release v0.14.0](https://github.com/vmware/govmomi/compare/v0.13.0...v0.14.0) + +> Release Date: 2017-04-08 + +### ⚠️ BREAKING + +### 📖 Commits + +- [9bfdc5ce] Release 0.14.0 +- [3ba0eba5] Release 0.13.0 +- [86063832] Add object.find command +- [0391e8eb] Adds FindManagedObject method. +- [796e87c8] Include embedded fields in object.collect output +- [2536e792] Use Duration flag for vm.ip -wait flag +- [3aa64170] Merge commit 'b0b51b50f40da2752c35266b7535b5bbbc8659e3' into marema31/govc-vm-ip-wait +- [59466881] Implement EthernetCardBackingInfo for OpaqueNetwork +- [0d2e1b22] Finder: support changing object root in find mode +- [9ded9d10] Add Bash completion script +- [3bd4ab46] Add QueryVirtualDiskInfo +- [16f6aa4f] Emacs: add metric select +- [3763321e] Add unit conversion to metric CSV +- [b0b51b50] Add -wait option to govc vm.ip to allow non-blocking query +- [f0d4774a] Add json support to metric ls and sample commands +- [c9de0310] Add performance manager and govc metric commands +- [d758f694] Add check for nil envelope +- [ab595fb3] Remove deferred Close() call in follower's Read() + + +## [Release v0.13.0](https://github.com/vmware/govmomi/compare/v0.12.1...v0.13.0) + +> Release Date: 2017-03-02 + +### 💫 `vcsim` (Simulator) + +- [5f7efaf1] esxcli FirewallInfo fixes ([#661](https://github.com/vmware/govmomi/issues/661)) + +### ⚠️ BREAKING + +### 📖 Commits + +- [b4a3f7a1] Release 0.13.0 +- [5bf03cb4] Add vm.guest.tools command +- [b4ef3b73] Host is optional for MarkAsVirtualMachine ([#675](https://github.com/vmware/govmomi/issues/675)) +- [f4a3ffe5] Add vsan and disk commands / helpers ([#672](https://github.com/vmware/govmomi/issues/672)) +- [1f82c282] Handle the case where e.VirtualSystem is nil ([#671](https://github.com/vmware/govmomi/issues/671)) +- [dd346974] Remove object.ListView ([#669](https://github.com/vmware/govmomi/issues/669)) +- [4994038a] Wraps the ContainerView managed object. ([#667](https://github.com/vmware/govmomi/issues/667)) +- [93064c06] Handle nil TaskInfo in task.Wait callback [#2](https://github.com/vmware/govmomi/issues/2) ([#666](https://github.com/vmware/govmomi/issues/666)) +- [f1f5b6cb] Handle nil TaskInfo in task.Wait callback ([#665](https://github.com/vmware/govmomi/issues/665)) +- [f3cf126d] Support alternative './...' syntax for finder ([#664](https://github.com/vmware/govmomi/issues/664)) +- [9bda6c3e] Finder: support automatic Folder recursion ([#663](https://github.com/vmware/govmomi/issues/663)) +- [0a28e595] Add a command line option to change an existing disk attached to a VM ([#658](https://github.com/vmware/govmomi/issues/658)) +- [3e95cb11] Attach and list RDM/LUN ([#656](https://github.com/vmware/govmomi/issues/656)) +- [5f7efaf1] vcsim: esxcli FirewallInfo fixes ([#661](https://github.com/vmware/govmomi/issues/661)) +- [17e6545f] Add device option to WaitForNetIP ([#660](https://github.com/vmware/govmomi/issues/660)) +- [ba9e3f44] Fix vm.change test +- [e66c8344] Add the option to describe a VM using the annotation option in ConfigSpec ([#657](https://github.com/vmware/govmomi/issues/657)) +- [505fcf9c] Update doc +- [913c0eb4] Add support for reading and changing SyncTimeWithHost option ([#539](https://github.com/vmware/govmomi/issues/539)) +- [682494e1] Remove _Task suffix from vapp methods +- [733acc9e] Emacs: add govc-command-history +- [ea52d587] Add object.collect command ([#652](https://github.com/vmware/govmomi/issues/652)) +- [f49782a8] Update email address for contributor Bruce Downs + + +## [Release v0.12.1](https://github.com/vmware/govmomi/compare/v0.12.0...v0.12.1) + +> Release Date: 2016-12-19 + +### ⚠️ BREAKING + +### 📖 Commits + +- [6103db21] Release 0.12.1 +- [45a53517] Note 6.5 support +- [fec40b21] Add '-f' flag to logs command ([#643](https://github.com/vmware/govmomi/issues/643)) +- [40cf9f80] govc.el: auth-source integration ([#648](https://github.com/vmware/govmomi/issues/648)) +- [ca99f8de] Add govc-command customization option ([#645](https://github.com/vmware/govmomi/issues/645)) +- [ad6e5634] Avoid Finder panic when SetDatacenter is not called ([#640](https://github.com/vmware/govmomi/issues/640)) +- [b5c807e3] Add storage support to vm.migrate ([#641](https://github.com/vmware/govmomi/issues/641)) +- [1a7dc61e] govc/version: skip first char in git version mismatch error ([#642](https://github.com/vmware/govmomi/issues/642)) +- [6bc730e1] Add Slack links +- [e152c355] Add DatastorePath helper ([#638](https://github.com/vmware/govmomi/issues/638)) +- [5b4d5215] Add support for file backed serialport devices ([#637](https://github.com/vmware/govmomi/issues/637)) +- [f49bd564] Add vm.ip docs ([#636](https://github.com/vmware/govmomi/issues/636)) + + +## [Release v0.12.0](https://github.com/vmware/govmomi/compare/v0.11.4...v0.12.0) + +> Release Date: 2016-12-01 + +### ⚠️ BREAKING + +### 📖 Commits + +- [ab40ac73] Release 0.12.0 +- [e702e188] Disable use of service ticket for datastore HTTP access by default ([#635](https://github.com/vmware/govmomi/issues/635)) +- [1fba1af7] Attach context to HTTP requests for cancellations +- [79cb3d93] Support InjectOvfEnv without PowerOn when importing +- [117118a2] Support stdin as import options source +- [b10f20f4] Don't ignore version/manifest for existing sessions +- [82929d3f] Add basic VirtualNVMEController support +- [757a2d6d] re-generate vim25 using 6.5.0 + + +## [Release v0.11.4](https://github.com/vmware/govmomi/compare/v0.11.3...v0.11.4) + +> Release Date: 2016-11-15 + +### ⚠️ BREAKING + +### 📖 Commits + +- [b9bcc6f4] Release 0.11.4 +- [dbbf84e8] Add authz role helpers and commands +- [765b34dc] Add folder/pod examples +- [79cb52fd] Add host.account examples +- [2a2cab2a] Add host.portgroup.change examples + + +## [Release v0.11.3](https://github.com/vmware/govmomi/compare/v0.11.2...v0.11.3) + +> Release Date: 2016-11-08 + +### ⚠️ BREAKING + +### 📖 Commits + +- [e16673dd] Release 0.11.3 +- [629a573f] Add -product-version flag to dvs.create +- [83028634] Allow DatastoreFile follower to drain current body + + +## [Release v0.11.2](https://github.com/vmware/govmomi/compare/v0.11.1...v0.11.2) + +> Release Date: 2016-11-01 + +### ⚠️ BREAKING + +### 📖 Commits + +- [cd80b8e8] Release 0.11.2 +- [f15dcbdc] Avoid possible NPE in VirtualMachine.Device method +- [128b352e] Add support for OpaqueNetwork type +- [c5b9a266] Add host account manager support for 5.5 + + +## [Release v0.11.1](https://github.com/vmware/govmomi/compare/v0.11.0...v0.11.1) + +> Release Date: 2016-10-27 + +### ⚠️ BREAKING + +### 📖 Commits + +- [1a7df5e3] Release 0.11.1 +- [1ae858d1] Add support for VirtualApp in pool.change command +- [91b2ad48] Release script tweaks + + +## [Release v0.11.0](https://github.com/vmware/govmomi/compare/v0.10.0...v0.11.0) + +> Release Date: 2016-10-25 + +### ⚠️ BREAKING + +### 📖 Commits + +- [a16901d7] Release 0.11.0 +- [4fc9deb4] Add object destroy and rename commands +- [82634835] Add dvs.portgroup.change command + + +## [Release v0.10.0](https://github.com/vmware/govmomi/compare/v0.9.0...v0.10.0) + +> Release Date: 2016-10-20 + +### ⚠️ BREAKING + +### 📖 Commits + +- [bb498f73] Release 0.10.0 +- [468a15af] Release script updates +- [1c3499c4] Documentation updates +- [1e52d88a] Update contributors +- [e3d59fd9] Fix snapshot.tree on vm with no snapshots +- [711fdd9c] Add host.date info and change commands +- [16d7514a] Add govc session ls and rm commands +- [73c471a9] Add HostConfigManager field checks +- [d7f94557] Improve cluster/host add thumbprint support +- [fea8955b] Add session.Locale var to change default locale +- [eefe6cc1] Add service ticket thumbprint validation +- [3a0a61a6] Set default locale to en_US +- [aa1a9a84] TLS enhancements +- [9f0e9654] Treat DatastoreFile follower Close as "stop" +- [838b2efa] Support typeattr for enum string types +- [dcbc9d56] Make vm.ip esxcli test optional +- [9e20e0ae] Remove vca references +- [7c708b2e] Adding vSPC proxyURI to govc + + +## [Release v0.9.0](https://github.com/vmware/govmomi/compare/v0.8.0...v0.9.0) + +> Release Date: 2016-09-09 + +### ⚠️ BREAKING + +### 📖 Commits + +- [f9184c1d] Release 0.9.0 +- [e050cb6d] Add govc -h flag +- [a4343ea8] Set default ScsiCtlrUnitNumber +- [a920d73d] Add -R option to datastore.ls +- [f517decc] Fix SCSI device unit number selection +- [abaf7597] Add DatastoreFile helpers +- [7cfa7491] Make Datastore ServiceTicket optional +- [9ad57862] Add vm.migrate command +- [c66458f9] Add govc vm.{un}register commands +- [54c0c6e5] Checking result of reflect.TypeOf is not nil before continuing +- [ea0189ea] Fix flags.NewOptionalBool panic +- [a9cdf437] Add govc guest command tests +- [38dee111] Add VirtualMachine.Unregister func +- [98b50d49] make curl follow HTTP redirects +- [8a27691f] make goreportcard happy +- [bf66f750] Add govc vm snapshot commands +- [eb02131a] Validate vm.clone -vm flag value +- [62159d11] Add device.usb.add command +- [27e02431] Remove a bunch of context.TODO() calls. +- [a9cee43a] Fixing tailing for events command +- [4fa7b32a] Bump to 1.7 and start using new context pkg +- [4b7c59bf] Fix missing datastore name with vm.clone -force=false +- [e3642fce] Fix deletion of powered off vApp +- [63d60025] Support stdin/stdout in datastore upload/download +- [e149909e] Emacs: add govc-session-network +- [0ccc1788] Emacs: add govc json diff +- [f1d6e127] Add host.portgroup.change command +- [6f441a84] Add host.portgroup.info command +- [aaf40729] Add HostNetworkPolicy to host.vswitch.info +- [5ccb0572] Add json support to host.vswitch.info command +- [9d19d1f7] Support instance uuid in SearchFlag +- [2d3bfc9f] Add json support to esxcli command +- [bac04959] Support multiple NICs with vm.ip -esxcli +- [b3177d23] Add -unclaimed flag to host.storage.info command +- [b1234a90] govc - popualte 'Path' fiels in xxx.info output +- [7cab0ab6] Implemented additional ListView methods +- [498cb97d] Add 'Annotation' attribute to importx options. +- [223168f0] Add NetworkMapping section to importx options. +- [5c708f6b] Remove vendor target from the Makefile +- [f8199eb8] Handle errors in QueryVirtualDiskUUid function ([#548](https://github.com/vmware/govmomi/issues/548)) +- [73dcde2c] vendor github.com/davecgh/go-spew/spew +- [e1e407f7] vendor golang.org/x/net/context +- [e3c3cd0a] Populate network mapping from ovf envelope ([#546](https://github.com/vmware/govmomi/issues/546)) +- [fa6668dc] Add QueryVirtualDiskUuid function ([#545](https://github.com/vmware/govmomi/issues/545)) +- [17682d5b] Fixes panic in govc events + + +## [Release v0.8.0](https://github.com/vmware/govmomi/compare/v0.7.1...v0.8.0) + +> Release Date: 2016-06-30 + +### ⚠️ BREAKING + +### 📖 Commits + +- [c0c7ce63] Release 0.8.0 +- [ce4b0be6] Disable datastore service ticket hostname usage +- [3e44fe88] Add support for login via local ticket +- [acf37905] Add StoragePod support to govc folder.create +- [94d4e2c9] Include StoragePod in Finder.FolderList +- [473f3885] Avoid use of eval with govc env +- [4fb7ad2e] Add datacenter.create folder option +- [77ea6f88] Avoid vm.info panic against vcsim +- [95b2bc4d] Session persistence improvements +- [720bbd10] Add type attribute to soap.Fault Detail +- [ff7b5b0d] Add filtering for use of datastore service ticket +- [fe9d7b52] Add support for Finder lookup via moref +- [c26c7976] Use ticket HostName for Datastore http access +- [bea2a43c] Add govc/vm.markasvm command +- [9101528d] Add govc/vm.markastemplate command +- [982e64b8] Add vm.markastemplate + + +## [Release v0.7.1](https://github.com/vmware/govmomi/compare/v0.7.0...v0.7.1) + +> Release Date: 2016-06-03 + +### ⚠️ BREAKING + +### 📖 Commits + +- [2cad28d0] Fix Datastore upload/download against VC + + +## [Release v0.7.0](https://github.com/vmware/govmomi/compare/v0.6.2...v0.7.0) + +> Release Date: 2016-06-02 + +### ⚠️ BREAKING + +### 📖 Commits + +- [6906d301] Release 0.7.0 +- [558321df] Move InventoryPath field to object.Common +- [4147a6ae] Add -require flag to govc version command +- [d9fd9a4b] Add support for local type in datastore.create +- [650b5800] Fix vm.create disk scsi controller lookup +- [9463b5e5] Update changelog for govc to add datastore -namespace flag +- [4aab41b8] Update changelog with DatastoreNamespaceManager methods +- [4d6ea358] Support mkdir/rm of namespace on vsan +- [bb7e2fd7] InjectOvfEnv() should work with VSphere +- [91ca6bd5] Add host.service command +- [2f369a29] Add host.storage.mark command +- [b001e05b] Add -rescan option to host.storage.info command + + +## [Release v0.6.2](https://github.com/vmware/govmomi/compare/v0.6.1...v0.6.2) + +> Release Date: 2016-05-13 + +### ⚠️ BREAKING + +### 📖 Commits + +- [9051bd6b] Release 0.6.2 +- [3ab0d9b2] Get complete file details in Datastore.Stat +- [0c21607e] Convert types when possible +- [648d945a] Avoid xsi:type overwriting type attribute +- [4e0680c1] adding remove all snapshots to vm objects + + +## [Release v0.6.1](https://github.com/vmware/govmomi/compare/v0.6.0...v0.6.1) + +> Release Date: 2016-04-30 + +### ⚠️ BREAKING + +### 📖 Commits + +- [18154e51] Release 0.6.1 +- [47098806] Fix mo.Entity interface + + +## [Release v0.6.0](https://github.com/vmware/govmomi/compare/v0.5.0...v0.6.0) + +> Release Date: 2016-04-29 + +### ⚠️ BREAKING + +### 📖 Commits + +- [2c1d977a] Release 0.6.0 +- [cc686c51] Add folder.moveinto command +- [8e85a8d2] Add folder.{create,destroy,rename} methods +- [0ba22d24] Add Common.Rename method +- [61792ed3] Fix Finder.FolderList check +- [b6be92a1] Restore optional DatacenterFlag +- [53903a3a] Add OutputFlag support to govc about command +- [e66f7793] Add OptionManager and host.option commands +- [9d69fe4b] Add debug xmlformat script +- [f1786bec] Add option to use the same path for debug runs +- [99c8c5eb] Add folder.info command +- [eca4105a] Add datacenter.info command +- [71484c40] Add mo.Entity interface +- [388df2f1] Add helper to wait for multiple VM IPs +- [fc9f58d0] Add RevertToSnapshot +- [a4aca111] Add govc env command +- [ef17f4bd] Update CI config +- [fa91a600] Add host.account commands +- [44bb6d06] Update release install instructions +- [08ba4835] Leave AddressType empty in EthernetCardTypes +- [f9704e39] Add vm clone +- [e6969120] Add datastore.Download method +- [1aca660c] device.remove: add keep option + + +## [Release v0.5.0](https://github.com/vmware/govmomi/compare/v0.4.0...v0.5.0) + +> Release Date: 2016-03-30 + +### ⚠️ BREAKING + +### 📖 Commits + +- [c1b29993] Release 0.5.0 +- [b8549681] Use VirtualDeviceList for import.vmdk +- [cf96f70d] Remove debug flags from pool tests +- [f74a896d] Switch to int32 type for xsd int fields +- [074494df] Regenerate against 6.0u2 wsdl +- [ce9314c4] Include license header in generated files +- [957c8827] Add pointer field white list to generator +- [2c1d1950] Change pool recusive destroy to children destroy +- [5d34409f] Add dvs.portgroup.info command +- [216031c3] Update docs +- [f7dfcc98] Remove govc-test pools in teardown hook +- [556a9b17] Simplify pool destroy test +- [4e47b140] Add folder management to vm.create +- [7c33bcb3] Update test ESX IP in Drone secrets file +- [1b6ec477] Regenerate Drone secrets file +- [f64ea833] Implemented the ablitiy to tail the vSphere event stream - govc tail and force flag added to events command +- [fd7d320f] Including github.com/davecgh/go-spew/spew in go get +- [1d4efec0] Including github.com/davecgh/go-spew/spew in go get +- [424d3611] The -dump option now requests a recursive traversal as -json does +- [b45747f3] Added new -dump output flag for pretty printing underlying objects using davecgh/go-spew +- [a243716c] Run govc tests against ESX using Drone +- [fb75c63e] Double quotes network name to prevent space in name from failing the tests +- [564944ba] test_helper.bash updated to conditionally set env variables +- [c9c6e38f] Added new govc vm.disk.create -mode option for selecting one the VirtualDiskMode types +- [6922c88b] Add -net flag to device.info command +- [dff2c197] Fix VirtualDeviceList.CreateFloppy +- [c7d8cd3e] Ran gofmt on create.go +- [e077bcf5] Fix issue with optional UnitNumber (v2) +- [539ad504] Added arguments to govc vm.disk.create for thick provisioning and eager scrubbing, as requested in issue [#254](https://github.com/vmware/govmomi/issues/254) +- [e66c6df9] Handle import statement for types too +- [265d8bdb] Remove hardcoded urn:vim25 value from vim_wsdl.rb + + +## [Release v0.4.0](https://github.com/vmware/govmomi/compare/v0.3.0...v0.4.0) + +> Release Date: 2016-02-26 + +### ⚠️ BREAKING + +### 📖 Commits + +- [b3d202ab] Release 0.4.0 +- [749da321] Fix vm.change's ExtraConfig values being truncated at equal signs +- [13fbc59d] Add switch to specify protocol version in SOAPAction header +- [07013a97] Update CHANGELOG +- [bfe414fe] Allow vm.create to take datastore cluster argument +- [dda71761] Include reference to datastore in CreateDisk +- [855abdb3] Make NewKey function public +- [d0031106] Use custom datastore flags in vm.create +- [306b613d] Modify govc's vm.create to create VM in one shot +- [e96130b4] Add extra datastore arguments to vm.create +- [0a2da16d] Add datastore cluster methods to finder +- [c69e9bc1] Allow StoragePod type to be traversed +- [4d2ea3f4] added explicit path during clone +- [3d8eb102] Update missing property whitelist +- [779ae0a1] re-generate vim25 using 6.0 Update 1b (vimbase [#3024326](https://github.com/vmware/govmomi/issues/3024326)) +- [53c29f6a] Handle import statements same as include +- [a738f89d] Update govc.el URL +- [da2a249e] Doc updates +- [47e46425] govc.el: minor fixes for distribution as a package +- [8459ceb9] handle GOVC_TEST_URL=user:pass[@IP](https://github.com/IP) pattern +- [3b669760] Add Emacs interface to govc +- [7ec8028d] Update README to include Drone build status and local build instructions +- [2ec65fbe] Add config for Drone CI build +- [5437c466] introduce Datastore.Type() +- [983571af] introduce IsVC method and start using it +- [0732f137] Introduce AttachedClusterHosts +- [18945281] start using new helper functions for govc/flags +- [044d904a] Add some common functions to find/finder.go +- [534dabbd] Support vapp in pool.info command +- [4d9c6c72] Fix bats tests +- [5e04d5ca] Add -p and -a options to govc datastore.ls command +- [33963263] Added check for missing ovf deployment section + + +## [Release v0.3.0](https://github.com/vmware/govmomi/compare/v0.2.0...v0.3.0) + +> Release Date: 2016-01-15 + +### ⚠️ BREAKING + +### 📖 Commits + +- [501f6106] Mark 0.3.0 in change log +- [83a26512] Update contributors +- [995d970f] Print os.Args[0] in error messages +- [0a4c9782] Move stat function to object.Datastore +- [8a0d4217] Support VirtualApp in the lister +- [82734ef3] Support empty folder in SearchFlag.VirtualMachines +- [f64f878f] Add support for custom session keep alive handler +- [2d498658] Use OptionalBool for ExpandableReservation +- [ac9a39b0] Script to capture vpxd traffic on VCSA +- [3f473628] Script to capture and decrypt hostd SOAP traffic +- [eccc3e21] Move govc url.Parse wrapper to soap.ParseURL +- [e1031f44] Don't assume sshClient firewall rule is disabled +- [cd5d8baa] Let the lister recurse into a ComputeHost +- [b601a586] Specify the new entity's name upon import +- [a5e26981] Explicitly instantiate and register flags +- [aca77c67] Parameterize datastore in VM tests +- [37324472] Pass context to command and flag functions +- [6f955173] Minor optimization to encoding usage +- [0f4aee8b] Create VMFS datastore with datastore.create +- [ec724783] Add host storage commands +- [debdd854] Run license script +- [64022512] Fix license script to work for uncommitted files +- [5cb0c344] Remove host reference from HostFirewallSystem +- [4fb4052a] Change the comment that mentions ha-datacenter +- [b76ad0eb] Let the ESXi to figure out datastore name +- [918188dc] Add helper method to get VM power state +- [29a2f027] Add permissions.{ls,set,remove} commands +- [f27787a1] Add DatacenterFlag.ManagedObjects helper +- [0e629647] Option to disable API version check +- [42d899d0] Add commands to add and remove datastores +- [369e0e7f] Check host state in Datastore.AttachedHosts +- [7adf8375] Test that vm.info -r prints mo names +- [3198242e] Change ComputeResource.Hosts to return HostSystem +- [b34f346e] Support property collection for embedded types +- [8035c180] Fix vm nested hv option +- [b1d9d3c2] Update copyright years in code headers +- [c99e7bac] Add dvs commands +- [c30b7f17] Support DVS lookup in finder +- [094fbdfe] Embed Reference interface in NetworkReference +- [0657cf76] Add DVS helpers +- [6e96a1db] Add host.vnic.{service,info} commands +- [ae6b0b77] Add VsanSystem and VirtualNicManager wrappers +- [24297494] Add vsan flags to cluster.change command +- [4088502d] Add license.assigned.list id flag +- [d089489e] Add cluster.add license flag +- [31ee6e03] Add vm.change options to set hv/mmu +- [a414852e] Refactor host.add command to use HostConnectFlag +- [51543392] Add cluster.{create,change,add} commands +- [8262e1da] Add cluster related host commands +- [2443b364] Add HostConnectFlag +- [8ae7da82] Add object.HostSystem methods +- [0f630dd9] Add finder.Folder method +- [7cd5fbb5] Add bash function to save/load GOVC environments +- [12f26c21] Add object.Common.Destroy method +- [2ab8aa59] Add ComputeResource.Reconfigure method +- [5f47f155] Add flags.NewOptionalBool +- [25fe42b2] Add -feature flag to license list commands +- [2e6c0476] Add license.InfoList list wrapper +- [ef7371af] Add license assignment commands +- [5005e6e4] Add license.AssignmentManager +- [69a23bd4] Use object.Common in license.Manager +- [dbce3faf] Rename receiver variable for consistency +- [80705c11] Pass pointer to bps uint64 in last progress report +- [26e77c8e] VirtualMachine: Add Customize function on object.VirtualMachine +- [c2a78973] Add license.decode command +- [b3a7e07e] Add DistributedVirtualPortgroup support to vm.info +- [1b11ad02] Fix KeepAlive +- [3ecfd0db] Add HostFirewallSystem wrapper +- [9ded9c1a] KeepAlive support with certificate based login +- [cf2a879b] Add DiagnosticManager and logs commands +- [7b14760a] Update README.md +- [ad694500] Export Datastore.ServiceTicket method +- [76690239] Added a method to create snapshot of a virtual machine +- [6d4932af] Use service ticket for datastore file access +- [5fcc29f6] Fix vcsa ssh config +- [ac390ec8] Retry on empty result from property collector +- [f3041b2c] Add methods for client certificate based auth +- [b9edc663] Add extension manager and govc commands +- [9057659c] Fix key composition in building OVF spec +- [f56f6e80] Move OVF environment related code to env{,test}.go +- [b33c9aef] Add minimal doc to ovf package +- [3d40aefb] Added verbose option to the import.spec feature +- [1df0a81d] change for looking up a VM using instanceUUID +- [5f4d36cd] Introduce govc vapp.{info|destroy|power} +- [88795252] Handle the import.spec case where no spec file is provided +- [bcdc53fb] Add inventory path to govc info commands +- [305371a8] Collect govc host and pool info in one call +- [bfd47026] Relax the convention around importing an ova +- [3742a8aa] don't start goroutine while context is nil + + +## [Release v0.2.0](https://github.com/vmware/govmomi/compare/v0.1.0...v0.2.0) + +> Release Date: 2015-09-15 + +### ⏮ Reverts + +- [2900f2ff] Add Host information to vm.info +- [8bec13f7] Fix git dirty status error in build script + +### ⚠️ BREAKING + +### 📖 Commits + +- [b3315079] Mark 0.2.0 in change log +- [cc3bcbee] Add mode argument to release script +- [ae4a6e53] Build govc with new cross compilation facilities +- [4708d165] Derive CONTRIBUTORS from commit history +- [00909f48] Move contrib/ -> scripts/ +- [a0f4f799] Capitalization +- [13baa0e4] Split import functionality into independent flags +- [6363d0e2] Added ovf.Property output to import.spec +- [7af121df] Update change log +- [f9deb385] Fix event.Manager category cache +- [7f0a892d] Avoid tabwriter in events command +- [29601b46] Use vm.power force flag for hard shutdown/reboot +- [ea833cf5] Add VirtualDiskManager CreateVirtualDisk wrapper +- [bfabd01d] Interative clean up of bats testing +- [7cba62d9] Clean up of vcsa creation script +- [631d6228] Add serial port URI info to device.info output +- [0b31dcff] Add -json support to device.info command +- [54e324d1] Add govc vm.info resources option +- [9cc5d8f5] Add helper method to wait for virtual machine power state. +- [9ddd6337] Remove superfluous math.Pow calculations +- [5272b1e9] Added common method of humanizing byte strings +- [3145d146] Add helper method to check if VMware Tools is running in the guest OS. +- [e4f4c737] Misc clean up +- [01f2aed0] Add host name to vm.info +- [f24ec75a] Use property.Collector.Retrieve() in vm.info +- [a779c3b7] Renamed vm.info VmInfos back to VirtualMachines +- [2900f2ff] Revert "Add Host information to vm.info" +- [2a567478] Add -hints option to host.esxcli command +- [1f0708e2] Add options to importing an ovf or and ova file +- [debde780] Only retrieve "currentSession" property +- [b5187c16] Update CONTRIBUTORS +- [3e4ced8c] Added the ability to specify ovf properties during deployment +- [688a6b18] Introduce more VirtualApp methods +- [b1f0cb0c] Add flag to specify destination folder for import.ovf and import.ova +- [c9fcf1ce] Add check for error reading ova file +- [edb0a2cf] clone vmware/rbvmomi repo if it's missing +- [40c26fc6] use e.Object.Reference().Type as suggested by Doug +- [c1442f95] introduce CreateVApp and CreateChildVM_Task +- [25405362] add VirtualAppList and VirtualApp methods to Finder +- [121f075c] Add CustomFieldsManager wrapper and cli commands +- [dd016de3] include VirtualApp in ls -l output +- [b5db4d6d] Provide ability to override url username and password +- [11d5ae9c] Add OVF unmarshalling +- [135569e7] Update travis.yml for new infra +- [822432eb] Make govet stop complaining +- [baf9149e] Add datastore.info cli command +- [2b93c199] Add serial port matcher to SelectByBackingInfo +- [26ba22de] Merge branch 'gavrie-master' +- [62591576] Add Host information to vm.info +- [a90019ab] Add methods for useful properties to VirtualMachine +- [502963c4] Add Relocate method to VirtualMachine +- [7f4b6d38] Add String method to objects for pretty printing +- [99f57f16] Add events helpers and cli command +- [4c989ac3] Update CONTRIBUTORS +- [ad7d1917] Update to vim25/6.0 API +- [ad39adb9] Add net.address flag +- [e01555f9] Add command to add host to datacenter +- [efbd3293] Stop returning children from `ManagedObjectList` +- [d16670f5] Update CONTRIBUTORS +- [97fbf898] Mention GOVC_USERNAME and GOVC_PASSWORD in CHANGELOG +- [8766bda0] Add test to check for flag name collisions +- [791b3365] Remove flags for overriding username and password +- [85957949] include GOVC_USERNAME and GOVC_PASSWORD in govc README +- [8584259a] Export variables in release script +- [14889008] Add test for GOVC_USERNAME and GOVC_PASSWORD +- [c0a984cd] Only run license tests against evaluation license +- [293ac813] Allow override of username and password +- [e053bdf2] Add extraConfig option to vm.change and vm.info +- [1dec0695] Update CONTRIBUTORS +- [1acf418c] Add Usage for host.esxcli +- [2e00fdb1] Modify archive.go bug +- [985291d5] Add missing types to list.ToElement +- [871f5d4f] Add script to create a draft prerelease +- [8bec13f7] Revert "Fix git dirty status error in build script" +- [c825a3c7] Only use annotated tags to describe a version +- [66320cb0] Retry twice on temporary network errors in govc +- [67be5f1d] Add retry functionality to vim25 package +- [fba0548b] Add method to destroy a compute resource +- [2add2f7a] Add methods to add standalone or clustered hosts +- [de297fcb] Add ability to create, read and modify clusters +- [f10480af] Change finder functions to no longer take varargs +- [4bc93a66] Fix resource pool creation/modification +- [b434a9a8] Rename persist flag to persist-session +- [d85ad215] Ignore ManagedObjectNotFound in list results +- [4c497373] Add example that lists datastores +- [5d153787] Update govc CHANGELOG +- [0165e2de] Add flag to toggle persisting session to disk +- [8acb2f28] Add Mevan to CONTRIBUTORS +- [add15217] Ignore missing environmentBrowser field +- [447d18cd] Fix error when using SDRS datastores +- [e85f6d59] Find ComputeResource objects with find package +- [55f984e8] Test package only depends on vim25 +- [dbe47230] Drop omitempty tag from optional pointer fields +- [749f0bfa] Interpret negative values for unsigned fields +- [49a34992] Update CHANGELOG +- [263780f3] Update code to work with bool pointer fields +- [93aad8da] Make optional bool fields pointers +- [b7c51f61] Return errors for unexpected HTTP statuses +- [62ca329a] Abort client tests on errors +- [ae345e7f] Rename LICENSE file +- [a783a8c6] Add govc CHANGELOG +- [ba707586] Add commands to configure the autostart manager +- [af6a188e] Re-enable search index test +- [ceea450c] Update govc README +- [ea5c9a52] Fix git dirty status error in build script + + +## v0.1.0 + +> Release Date: 2015-03-17 + +### ⚠️ BREAKING + +### 📖 Commits + +- [477dcaf9] Cross-compile govc using gox +- [8593d9c7] Add version variable that can be set by the linker +- [fb38ca45] Add CHANGELOG +- [76f8f1a1] Add package docs to client.go +- [27bf35df] Use context.Context in client in root package +- [f3b8162f] Comment out broken test +- [a1d9d1e7] Drop the _gen filename suffix +- [91650a1f] Add context.Context argument to object package +- [1814113a] Use vim25.Client throughout codebase +- [b977114e] Move property retrieval functions to property package +- [8c3243d8] Add lightweight client structure to vim25 package +- [ec4b5b85] Add context.Context argument to find/list packages +- [7eecfbc7] Make Wait function in property package standalone +- [6c1982c8] Add keep alive for soap.RoundTripper +- [1324d1f0] Return nil UserSession when not authenticated +- [ae7ea3dd] Comments for task.Wait +- [a53a6b2c] Add context parameter to object.Task functions +- [f6f44097] Move functionality to wait for task to new package +- [ad2303cf] Move Ancestors function to vim25/mo +- [fb9e1439] Move PropertyCollector to new property package +- [a6618591] Move Reference to vim25/mo +- [bfdb90f1] Bind virtual machine to guest operation wrappers +- [ec0c16a7] Move HasFault to vim25/types +- [683ca537] Move wrappers for managed objects to object package +- [223a07f8] Add GetServiceContent function to vim25/soap +- [25b07674] Decouple factory functions from client +- [b96cf609] Move SessionManager to new session package +- [ea8d5d11] Return on error in SessionManager +- [7d58a49e] Mutate copy of parameter instead of parameter itself +- [e158fd95] Marshal soap.Client instead of govmomi.Client +- [1336ad45] Embed soap.Client in govmomi.Client +- [15cfd514] Work with pointer to url.URL +- [be2936f8] Move guest related wrappers to new guest package +- [b772ba28] Move LicenseManager to new license package +- [7ac1477f] Move EventManager to new event package +- [2053e065] Retrieve dependencies before running test +- [2d14321e] Add context.Context argument to RoundTripper +- [64f716b2] Include type of request in summarized debug log +- [40249c87] Store reference to http.Transport +- [ac77f0c5] Move debugging code in soap.Client to own struct +- [c8fab31b] Loosen .ovf match in ova.import +- [9f685e92] And further fixing the merge... go fmt. +- [8dbb438b] Merge remote-tracking branch 'upstream/master' into event_manager +- [e57a557c] created session manager wrapper +- [5525d5c6] Change return pattern in CreateDatacenter +- [8acd5512] Update contributors +- [7138d375] Coding style consistency +- [951e9194] added SessionIsActive to Client +- [2211e73d] Add CreateFolder method +- [eef40cc0] Add Login/Logout functions to client struct +- [3c7dea04] Update contributors +- [9c4a9202] Fixed error when attempting to access datastore +- [05ee0e62] Add PropertiesN function on client struct +- [01ee2fd5] Adding EventManager so that events can be queried for +- [8d10cfc7] Restrict permissions on session file +- [88b5d03c] Key session file off of entire URL +- [9354d314] Error types for getter functions on finder +- [a30287dc] Add description for pool.create +- [77466af0] Prefix option list in help output +- [cbb8d0b2] Create multiple resource pools through pool.create +- [8d4699d8] Add usage and description for pool.destroy +- [2e195a92] Change pool.change to take multiple arguments +- [38e4a2b2] Add usage and description for pool.info +- [2f286768] Add usage and description for pool.create +- [413fa901] Set insert_key = false +- [d6c2b33e] Update travis.yml +- [b878c20a] Adding CustomizationSpecManager +- [7c8f3e56] Add vm mark as vm and mark as template features +- [033d02e9] Update contributors +- [18919172] Add cpu and memory usage to host.info +- [b29f93c1] Adding the RegisterVM task. +- [e6bf8bb5] Add error types for Finder +- [852578b9] Support multiple hosts in host.info command +- [f1899c63] Set InventoryPath field +- [3a5c1cf3] Add InventoryPath field +- [624f21a4] Add resource pool cli commands +- [4c7cd61f] Add ResourcePool wrapper methods +- [761d43e5] Include ResourcePool in ls -l output +- [d2daf706] Support nested resource pools in lister +- [4d9d9a72] Add vm.change cli command +- [e6ebcd7f] bats fixup: destroy datacenter +- [65838131] Disable vcsa box password expiration +- [7a6e737b] Add CONTRIBUTORS file +- [1cbe968d] Issue [#192](https://github.com/vmware/govmomi/issues/192): HostSystem doesn't seem to be returning the correct host. +- [116a4044] fix a problem of ignored https_proxy environment variable with https scheme +- [df423c32] Add create and destroy datacenter to govc. +- [035bd12c] Usage for devices.{cdrom,floppy}.* +- [68e50dd3] make storage resource manager +- [b28d6f42] Specify default network in test helper +- [4b388e67] Fix boot order test +- [4414a07e] Expand vm.vnc command +- [e329e6e7] rename the session file for windows naming check +- [706520fa] use filepath for filesystem related path operations +- [ceb35f13] Add -f flag to datastore.rm +- [6498890f] Default VM memory to 1GiB +- [591b74f4] Include description for device.cdrom commands +- [815f0286] Add usage to device.cdrom.insert +- [f2209c2b] Flag description casing +- [5e52668c] Add usage to import commands +- [23cf4d35] Expand datastore.ls +- [bca8ef73] Expose underlying VimFault through Fault() function +- [90edb2bc] Add Usage() function to subset of commands +- [afdc145a] Implement subset of license manager +- [14765d07] Add net.adapter option to network flag +- [18c2cce0] Add CreateEthernetCard method +- [9b2730f0] Don't run vm.destroy if there is no input +- [611ced85] Add new ops to vm.power command +- [6cd9f466] Add VM power ops +- [7918063c] Work on README +- [db17cddd] Check minimum API version from client flag +- [df075430] Don't run datastore.rm if there is no input +- [e49a6d57] Move environment variables names into constants +- [2cfe267f] Add device.scsi command +- [6df44c1a] Support scsi disk.controller type in vm.create +- [39a60bbf] Add CreateSCSIController method +- [136fabe5] Rename vm.create disk.adapter to disk.controller +- [9c51314c] Change disk related commands to use new helpers +- [b0c895e5] Add VirtualDisk support to device helpers +- [a00f4545] Add helpers for creating disks +- [16283936] Add FindDiskController helper +- [dda056dc] Add VirtualDeviceList.FindSCSIController method +- [5402017a] FindByBackingInfo -> SelectByBackingInfo +- [0ff5759c] Add vm disk related bats tests +- [8f1e183a] Output disk file backing in device.info +- [e7cfba4b] Remove datastore test files +- [6b883be5] Use DeviceAdd helper in vm.network.add command +- [eb5881ae] Use device name in vm.network.change command +- [b7503468] Remove vm.network.remove command +- [0b81619a] Add vm.network.change cli command +- [0af5c4cf] Use VirtualDeviceList helpers in vm.network.remove +- [94c62da0] Add VirtualDeviceList FindByBackingInfo method +- [c247b80c] Move govc resource finders to govmomi/find package +- [5f0c8dd4] Add vm.info bats test +- [5d99454d] mv govc/flags/list -> govmomi/list +- [028bd3ff] Fix HostSystem.ResourcePool with cluster parent +- [48e25166] Add ls bats test +- [c5f24bce] Add host bats test +- [f965c9ad] Add default GOVC_HOST to vcsim_env +- [77fc8ade] Add network flag required test +- [b1236bf8] Add wrapper to manually run govc against vcsim +- [68831a1f] Fix network device.remove test +- [4649bf1f] Default vcsim box to 4G memory +- [b3f71333] Simplify vcsim_env helper +- [2ca11cde] Answer pending VM questions from govc +- [b6c3ff31] Move govc/test Vagrant boxes +- [b1b5b26e] Change network flag to use NetworkReference +- [83f49af7] Add network bats test +- [a8ffa576] Add NetworkReference interface +- [6fe62e29] Add vcsim_env helper +- [a616817d] Fix collapse_ws helper +- [0614961e] Add DistributedVirtualPortgroup constructor +- [1ddf6801] Cache esxcli command info +- [c713b974] Add table formatter to esxcli command +- [fd19a011] Include esxcli method info in response +- [3c9a436f] Explicit exit status check in assert_failure +- [5a63bc06] Collapse whitespace in assert_line helper +- [c9bd4312] Change vm.ip -esxcli to wait for ip +- [e97e5604] boot order test fixups +- [0e128e0d] 32M is plenty of memory for ttylinux +- [85ded933] Add test cleanup script +- [2bc707e7] Add device.serial cli commands +- [17fb283a] Add serial port device related helpers +- [d9b846d1] Add device.boot tests +- [b5a21e4e] Add device.floppy cli commands +- [d1d39fc3] Add floppy device related helpers +- [1e2c54c0] Refactor disk logic into disk.go +- [9dff8e74] Fix attach disk error checks +- [0f352ec3] Add vm.disk.attach +- [bdd7b37b] Refactor vm.disk.add to vm.disk.create +- [ae2e990e] Add govc functional tests +- [a707fae6] Fix alignment for 32-bit go +- [13274292] Default cli client url.User field +- [17df67ad] Add device.boot cli command +- [3c345ad7] Add device.ls -boot option +- [3b25234c] Add boot order related VirtualDeviceList helpers +- [f996c7d0] Add VirtualMachine BootOptions wrappers +- [4f3b935b] Add some DeviceType constants +- [86f90c52] Add VirtualDeviceList.Type method +- [5f3b95d7] Output MAC Address in device.info +- [58c3c64e] Add VirtualMachineList.PrimaryMacAddress helper +- [67fea291] Fix import.ovf with relative ovf source path +- [22602029] Support non-disk files in import.ovf +- [92175548] Add Upload.Headers field +- [f095536d] Fix import.ova command +- [5093303a] Add device related govc commands +- [18644254] Add device list related helpers +- [6803033e] Add device list helpers +- [4f8cd87c] Switch to BaseOptionValue for vm extra config +- [76662657] Regenerate types +- [46ec389f] Generate interface types for all base types +- [f78df469] Remove Client param from ResourcePool methods +- [ca3cd417] Add Client reference to ResourcePool +- [ffc306cc] Add Client reference to Network +- [c1138fc4] Remove Client param from HttpNfcLease methods +- [6f983a49] Add Client reference to HttpNfcLease +- [d2d566d0] Remove Client param from HostSystem methods +- [60bf1770] Add Client reference to HostSystem +- [e32542c1] Remove Client param from HostDatastoreBrowser methods +- [8956959a] Add Client reference to HostDatastoreBrowser +- [79e7da1d] Remove Client param from Folder methods +- [68b3e6dc] Add Client reference to Folder +- [da5b8ec0] Remove Client param from Datastore methods +- [f89dd25a] Add Client reference to Datastore +- [1b372efa] Remove Client param from Datacenter methods +- [ce320403] Add Client reference to Datacenter +- [b99a9529] Remove Client param from VirtualMachine methods +- [eb700d65] Add Client reference to VirtualMachine +- [673485e4] Remove config check from esxcli.GuestInfo.IpAddress +- [667df16a] Add VCSA Vagrant box +- [66b7daab] Use single consistent pattern to populate FlagSet +- [8fa06b5a] Export NewReference function +- [a4e11a3a] Check if info is nil before using it +- [8bbe7361] Add ManagedObject wrappers +- [9d5df71d] Add vm.ip -esxcli option +- [1818a2a6] Add esxcli helper for guest related info +- [ac6efdc9] Use vim.CLIInfo for esxcli command flags and help +- [5b9b34bc] Remove Cdrom function from disk flag +- [01d201ee] Use new esxcli command parser +- [7531d60e] New esxcli command parser +- [a27c9bd5] Refactor esxcli to esxcli.Executor +- [fdb2d2d0] Refactor unmarshal +- [2dd9910d] Add esxcli related types and methods +- [aad819e8] Add IsoFlag +- [df11fc04] Handle empty values in esxcli +- [6ceff6a4] Fix default network in NetworkFlag +- [bc39649d] Add DistributedVirtualPortgroup wrapper +- [a7eb1d1e] Add DVS support to NetworkFlag +- [71898a73] Support DistributedVirtualPortgroup in lister +- [1cf31f03] Regenerate mo types +- [1e7c1957] Generate mo types regardless of props +- [549a2712] tasks are no longer generated +- [fcf2cd94] Remove unused DiskFlag.Copy method +- [e494c312] Add DiskFlag adpater option +- [71e5eea2] Add host.esxcli command +- [5d0fe65c] Replace panic by error in host system flag +- [a2a7c8ff] Remove newOvf() +- [d8e94d8f] Use default host system where possible +- [67835263] Move HostNetworkSystem getter to HostSystemFlag +- [348258b5] Move resource pool getter to host system object +- [03f94f4b] Default URL scheme and path if not specified +- [73b11f40] Move progress reader to vim25/progress +- [34f73f0a] Refactored progress reporting infrastructure +- [79f15899] Include environment variable names in help +- [1de37e80] Don't skip certificate verification by default +- [4a533b21] Support ClusterComputeResource in list flag +- [817df9d1] Include remote path in importable +- [a0944d82] Import vm.network commands +- [2fd2f026] Add vm.network.remove command +- [e3307b6f] Add vm.network.add command +- [2ac39a1e] Import host.portgroup commands +- [27686532] Add host.portgroup.remove command +- [46545dd9] Add host.portgroup.add command +- [29d8ed38] Add host.vswitch.remove command +- [c2bfbccf] Add host.vswitch.info command +- [f05e3e0a] Include host/vswitch commands +- [17094882] Add host.vswitch.add cli command +- [febf70cb] Add SearchFlag HostNetworkSystem helper +- [cb41663b] Add HostSystem ConfigManager getter +- [6f482eb1] Add HostConfigManager wrapper +- [851cb8d3] Add HostNetworkSystem wrapper +- [8bb8b613] Implement flag.Value interface in NetworkFlag +- [41ebd843] Change destination path for import.vmdk command +- [a6e0f1d4] Don't create VM if vmx already exists +- [b48f0080] Check that DiskFlag.Disk exists +- [8fcafba3] Use DatastoreFlag.Stat method in vmdk.PrepareDestination +- [29daec38] Add DatastoreFlag Stat method +- [29ca9c4a] Use aggregate progess in lease updater +- [de422b52] Enable debug logging with environment variable +- [48690f77] Add script that summarizes debug trace information +- [c515f6e1] Add guest.rm cli command +- [ade53d1e] Remove recursive arg from DeleteFileInGuest +- [63ec87fd] Add guest.start cli command +- [a5dccc14] Add guest.kill cli command +- [8e1abdd4] Add guest.mktemp cli command +- [8d287c3d] Add guest.ls cli command +- [79a67b2d] Fix a few tabwriter outputs Stderr -> Stdout +- [6dc9803f] Remove TODO +- [48a55bbd] Add guest.ps cli command +- [bed7c508] vm arg is required for guest ops +- [fc387eb6] Add example/project links +- [6e75fbf6] Add example: Create and configure a vCenter VM +- [068cc973] Add vm.disk.add command +- [ae42925a] ImportVApp host argument is optional +- [a959e782] Use OutputFlag.Log for ovf warnings +- [db30f1d4] Stream uploads directly from the .ova file +- [b0809106] Add import.Archive interface +- [1faa4e8b] Add Client.Upload method +- [47fe7028] Split datastore.import into multiple commands +- [66a468e2] Rename datastore.delete -> datastore.rm +- [3afcdf5d] Register commands with explicit name +- [07a12472] Load fewer properties where possible +- [3f2d9e5e] Cache rich type info for managed objects +- [be3b5ab1] Install go vet for travis +- [bcf792a0] Add go vet to travis script +- [6be65b35] Rename OutputWrite.WriteTo method to Write +- [b2c603f2] go vet: format related warnings +- [7403b749] go vet: composite literal uses unkeyed fields +- [98ac1aaf] Add NewFolder func +- [eea431c8] Change NewDatastore signature +- [7dbc2b25] Add NewResourcePool func +- [8467fbfd] Support importing VMDKs into ESXi machines +- [8a501f08] Be specific about channel direction +- [abeb8e83] Add DeleteVirtualDisk function +- [11d67d27] Add datastore.import support for .ova files +- [c29ff5c0] Improve about command output +- [bdeb77fd] Add progress for ovf datastore.import +- [4810135c] Ignore PowerOff error in vm.destroy command +- [48c2bbd3] Stop Ticker in ProgressLogger +- [8dfa7db3] Include Client.URL's port in ParseURL +- [c2330cf6] Add progress aggregator for govc +- [d7274985] Use virtual machine flag for vnc command +- [85649cd8] Remove vim25/tasks pkg +- [8f1a2803] Return task objects for every task function +- [df9af568] Add test for progress reader +- [1ddaf841] progessReader passthrough is progress channel is nil +- [9544be13] Add travis ci config +- [bad48a77] Use time.Equal when comparing time.Time +- [e4aeadc2] Upload progress for datastore.import +- [295b4597] Move computation of progress percentage and detail +- [c72543ac] Remove trailing _ from command name +- [2d96f8a5] Add progress report to datastore.{upload,download} +- [ae8509c1] Add functions to about command +- [583a4aca] Merge branch 'readme' +- [2b03454b] Add ovf support to datastore.import +- [fcdfafd6] Add options param to Client.UploadFile +- [0f218092] Move ParseURL helper to Client +- [9f9996e2] Published -> available +- [378e32b9] Fix +- [dae1e4e5] Use WaitForProperties in VirtualMachine.WaitForIP +- [a0335bac] Initial govc readme +- [65050902] Initial govmomi readme +- [231996ff] Add custom HttpNfcLease helpers +- [3293be25] Add Client.WaitForProperties method +- [a28b4fc0] Add generated HttpNfcLease wrapper +- [b610aa5c] Add ResourcePool.ImportVApp wrapper +- [6f9f316f] Add OvfManager getter +- [4ab1b230] Add generated OvfManager wrapper +- [a3e28532] Use virtual machine flag for guest ops +- [8044501f] Configure parent disk on create +- [1786687d] Generate mapping for interface type names +- [f3fa15c1] Use interface type name if type attr is missing +- [27cda4d6] Ignore EEXIST on mkdir in guest +- [c4517301] Use search flag from host system flag +- [9f9b0c9d] Initialize SearchFlag from Register hook +- [02108dd4] Call user function before recursing (govc/cli) +- [73b14a66] Don't overwrite fields (govc/cli) +- [0a5da729] Prefix search flags with entity name +- [cc6aa166] Isset -> IsSet +- [af8adde5] Consistently name pointer receiver 'flag' +- [5cd9a61e] Rename environment variables GOVMOMI -> GOVC +- [45eca426] Use list flag to find host system +- [15fe3728] Use list flag to find resource pool +- [1938ff93] List resource pool in compute resource +- [051ba306] Use list flag to find network +- [4015bec1] Create a VM with a read only parent disk +- [9e98ef07] Upload disk to import to directory +- [72fa245c] Split import into upload and import steps +- [d46b4e51] Add datastore.import command +- [2ba133de] Move datastore path helper to datastore struct +- [ba92fed2] Capture request and response bodies in debug mode +- [2660649a] Add datastore.ls cli command +- [2c8b9fd5] Add Datastore.Browser method +- [8e6805f5] Add HostDatastoreBrowser wrapper +- [6aef2e27] Change generated Base interfaces to a Get method +- [cb0c5763] Add datastore.cp cli command +- [d7cc920a] Add datastore.mv cli command +- [3601ab3b] Add Copy, Move FileManager methods +- [8c62e27e] Datastore commands take paths as regular arguments +- [a740c827] Use list flag to find datastore +- [b7d4b208] Add guest.getenv command +- [e72b79f9] Add guest.chmod command +- [5bd30d15] Use FileAttr flag in guest.upload +- [8c889f03] Add guest FileAttr flag +- [22f854ef] Fix guest RewriteURL method +- [69af5618] Retrieve object ancestors if listing a relative path +- [882faef4] Import vm/guest commands +- [a8fdd5ab] Add guest.upload command +- [93815beb] Add guest.download command +- [108f118d] Add guest.rmdir command +- [77c1f59d] Add guest.mkdir command +- [98283e1a] Common flags and helpers for guest command +- [37065ae1] Add cli flag for guest authentication +- [fc5eb7a7] More GuestFileManager wrappers +- [8611b851] Rename cli datastore upload/download receivers +- [2a058397] Move {Upload,Download}File methods to soap.Client +- [75dfb253] Use list flag to find datacenter +- [b0557434] Add GuestOperationManager wrapper +- [9fb9b66e] Load datacenter name for datastore URL +- [011790a6] Fix DatastoreFlag lookup +- [b7c12086] Add vm.ip command +- [17b0879d] Report progress from vm.power command +- [0a10a798] Avoid panic if ClientFlag url is not set +- [33c26af2] Long/short output for ls command +- [0c97323b] Make traversal of leaf nodes in list code configurable +- [ad0e3778] Add soap.Client.URL method +- [f3289833] Destroy multiple VMs +- [90d80fb3] Power on/off multiple VMs +- [97c2034b] Rename c -> cmd, client -> c +- [8ea428a4] Initialize vm commands with search type +- [1e175eab] Change xml.Decoder.AddType to TypeFunc +- [754da687] Change xml.Decoder.AddType to TypeFunc +- [8cbebfcb] Use list flag from search flag +- [43950349] Use list flag from vm.info cli command +- [0c3080c0] List relative to configurable object +- [c8438410] Extract list functionality as flag +- [ad7bac7a] Support vm.create with -disk .iso +- [189a2231] Add Isset function to search flag +- [bd38dd9b] Add vm.destroy cli command +- [24da8d1c] Add VirtualMachine.Destroy method +- [79466361] Include client counter in debug file prefix +- [11ac68f1] Check if session is valid before returning it +- [685f9554] Return fault from missing set if applicable +- [44575370] Method fault is a base class +- [f1258736] Optionally power on vm after creation +- [dd38436e] Function to map strings to types +- [9a0dde0a] Return VirtualMachine from CreateVM +- [29c8d2ee] Return result from Client.waitForTask +- [a368944d] Move error wrapper to soap package +- [bb62b6a6] Fix client_test compile +- [e0ce3a86] DatastoreFlag refactoring +- [4cd1e77f] Check for DatastorePath required flag +- [79887bf3] Rename DatastorePath to DatastorePathFlag +- [03f2520e] Persist session to disk +- [3a9169e2] Unembed soap.Client from govmomi.Client +- [b510dc18] Implement vm.create cli command +- [06d2e159] Add cli Disk flag +- [b0ce5181] Add cli Network flag +- [8736db1c] Add cli VmFolder flag +- [05a5e45c] Add Folder.CreateVM method +- [4d5eb080] Add VirtualDiskManager wrapper +- [6b4744ac] Move waitForTask method to Client type +- [7e4d047d] Remove embedded ClientFlag +- [a16bada5] Store debug logs on disk +- [e1d7c5b0] Only care about guest.ipAddress property for -waitip +- [647bd102] Use cli flag types for host, pool and datastore +- [14d27b9f] Add cli HostSystemFlag +- [920a5c8a] Add cli ResourcePoolFlag +- [0f76226c] Cache Datastore lookup +- [7bb22ee0] Add govmomi.ResourcePool type +- [6ffac6fc] Wait for the guest to get an IP address +- [2c361e75] Import datastore command package +- [5a68e03c] Add datastore.download command +- [135eb434] Add datastore.upload command +- [02f40085] Add datastore.delete command +- [a25d7233] Add datastore.mkdir command +- [d1f9dad7] Add cli DatastorePathFlag +- [27789049] Add cli DatastoreFlag +- [ea66997e] Add Datastore URL, Upload/Download File methods +- [3c630d4d] Add FileManager wrapper +- [68ca1c21] Unembed ServiceContent in govmomi.Client +- [57dd4153] Enable/disable VNC from govc +- [002cb1dc] Rename field Ref -> Self +- [5a3968ad] Add generic list command +- [31664dcf] Assign reference to self in managed objects +- [99809e14] Include reference to self in managed objects +- [96b65720] Rely on response to determine managed object type +- [dcfd55a6] Include type registry for managed objects +- [46c8fce8] Load complete object for json output +- [ceb3cfa2] Use search flag from power command +- [1e19e548] Add vm.info, host.info commands +- [979d8c48] Split govc/vm/command.go +- [24ce0371] Add output flag +- [32693cf3] Initial stab at listing VMs +- [59734757] Add datacenter flag +- [382bf2bc] More verbosity +- [e9a6152d] Allow embedding of flag types +- [2d2386dc] Move client flag to flags pkg +- [c2f5e99b] Nesting of flags through reflection +- [6d6f9baa] Add SearchIndex wrapper +- [4e06b8ae] govc cli skeleton +- [444617bb] Add power on/off and reset functions to VirtualMachine +- [a1377afa] Add compute resource struct +- [b6aceec1] Add virtual machine struct +- [415f4cd9] Add network struct +- [a7b60eb8] Add datastore struct +- [18ec5f35] Function to retrieve datacenter folders +- [cebbf289] Retrieve only childEntity property for folder +- [c7b42438] Add folder and datacenter types +- [00dce928] Allow custom request for mo.RetrieveProperties +- [1ac7f6df] Embed ServiceContent type in govmomi.Client +- [887b482e] Use cookiejar in soap client +- [3b674be4] Add basic client structure +- [79f0006e] Don't use pointer for enum (string) fields +- [29b2981c] Move generated enum types to their own file +- [5a0e65e5] Import scripts used for code generation +- [71c53d0e] Initial import +- [6081afb9] Add Apache license +- [ff8c717d] Import modifications to xml package +- [57091273] Import Go LICENSE file +- [d5645253] Import encoding/xml from Go 1.3.1 diff --git a/vendor/github.com/vmware/govmomi/CONTRIBUTING.md b/vendor/github.com/vmware/govmomi/CONTRIBUTING.md new file mode 100644 index 0000000000..038e5321b7 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/CONTRIBUTING.md @@ -0,0 +1,197 @@ +# Contributing to `govmomi` + +## Getting started + +First, fork the repository on GitHub to your personal account. + +Change `$USER` in the examples below to your Github username if they are not the +same. + +```bash +git clone https://github.com/vmware/govmomi.git && cd govmomi + +# prevent accidentally pushing to vmware/govmomi +git config push.default nothing +git remote rename origin vmware + +# add your fork +git remote add $USER git@github.com:$USER/govmomi.git + +git fetch -av +``` + +## Contribution Flow + +This is a rough outline of what a contributor's workflow looks like: + +- Create an issue describing the feature/fix +- Create a topic branch from where you want to base your work. +- Make commits of logical units. +- Make sure your commit messages are in the proper format (see below). +- Push your changes to a topic branch in your fork of the repository. +- Submit a pull request to `vmware/govmomi`. + +See [below](#format-of-the-commit-message) for details on commit best practices +and **supported prefixes**, e.g. `govc: `. + +> **Note:** If you are new to Git(hub) check out [Git rebase, squash...oh +> my!](https://www.mgasch.com/2021/05/git-basics/) for more details on how to +> successfully contribute to an open source project. + +### Example 1 - Fix a Bug in `govmomi` + +```bash +git checkout -b issue- main +git add +git commit -m "fix: ..." -m "Closes: #" +git push $USER issue- +``` + +### Example 2 - Add a new (non-breaking) API to `govmomi` + +```bash +git checkout -b issue- main +git add +git commit -m "Add API ..." -m "Closes: #" +git push $USER issue- +``` + +### Example 3 - Add a Feature to `govc` + +```bash +git checkout -b issue- main +git add +git commit -m "govc: Add feature ..." -m "Closes: #" +git push $USER issue- +``` +**Note**: +To register the new `govc` command package, add a blank `_` import to `govmomi/govc/main.go`. + +### Example 4 - Fix a Bug in `vcsim` + +```bash +git checkout -b issue- main +git add +git commit -m "vcsim: Fix ..." -m "Closes: #" +git push $USER issue- +``` + +### Example 5 - Document Breaking (API) Changes + +Breaking changes, e.g. to the `govmomi` APIs, are highlighted in the `CHANGELOG` +and release notes when the keyword `BREAKING:` is used in the commit message +body. + +The text after `BREAKING:` is used in the corresponding highlighted section. +Thus these details should be stated at the body of the commit message. +Multi-line strings are supported. + +```bash +git checkout -b issue- main +git add +cat << EOF | git commit -F - +Add ctx to funcXYZ + +This commit introduces context.Context to function XYZ +Closes: #1234 + +BREAKING: Add ctx to funcXYZ() +EOF + +git push $USER issue- +``` + +### Stay in sync with Upstream + +When your branch gets out of sync with the main branch, use the +following to update (rebase): + +```bash +git checkout issue- +git fetch -a +git rebase main +git push --force-with-lease $USER issue- +``` + +### Updating Pull Requests + +If your PR fails to pass CI or needs changes based on code review, it's ok to +add more commits stating the changes made, e.g. "Address review comments". This +is to assist the reviewer(s) to easily detect and review the recent changes. + +In case of small PRs, it's ok to squash and force-push (see further below) +directly instead. + +```bash +# incorporate review feedback +git add . + +# create a fixup commit which will be merged into your (original) +git commit --fixup +git push $USER issue- +``` + +Be sure to add a comment to the PR indicating your new changes are ready to +review, as Github does not generate a notification when you git push. + +Once the review is complete, squash and push your final commit(s): + +```bash +# squash all commits into one +# --autosquash will automatically detect and merge fixup commits +git rebase -i --autosquash main +git push --force-with-lease $USER issue- +``` + +### Code Style + +The coding style suggested by the Go community is used in `govmomi`. See the +[style doc](https://github.com/golang/go/wiki/CodeReviewComments) for details. + +Try to limit column width to 120 characters for both code and markdown documents +such as this one. + +### Format of the Commit Message + +We follow the conventions described in [How to Write a Git Commit +Message](http://chris.beams.io/posts/git-commit/). + +Be sure to include any related GitHub issue references in the commit message, +e.g. `Closes: #`. + +The [`CHANGELOG.md`](./CHANGELOG.md) and release page uses **commit message +prefixes** for grouping and highlighting. A commit message that +starts with `[prefix:] ` will place this commit under the respective +section in the `CHANGELOG`. + +The following example creates a commit referencing the `issue: 1234` and puts +the commit message in the `govc` `CHANGELOG` section: + +```bash +git commit -s -m "govc: Add CLI command X" -m "Closes: #1234" +``` + +Currently the following prefixes are used: + +- `api:` - Use for API-related changes +- `govc:` - Use for changes to `govc` CLI +- `vcsim:` - Use for changes to vCenter Simulator +- `chore:` - Use for repository related activities +- `fix:` - Use for bug fixes +- `docs:` - Use for changes to the documentation +- `examples:` - Use for changes to examples + +If your contribution falls into multiple categories, e.g. `api` and `vcsim` it +is recommended to break up your commits using distinct prefixes. + +### Running CI Checks and Tests +You can run both `make check` and `make test` from the top level of the +repository. + +While `make check` will catch formatting and import errors, it will not apply +any fixes. The developer is expected to do that. + +## Reporting Bugs and Creating Issues + +When opening a new issue, try to roughly follow the commit message format +conventions above. diff --git a/vendor/github.com/vmware/govmomi/CONTRIBUTORS b/vendor/github.com/vmware/govmomi/CONTRIBUTORS new file mode 100644 index 0000000000..03ca7c2f9e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/CONTRIBUTORS @@ -0,0 +1,283 @@ +# People who can (and typically have) contributed to this repository. +# +# This script is generated by contributors.sh +# + +Abhijeet Kasurde +abrarshivani +Adam Chalkley +Adam Fowler +Adam Shannon +Akanksha Panse +Al Biheiri +Alessandro Cortiana +Alex +Alex Bozhenko +Alex Ellis (VMware) +Aligator <8278538+yet-another-aligator@users.noreply.github.com> +Alvaro Miranda +Amanda H. L. de Andrade +amanpaha +Amit Bathla +amit bezalel +Andrew +Andrew Chin +Andrew Kutz +Andrey Klimentyev +Anfernee Yongkun Gui +angystardust +aniketGslab +Ankit Gohil +Ankit Vaidya +Ankur Huralikoppi +Anna Carrigan +Antony Saba +Ariel Chinn +Arran Walker +Artem Anisimov +Arunesh Pandey +Aryeh Weinreb +Augy StClair +Austin Parker +Balu Dontu +bastienbc +Ben Corrie +Ben Vickers +Benjamin Davini +Benjamin Peterson +Benjamin Vickers +Bhavya Choudhary +Bob Killen +Brad Fitzpatrick +Brian McClain +Brian Rak +brian57860 +Bruce Downs +Bruno Meneguello <1322552+bkmeneguello@users.noreply.github.com> +Bryan Venteicher +C S P Nanda +Carsten Grohmann +Cheng Cheng +Chethan Venkatesh +Choudhury Sarada Prasanna Nanda +Chris Marchesi +Christian Höltje +Christian Schlotter +Clint Greenwood +cpiment +CuiHaozhi +Cédric Blomart +Dan Ilan +Dan Norris +Daniel Frederick Crisman +Daniel Mueller +Danielle Barda +Danny Lockard +Dave Gress +Dave Smith-Uchida +Dave Tucker +David Gress +David Stark +Davide Agnello +Davinder Kumar +Defa +demarey +Deric Crago +Deyan Popov +Dinesh Bhat <35480850+dbhat-arkin@users.noreply.github.com> +ditsuke +Divyen Patel +Dnyanesh Gate +Doug MacEachern +East <60801291+houfangdong@users.noreply.github.com> +Eloy Coto +Eng Zer Jun +Eric Edens +Eric Graham <16710890+Pheric@users.noreply.github.com> +Eric Gray +Eric Yutao +Erik Hollensbe +Erik Lund +Essodjolo KAHANAM +Ethan Kaley +Evan Chu +Fabio Rapposelli +fabriziopandini +Faiyaz Ahmed +Federico Pellegatta <12744504+federico-pellegatta@users.noreply.github.com> +forkbomber +François Rigault +freebsdly +Gavin Gray +Gavrie Philipson +George Hicken +George Hicken +Gerrit Renker +gthombare +guoguangwu +Hakan Halil +HakanSunay +Hasan Mahmood +Haydon Ryan +Heiko Reese +Henrik Hodne +hkumar +Hrabur Stoyanov +hui luo +Ian Eyberg +Isaac Rodman +Ivan Mikushin +Ivan Porto Carrero +James King +James Peach +Jason Kincl +Jeremy Canady +jeremy-clerc +Jiatong Wang +jingyizPensando +Jonas Ausevicius +Jorge Sevilla +Joseph LeBlanc +João Pereira +Julien PILLON +Justin J. Novack +kayrus +Keenan Brock +Kevin George +Kiril Karaatanassov +Knappek +Kristian Alvestad +Lars Lehtonen +Leslie Wang +leslie-qiwa +Lintong Jiang +Liping Xue +liron.levin +Louie Jiang +Lubron Zhan +Luther Monson +Madanagopal Arunachalam +makelarisjr <8687447+makelarisjr@users.noreply.github.com> +Manuel Grandeit +maplain +Marc Carmier +Marcus Tan +Maria Ntalla +Marin Atanasov Nikolov +Mario Trangoni +Mark Dechiaro +Mark Peek +Mark Rexwinkel +martin +Matt Clay +Matt Moore +Matt Moriarity +Matthew Cosgrove +Mayank Bhatt +mbhadale +Merlijn Sebrechts +Mevan Samaratunga +Michael Gasch +Michal Jankowski +Mike Schinkel +Mincho Tonev +mingwei +Nicolas Lamirault +nikhaild <84156354+nikhaild@users.noreply.github.com> +Nikhil Kathare +Nikhil R Deshpande +Nikolas Grottendieck +Nils Elde +nirbhay +Nobuhiro MIKI +Om Kumar +Omar Kohl +Parham Alvani +Parveen Chahal +Paul Martin <25058109+rawstorage@users.noreply.github.com> +Pierre Gronlier +Pieter Noordhuis +pradeepj <50135054+pradeep288@users.noreply.github.com> +Pranshu Jain +prydin +rconde01 +rHermes +Rianto Wahyudi +Ricardo Katz +rmcqueen +Robin Watkins +Rowan Jacobs +Roy Ling +rsikdar +runner.mei +Ryan Johnson +S R Ashrith +S.Çağlar Onur +Saad Malik +Sam Zhu +samzhu333 <45263849+samzhu333@users.noreply.github.com> +Sandeep Pissay Srinivasa Rao +schmikei +Scott Holden +Sergey Ignatov +serokles +shahra +Shalini Bhaskara +Shaozhen Ding +Shawn Neal +shylasrinivas +sky-joker +smaftoul +smahadik +Sten Feldman +Stepan Mazurov +Steve Purcell +Stoyan Zhelyazkov +Sudhindra Aithal +SUMIT AGRAWAL +Sunny Carter +syuparn +Takaaki Furukawa +Tamas Eger +Tanay Kothari +tanishi +Ted Zlatanov +Thad Craft +Thibaut Ackermann +Tim McNamara +Tjeu Kayim <15987676+TjeuKayim@users.noreply.github.com> +Toomas Pelberg +Trevor Dawe +tshihad +Ueli Banholzer +Uwe Bessle +Vadim Egorov +Vamshik Shetty +Vikram Krishnamurthy +Vipul Kotkar +volanja +Volodymyr Bobyr +Waldek Maleska +William Lam +Witold Krecicki +xing-yang +xinyanw409 +Yang Yang +yangxi +Yann Hodique +Yash Nitin Desai +Yassine TIJANI +Yi Jiang +yiyingy +ykakarap +Yogesh Sobale <6104071+ysobale@users.noreply.github.com> +Your Name +Yue Yin +Yun Zhou +Yuya Kusakabe +Zach G +Zach Tucker +Zacharias Taubert +Zee Yang +zyuxin +Кузаков Евгений diff --git a/vendor/github.com/vmware/govmomi/Dockerfile.govc b/vendor/github.com/vmware/govmomi/Dockerfile.govc new file mode 100644 index 0000000000..e7d6766b01 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/Dockerfile.govc @@ -0,0 +1,45 @@ +# Create a builder container +# golang:1.18.0-buster amd64 +FROM golang@sha256:7d39537344486528f8cdb3bd8adb98ab7f0f4236044b6944fed8631da35a4ce5 AS build +WORKDIR /go/src/app + +# Create appuser to isolate potential vulnerabilities +# See https://stackoverflow.com/a/55757473/12429735 +ENV USER=appuser +ENV UID=10001 +RUN adduser \ + --disabled-password \ + --gecos "" \ + --shell "/sbin/nologin" \ + --no-create-home \ + --uid "${UID}" \ + "${USER}" + +# Create a new tmp directory so no bad actors can manipulate it +RUN mkdir /temporary-tmp-directory && chmod 777 /temporary-tmp-directory + +############################################################################### +# Final stage +FROM scratch + +# Allow container to use latest TLS certificates +COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ + +# Copy over appuser to run as non-root +COPY --from=build /etc/passwd /etc/passwd +COPY --from=build /etc/group /etc/group + +# Copy over the /tmp directory for golang/os.TmpDir +COPY --chown=appuser --from=build /temporary-tmp-directory /tmp + +# Copy application from external build +COPY govc /govc + +# Run all commands as non-root +USER appuser:appuser + +# session cache, etc +ENV GOVMOMI_HOME=/tmp + +# Set CMD to application with container defaults +CMD ["/govc"] diff --git a/vendor/github.com/vmware/govmomi/Dockerfile.vcsim b/vendor/github.com/vmware/govmomi/Dockerfile.vcsim new file mode 100644 index 0000000000..141de0ff2e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/Dockerfile.vcsim @@ -0,0 +1,47 @@ +# Create a builder container +# golang:1.18.0-buster amd64 +FROM golang@sha256:7d39537344486528f8cdb3bd8adb98ab7f0f4236044b6944fed8631da35a4ce5 AS build +WORKDIR /go/src/app + +# Create appuser to isolate potential vulnerabilities +# See https://stackoverflow.com/a/55757473/12429735 +ENV USER=appuser +ENV UID=10001 +RUN adduser \ + --disabled-password \ + --gecos "" \ + --home "/nonexistent" \ + --shell "/sbin/nologin" \ + --no-create-home \ + --uid "${UID}" \ + "${USER}" + +# Create a new tmp directory so no bad actors can manipulate it +RUN mkdir /temporary-tmp-directory && chmod 777 /temporary-tmp-directory + +############################################################################### +# Final stage +FROM scratch + +# Run all commands as non-root +USER appuser:appuser + +# Allow container to use latest TLS certificates +COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ + +# Copy over appuser to run as non-root +COPY --from=build /etc/passwd /etc/passwd +COPY --from=build /etc/group /etc/group + +# Copy over the /tmp directory for golang/os.TmpDir +COPY --chown=appuser --from=build /temporary-tmp-directory /tmp + +# Expose application port +EXPOSE 8989 + +# Copy application from external build +COPY vcsim /vcsim + +# Set entrypoint to application with container defaults +ENTRYPOINT [ "/vcsim" ] +CMD ["-l", "0.0.0.0:8989"] diff --git a/vendor/github.com/vmware/govmomi/LICENSE.txt b/vendor/github.com/vmware/govmomi/LICENSE.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/LICENSE.txt @@ -0,0 +1,202 @@ + + 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. diff --git a/vendor/github.com/vmware/govmomi/Makefile b/vendor/github.com/vmware/govmomi/Makefile new file mode 100644 index 0000000000..0f31649af8 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/Makefile @@ -0,0 +1,153 @@ +# Copyright (c) 2021 VMware, Inc. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +# If you update this file, please follow +# https://www.thapaliya.com/en/writings/well-documented-makefiles/ + +# Ensure Make is run with bash shell as some syntax below is bash-specific +SHELL := /usr/bin/env bash + +# Print the help/usage when make is executed without any other arguments +.DEFAULT_GOAL := help + + +## -------------------------------------- +## Help +## -------------------------------------- + +.PHONY: help +help: ## Display usage + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make [target] \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + + +## -------------------------------------- +## Locations and programs +## -------------------------------------- + +# Directories +BIN_DIR := bin +TOOLS_DIR := hack/tools +TOOLS_BIN_DIR := $(TOOLS_DIR)/bin + +# Tooling binaries +GO ?= $(shell command -v go 2>/dev/null) +GOLANGCI_LINT := $(TOOLS_BIN_DIR)/golangci-lint + + +## -------------------------------------- +## Prerequisites +## -------------------------------------- + +# Do not proceed unless the go binary is present. +ifeq (,$(strip $(GO))) +$(error The "go" program cannot be found) +endif + + +## -------------------------------------- +## Linting and fixing linter errors +## -------------------------------------- + +.PHONY: lint +lint: ## Run all the lint targets + $(MAKE) lint-go-full + +GOLANGCI_LINT_FLAGS ?= --fast=true +.PHONY: lint-go +lint-go: $(GOLANGCI_LINT) ## Lint codebase + $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_FLAGS) + +.PHONY: lint-go-full +lint-go-full: GOLANGCI_LINT_FLAGS = --fast=false --max-same-issues=200 +lint-go-full: lint-go ## Run slower linters to detect possible issues + +.PHONY: fix +fix: GOLANGCI_LINT_FLAGS = --fast=false --fix +fix: lint-go ## Tries to fix errors reported by lint-go-full target + +.PHONY: check +check: lint-go-full +check: ## Run linters + + +## -------------------------------------- +## Tooling Binaries +## -------------------------------------- + +TOOLING_BINARIES := $(GOLANGCI_LINT) +tools: $(TOOLING_BINARIES) ## Build tooling binaries +.PHONY: $(TOOLING_BINARIES) +$(TOOLING_BINARIES): + cd $(TOOLS_DIR); make $(@F) + + +## -------------------------------------- +## Build / Install +## -------------------------------------- +.PHONY: install +install: ## Install govc and vcsim + $(MAKE) -C govc install + $(MAKE) -C vcsim install + + +## -------------------------------------- +## Generate +## -------------------------------------- + +.PHONY: mod +mod: ## Runs go mod tidy to validate modules + go mod tidy -v + +.PHONY: mod-get +mod-get: ## Downloads and caches the modules + go mod download + +.PHONY: doc +doc: install +doc: ## Generates govc USAGE.md + ./govc/usage.sh > ./govc/USAGE.md + +.PHONY: generate-types +generate-types: ## Generate the types + $(MAKE) -C ./gen/ $@ + + +## -------------------------------------- +## Tests +## -------------------------------------- + +# Test options +TEST_COUNT ?= 1 +TEST_TIMEOUT ?= 5m +TEST_RACE_HISTORY_SIZE ?= 5 +GORACE ?= history_size=$(TEST_RACE_HISTORY_SIZE) + +ifeq (-count,$(findstring -count,$(TEST_OPTS))) +$(error Use TEST_COUNT to override this option) +endif + +ifeq (-race,$(findstring -race,$(TEST_OPTS))) +$(error The -race flag is enabled by default & cannot be specified in TEST_OPTS) +endif + +ifeq (-timeout,$(findstring -timeout,$(TEST_OPTS))) +$(error Use TEST_TIMEOUT to override this option) +endif + +.PHONY: go-test +go-test: ## Runs go unit tests with race detector enabled + GORACE=$(GORACE) CGO_ENABLED=1 $(GO) test \ + -count $(TEST_COUNT) \ + -race \ + -timeout $(TEST_TIMEOUT) \ + -v $(TEST_OPTS) \ + ./... + +.PHONY: govc-test +govc-test: install +govc-test: ## Runs govc bats tests + ./govc/test/images/update.sh + (cd govc/test && ./vendor/github.com/bats-core/bats-core/bin/bats -t .) + +.PHONY: test +test: go-test govc-test ## Runs go-test and govc-test diff --git a/vendor/github.com/vmware/govmomi/README.md b/vendor/github.com/vmware/govmomi/README.md new file mode 100644 index 0000000000..13ba3bf30e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/README.md @@ -0,0 +1,127 @@ + + +[![Build](https://github.com/vmware/govmomi/actions/workflows/govmomi-build.yaml/badge.svg)][ci-build] +[![Tests](https://github.com/vmware/govmomi/actions/workflows/govmomi-go-tests.yaml/badge.svg)][ci-tests] +[![Go Report Card](https://goreportcard.com/badge/github.com/vmware/govmomi)][go-report-card] +[![Latest Release](https://img.shields.io/github/release/vmware/govmomi.svg?logo=github&style=flat-square)][latest-release] +[![Go Reference](https://pkg.go.dev/badge/github.com/vmware/govmomi.svg)][go-reference] +[![go.mod Go version](https://img.shields.io/github/go-mod/go-version/vmware/govmomi)][go-version] + +# govmomi + +A Go library for interacting with VMware vSphere APIs (ESXi and/or vCenter Server). + +In addition to the vSphere API client, this repository includes: + +* [govc][govc] - vSphere CLI +* [vcsim][vcsim] - vSphere API mock framework +* [toolbox][toolbox] - VM guest tools framework + +## Compatibility + +This library supports vCenter Server and ESXi versions following the [VMware Product Lifecycle Matrix][reference-lifecycle]. + +Product versions that are end of support may work, but are not officially supported. + +## Documentation + +The APIs exposed by this library closely follow the API described in the [VMware vSphere API Reference Documentation][reference-api]. Refer to the documentation to become familiar with the upstream API. + +The code in the `govmomi` package is a wrapper for the code that is generated from the vSphere API description. It primarily provides convenience functions for working with the vSphere API. See [godoc.org][reference-godoc] for documentation. + +## Installation + +### Binaries and Docker Images for `govc` and `vcsim` + +Installation instructions, released binaries, and Docker images are documented in the respective README files of [`govc`][govc] and [`vcsim`][vcsim]. + +## Discussion + +The project encourages the community to collaborate using GitHub [issues][govmomi-github-issues], GitHub [discussions][govmomi-github-discussions], and [Slack][slack-channel]. + +> **Note** +> Access to Slack requires a free [VMware {code}][slack-join] developer program membership. + +## Status + +Changes to the API are subject to [semantic versioning][reference-semver]. + +Refer to the [CHANGELOG][govmomi-changelog] for version to version changes. + +## Notable Projects Using govmomi + +* [collectd-vsphere][project-travisci-collectd-vsphere] +* [Docker LinuxKit][project-docker-linuxKit] +* [Elastic Agent VMware vSphere integration][project-elastic-agent] +* [Gru][project-gru] +* [Juju][project-juju] +* [Jupiter Brain][project-travisci-jupiter-brain] +* [Kubernetes vSphere Cloud Provider][project-k8s-cloud-provider] +* [Kubernetes Cluster API][project-k8s-cluster-api] +* [OPS][project-nanovms-ops] +* [OpenTelemetry Collector Contrib][opentelemetry-collector-contrib] +* [Packer Plugin for VMware vSphere][project-hashicorp-packer-plugin-vsphere] +* [Rancher][project-rancher] +* [Terraform Provider for VMware vSphere][project-hashicorp-terraform-provider-vsphere] +* [Telegraf][project-influxdata-telegraf] +* [VMware Event Broker Appliance][project-vmware-veba] +* [VMware vSphere Integrated Containers Engine][project-vmware-vic] +* [VMware vSphere 7.0][project-vmware-vsphere] + +## Related Projects + +* [go-vmware-nsxt][reference-go-vmware-nsxt] +* [pyvmomi][reference-pyvmomi] +* [rbvmomi][reference-rbvmomi] + +## License + +govmomi is available under the [Apache 2 License][govmomi-license]. + +## Name + +Pronounced: _go·​v·​mom·​ie_ + +Follows pyvmomi and rbvmomi: language prefix + the vSphere acronym "VM Object Management Infrastructure". + +[//]: Links + +[ci-build]: https://github.com/vmware/govmomi/actions/workflows/govmomi-build.yaml +[ci-tests]: https://github.com/vmware/govmomi/actions/workflows/govmomi-go-tests.yaml +[latest-release]: https://github.com/vmware/govmomi/releases/latest +[govc]: govc/README.md +[govmomi-github-issues]: https://github.com/vmware/govmomi/issues +[govmomi-github-discussions]: https://github.com/vmware/govmomi/discussions +[govmomi-changelog]: CHANGELOG.md +[govmomi-license]: LICENSE.txt +[go-reference]: https://pkg.go.dev/github.com/vmware/govmomi +[go-report-card]: https://goreportcard.com/report/github.com/vmware/govmomi +[go-version]: https://github.com/vmware/govmomi +[opentelemetry-collector-contrib]: https://github.com/open-telemetry/opentelemetry-collector-contrib +[project-docker-linuxKit]: https://github.com/linuxkit/linuxkit/tree/master/src/cmd/linuxkit +[project-elastic-agent]: https://github.com/elastic/integrations/tree/main/packages/vsphere +[project-gru]: https://github.com/dnaeon/gru +[project-hashicorp-packer-plugin-vsphere]: https://github.com/hashicorp/packer-plugin-vsphere +[project-hashicorp-terraform-provider-vsphere]: https://github.com/hashicorp/terraform-provider-vsphere +[project-influxdata-telegraf]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/vsphere +[project-juju]: https://github.com/juju/juju +[project-k8s-cloud-provider]: https://github.com/kubernetes/cloud-provider-vsphere +[project-k8s-cluster-api]: https://github.com/kubernetes-sigs/cluster-api-provider-vsphere +[project-nanovms-ops]: https://github.com/nanovms/ops +[project-rancher]: https://github.com/rancher/rancher/blob/master/pkg/api/norman/customization/vsphere/listers.go +[project-travisci-collectd-vsphere]: https://github.com/travis-ci/collectd-vsphere +[project-travisci-jupiter-brain]: https://github.com/travis-ci/jupiter-brain +[project-vmware-veba]: https://github.com/vmware-samples/vcenter-event-broker-appliance/tree/development/vmware-event-router +[project-vmware-vic]: https://github.com/vmware/vic +[project-vmware-vsphere]: https://docs.vmware.com/en/VMware-vSphere/7.0/rn/vsphere-esxi-vcenter-server-7-vsphere-with-kubernetes-release-notes.html +[reference-api]: https://developer.vmware.com/apis/968/vsphere +[reference-godoc]: http://godoc.org/github.com/vmware/govmomi +[reference-go-vmware-nsxt]: https://github.com/vmware/go-vmware-nsxt +[reference-lifecycle]: https://lifecycle.vmware.com +[reference-pyvmomi]: https://github.com/vmware/pyvmomi +[reference-rbvmomi]: https://github.com/vmware/rbvmomi +[reference-semver]: http://semver.org +[slack-join]: https://developer.vmware.com/join/ +[slack-channel]: https://vmwarecode.slack.com/messages/govmomi +[toolbox]: toolbox/README.md +[vcsim]: vcsim/README.md diff --git a/vendor/github.com/vmware/govmomi/RELEASE.md b/vendor/github.com/vmware/govmomi/RELEASE.md new file mode 100644 index 0000000000..58b978a50f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/RELEASE.md @@ -0,0 +1,109 @@ +# How to create a `govmomi` Release on Github + +> **Note** +> +> The steps outlined in this document can only be performed by maintainers or +> administrators of this project. + +The release automation is based on Github +[Actions](https://github.com/features/actions) and has been improved over time +to simplify the experience for creating `govmomi` releases. + +The Github Actions release [workflow](.github/workflows/govmomi-release.yaml) +uses [`goreleaser`](http://goreleaser.com/) and automatically creates/pushes: + +- Release artifacts for `govc` and `vcsim` to the + [release](https://github.com/vmware/govmomi/releases) page, including + `LICENSE.txt`, `README` and `CHANGELOG` +- Docker images for `vmware/govc` and `vmware/vcsim` to Docker Hub +- Source code + +Releases are not tagged on the `main` branch, but a dedicated release branch, for example `release-0.35`. + +### Verify `main` branch is up to date with the remote + +```console +git checkout main +git fetch -avp +git diff main origin/main + +# if your local and remote branches diverge run +git pull origin/main +``` + +> **Warning** +> +> These steps assume `origin` to point to the remote +> `https://github.com/vmware/govmomi`, respectively +> `git@github.com:vmware/govmomi`. + +### Create a release branch + +For new releases, create a release branch from the most recent commit in +`main`, e.g. `release-0.35`. + +```console +export RELEASE_BRANCH=release-0.35 +git checkout -b ${RELEASE_BRANCH} +``` + +For maintenance/patch releases on **existing** release branches, simply checkout the existing +release branch and add commits to the existing release branch. + +### Verify `make docs` and `CONTRIBUTORS` are up to date + +> **Warning** +> +> Run the following commands and commit any changes to the release branch before +> proceeding with the release. + +```console +make doc +./scripts/contributors.sh +if [ -z "$(git status --porcelain)" ]; then + echo "working directory clean: proceed with release" +else + echo "working directory dirty: please commit changes" +fi + +# perform git add && git commit ... in case there were changes +``` + +### Push the release branch + +> **Warning** +> +> Do not create a tag as this will be done by the release automation. + +The final step is pushing the new/updated release branch. + +```console +git push origin ${RELEASE_BRANCH} +``` + +### Create a release in the Github UI + +Open the `govmomi` Github [repository](https://github.com/vmware/govmomi) and +navigate to `Actions -> Workflows -> Release`. + +Click `Run Workflow` which opens a dropdown list. + +Select the new/updated branch, e.g. `release-0.35`, i.e. **not** the `main` +branch. + +Specify a semantic `tag` to associate with the release, e.g. `v0.35.0`. + +> **Warning** +> +> This tag **must not** exist or the release will fail during the validation +> phase. + +By default, a dry-run is performed to rule out most (but not all) errors during +a release. If you do not want to perform a dry-run, e.g. to finally create a +release, deselect the `Verify release workflow ...` checkbox. + +Click `Run Workflow` to kick off the workflow. + +After successful completion and if the newly created `tag` is the **latest** +(semantic version sorted) tag in the repository, a PR is automatically opened +against the `main` branch to update the `CHANGELOG`. diff --git a/vendor/github.com/vmware/govmomi/USAGE.md b/vendor/github.com/vmware/govmomi/USAGE.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/vmware/govmomi/client.go b/vendor/github.com/vmware/govmomi/client.go new file mode 100644 index 0000000000..5becedd489 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/client.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2014-2023 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. +*/ + +/* +This package is the root package of the govmomi library. + +The library is structured as follows: + +# Package vim25 + +The minimal usable functionality is available through the vim25 package. +It contains subpackages that contain generated types, managed objects, and all +available methods. The vim25 package is entirely independent of the other +packages in the govmomi tree -- it has no dependencies on its peers. + +The vim25 package itself contains a client structure that is +passed around throughout the entire library. It abstracts a session and its +immutable state. See the vim25 package for more information. + +# Package session + +The session package contains an abstraction for the session manager that allows +a user to login and logout. It also provides access to the current session +(i.e. to determine if the user is in fact logged in) + +# Package object + +The object package contains wrappers for a selection of managed objects. The +constructors of these objects all take a *vim25.Client, which they pass along +to derived objects, if applicable. + +# Package govc + +The govc package contains the govc CLI. The code in this tree is not intended +to be used as a library. Any functionality that govc contains that _could_ be +used as a library function but isn't, _should_ live in a root level package. + +# Other packages + +Other packages, such as "event", "guest", or "license", provide wrappers for +the respective subsystems. They are typically not needed in normal workflows so +are kept outside the object package. +*/ +package govmomi + +import ( + "context" + "net/url" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/session" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +type Client struct { + *vim25.Client + + SessionManager *session.Manager +} + +// NewClient creates a new client from a URL. The client authenticates with the +// server with username/password before returning if the URL contains user information. +func NewClient(ctx context.Context, u *url.URL, insecure bool) (*Client, error) { + soapClient := soap.NewClient(u, insecure) + vimClient, err := vim25.NewClient(ctx, soapClient) + if err != nil { + return nil, err + } + + c := &Client{ + Client: vimClient, + SessionManager: session.NewManager(vimClient), + } + + // Only login if the URL contains user information. + if u.User != nil { + err = c.Login(ctx, u.User) + if err != nil { + return nil, err + } + } + + return c, nil +} + +// Login dispatches to the SessionManager. +func (c *Client) Login(ctx context.Context, u *url.Userinfo) error { + return c.SessionManager.Login(ctx, u) +} + +// Logout dispatches to the SessionManager. +func (c *Client) Logout(ctx context.Context) error { + // Close any idle connections after logging out. + defer c.Client.CloseIdleConnections() + return c.SessionManager.Logout(ctx) +} + +// PropertyCollector returns the session's default property collector. +func (c *Client) PropertyCollector() *property.Collector { + return property.DefaultCollector(c.Client) +} + +// RetrieveOne dispatches to the Retrieve function on the default property collector. +func (c *Client) RetrieveOne(ctx context.Context, obj types.ManagedObjectReference, p []string, dst interface{}) error { + return c.PropertyCollector().RetrieveOne(ctx, obj, p, dst) +} + +// Retrieve dispatches to the Retrieve function on the default property collector. +func (c *Client) Retrieve(ctx context.Context, objs []types.ManagedObjectReference, p []string, dst interface{}) error { + return c.PropertyCollector().Retrieve(ctx, objs, p, dst) +} + +// Wait dispatches to property.Wait. +func (c *Client) Wait(ctx context.Context, obj types.ManagedObjectReference, ps []string, f func([]types.PropertyChange) bool) error { + return property.Wait(ctx, c.PropertyCollector(), obj, ps, f) +} + +// IsVC returns true if we are connected to a vCenter +func (c *Client) IsVC() bool { + return c.Client.IsVC() +} diff --git a/vendor/github.com/vmware/govmomi/event/history_collector.go b/vendor/github.com/vmware/govmomi/event/history_collector.go new file mode 100644 index 0000000000..4796c9426f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/event/history_collector.go @@ -0,0 +1,76 @@ +/* +Copyright (c) 2015 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 event + +import ( + "context" + + "github.com/vmware/govmomi/history" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type HistoryCollector struct { + *history.Collector +} + +func newHistoryCollector(c *vim25.Client, ref types.ManagedObjectReference) *HistoryCollector { + return &HistoryCollector{ + Collector: history.NewCollector(c, ref), + } +} + +func (h HistoryCollector) LatestPage(ctx context.Context) ([]types.BaseEvent, error) { + var o mo.EventHistoryCollector + + err := h.Properties(ctx, h.Reference(), []string{"latestPage"}, &o) + if err != nil { + return nil, err + } + + return o.LatestPage, nil +} + +func (h HistoryCollector) ReadNextEvents(ctx context.Context, maxCount int32) ([]types.BaseEvent, error) { + req := types.ReadNextEvents{ + This: h.Reference(), + MaxCount: maxCount, + } + + res, err := methods.ReadNextEvents(ctx, h.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (h HistoryCollector) ReadPreviousEvents(ctx context.Context, maxCount int32) ([]types.BaseEvent, error) { + req := types.ReadPreviousEvents{ + This: h.Reference(), + MaxCount: maxCount, + } + + res, err := methods.ReadPreviousEvents(ctx, h.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/event/manager.go b/vendor/github.com/vmware/govmomi/event/manager.go new file mode 100644 index 0000000000..c423c18373 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/event/manager.go @@ -0,0 +1,199 @@ +/* +Copyright (c) 2015 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 event + +import ( + "context" + "fmt" + "reflect" + "sync" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type Manager struct { + r types.ManagedObjectReference + c *vim25.Client + + eventCategory map[string]string + eventCategoryMu *sync.Mutex + maxObjects int +} + +func NewManager(c *vim25.Client) *Manager { + m := Manager{ + r: c.ServiceContent.EventManager.Reference(), + c: c, + eventCategory: make(map[string]string), + eventCategoryMu: new(sync.Mutex), + maxObjects: 10, + } + + return &m +} + +// Reference returns the event.Manager MOID +func (m Manager) Reference() types.ManagedObjectReference { + return m.r +} + +func (m Manager) Client() *vim25.Client { + return m.c +} + +func (m Manager) CreateCollectorForEvents(ctx context.Context, filter types.EventFilterSpec) (*HistoryCollector, error) { + req := types.CreateCollectorForEvents{ + This: m.r, + Filter: filter, + } + + res, err := methods.CreateCollectorForEvents(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return newHistoryCollector(m.c, res.Returnval), nil +} + +func (m Manager) LogUserEvent(ctx context.Context, entity types.ManagedObjectReference, msg string) error { + req := types.LogUserEvent{ + This: m.r, + Entity: entity, + Msg: msg, + } + + _, err := methods.LogUserEvent(ctx, m.c, &req) + if err != nil { + return err + } + + return nil +} + +func (m Manager) PostEvent(ctx context.Context, eventToPost types.BaseEvent, taskInfo ...types.TaskInfo) error { + req := types.PostEvent{ + This: m.r, + EventToPost: eventToPost, + } + + if len(taskInfo) == 1 { + req.TaskInfo = &taskInfo[0] + } + + _, err := methods.PostEvent(ctx, m.c, &req) + if err != nil { + return err + } + + return nil +} + +func (m Manager) QueryEvents(ctx context.Context, filter types.EventFilterSpec) ([]types.BaseEvent, error) { + req := types.QueryEvents{ + This: m.r, + Filter: filter, + } + + res, err := methods.QueryEvents(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m Manager) RetrieveArgumentDescription(ctx context.Context, eventTypeID string) ([]types.EventArgDesc, error) { + req := types.RetrieveArgumentDescription{ + This: m.r, + EventTypeId: eventTypeID, + } + + res, err := methods.RetrieveArgumentDescription(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m Manager) eventCategoryMap(ctx context.Context) (map[string]string, error) { + m.eventCategoryMu.Lock() + defer m.eventCategoryMu.Unlock() + + if len(m.eventCategory) != 0 { + return m.eventCategory, nil + } + + var o mo.EventManager + + ps := []string{"description.eventInfo"} + err := property.DefaultCollector(m.c).RetrieveOne(ctx, m.r, ps, &o) + if err != nil { + return nil, err + } + + for _, info := range o.Description.EventInfo { + m.eventCategory[info.Key] = info.Category + } + + return m.eventCategory, nil +} + +// EventCategory returns the category for an event, such as "info" or "error" for example. +func (m Manager) EventCategory(ctx context.Context, event types.BaseEvent) (string, error) { + // Most of the event details are included in the Event.FullFormattedMessage, but the category + // is only available via the EventManager description.eventInfo property. The value of this + // property is static, so we fetch and once and cache. + eventCategory, err := m.eventCategoryMap(ctx) + if err != nil { + return "", err + } + + switch e := event.(type) { + case *types.EventEx: + if e.Severity == "" { + return "info", nil + } + return e.Severity, nil + } + + class := reflect.TypeOf(event).Elem().Name() + + return eventCategory[class], nil +} + +// Events gets the events from the specified object(s) and optionanlly tail the +// event stream +func (m Manager) Events(ctx context.Context, objects []types.ManagedObjectReference, pageSize int32, tail bool, force bool, f func(types.ManagedObjectReference, []types.BaseEvent) error, kind ...string) error { + // TODO: deprecated this method and add one that uses a single config struct, so we can extend further without breaking the method signature. + if len(objects) >= m.maxObjects && !force { + return fmt.Errorf("maximum number of objects to monitor (%d) exceeded, refine search", m.maxObjects) + } + + proc := newEventProcessor(m, pageSize, f, kind) + for _, o := range objects { + proc.addObject(ctx, o) + } + + defer proc.destroy() + + return proc.run(ctx, tail) +} diff --git a/vendor/github.com/vmware/govmomi/event/processor.go b/vendor/github.com/vmware/govmomi/event/processor.go new file mode 100644 index 0000000000..972474ce1c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/event/processor.go @@ -0,0 +1,194 @@ +/* +Copyright (c) 2016-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 event + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25/types" +) + +type tailInfo struct { + t *eventTailer + obj types.ManagedObjectReference + collector *HistoryCollector +} + +type eventProcessor struct { + mgr Manager + pageSize int32 + kind []string + tailers map[types.ManagedObjectReference]*tailInfo // tailers by collector ref + callback func(types.ManagedObjectReference, []types.BaseEvent) error +} + +func newEventProcessor(mgr Manager, pageSize int32, callback func(types.ManagedObjectReference, []types.BaseEvent) error, kind []string) *eventProcessor { + return &eventProcessor{ + mgr: mgr, + tailers: make(map[types.ManagedObjectReference]*tailInfo), + callback: callback, + pageSize: pageSize, + kind: kind, + } +} + +func (p *eventProcessor) addObject(ctx context.Context, obj types.ManagedObjectReference) error { + filter := types.EventFilterSpec{ + Entity: &types.EventFilterSpecByEntity{ + Entity: obj, + Recursion: types.EventFilterSpecRecursionOptionAll, + }, + EventTypeId: p.kind, + } + + collector, err := p.mgr.CreateCollectorForEvents(ctx, filter) + if err != nil { + return fmt.Errorf("[%#v] %s", obj, err) + } + + err = collector.SetPageSize(ctx, p.pageSize) + if err != nil { + return err + } + + p.tailers[collector.Reference()] = &tailInfo{ + t: newEventTailer(), + obj: obj, + collector: collector, + } + + return nil +} + +func (p *eventProcessor) destroy() { + for _, info := range p.tailers { + _ = info.collector.Destroy(context.Background()) + } +} + +func (p *eventProcessor) run(ctx context.Context, tail bool) error { + if len(p.tailers) == 0 { + return nil + } + + var collectors []types.ManagedObjectReference + for ref := range p.tailers { + collectors = append(collectors, ref) + } + + c := property.DefaultCollector(p.mgr.Client()) + props := []string{"latestPage"} + + if len(collectors) == 1 { + // only one object to follow, don't bother creating a view + return property.Wait(ctx, c, collectors[0], props, func(pc []types.PropertyChange) bool { + if err := p.process(collectors[0], pc); err != nil { + return false + } + + return !tail + }) + } + + // create and populate a ListView + m := view.NewManager(p.mgr.Client()) + + list, err := m.CreateListView(ctx, collectors) + if err != nil { + return err + } + + defer func() { + _ = list.Destroy(context.Background()) + }() + + ref := list.Reference() + filter := new(property.WaitFilter).Add(ref, collectors[0].Type, props, list.TraversalSpec()) + + return property.WaitForUpdates(ctx, c, filter, func(updates []types.ObjectUpdate) bool { + for _, update := range updates { + if err := p.process(update.Obj, update.ChangeSet); err != nil { + return false + } + } + + return !tail + }) +} + +func (p *eventProcessor) process(c types.ManagedObjectReference, pc []types.PropertyChange) error { + t := p.tailers[c] + if t == nil { + return fmt.Errorf("unknown collector %s", c.String()) + } + + for _, u := range pc { + evs := t.t.newEvents(u.Val.(types.ArrayOfEvent).Event) + if len(evs) == 0 { + continue + } + + if err := p.callback(t.obj, evs); err != nil { + return err + } + } + + return nil +} + +const invalidKey = int32(-1) + +type eventTailer struct { + lastKey int32 +} + +func newEventTailer() *eventTailer { + return &eventTailer{ + lastKey: invalidKey, + } +} + +func (t *eventTailer) newEvents(evs []types.BaseEvent) []types.BaseEvent { + var ret []types.BaseEvent + if t.lastKey == invalidKey { + ret = evs + } else { + found := false + for i := range evs { + if evs[i].GetEvent().Key != t.lastKey { + continue + } + + found = true + ret = evs[:i] + break + } + + if !found { + ret = evs + } + } + + if len(ret) > 0 { + t.lastKey = ret[0].GetEvent().Key + } + + return ret +} diff --git a/vendor/github.com/vmware/govmomi/event/sort.go b/vendor/github.com/vmware/govmomi/event/sort.go new file mode 100644 index 0000000000..9d19a73506 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/event/sort.go @@ -0,0 +1,46 @@ +/* +Copyright (c) 2015-2023 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 event + +import ( + "sort" + + "github.com/vmware/govmomi/vim25/types" +) + +// Sort events in ascending order base on Key +// From the EventHistoryCollector.latestPage sdk docs: +// +// The "oldest event" is the one with the smallest key (event ID). +// The events in the returned page are unordered. +func Sort(events []types.BaseEvent) { + sort.Sort(baseEvent(events)) +} + +type baseEvent []types.BaseEvent + +func (d baseEvent) Len() int { + return len(d) +} + +func (d baseEvent) Less(i, j int) bool { + return d[i].GetEvent().Key < d[j].GetEvent().Key +} + +func (d baseEvent) Swap(i, j int) { + d[i], d[j] = d[j], d[i] +} diff --git a/vendor/github.com/vmware/govmomi/history/collector.go b/vendor/github.com/vmware/govmomi/history/collector.go new file mode 100644 index 0000000000..9b25ea85a1 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/history/collector.go @@ -0,0 +1,91 @@ +/* +Copyright (c) 2015 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 history + +import ( + "context" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type Collector struct { + r types.ManagedObjectReference + c *vim25.Client +} + +func NewCollector(c *vim25.Client, ref types.ManagedObjectReference) *Collector { + return &Collector{ + r: ref, + c: c, + } +} + +// Reference returns the managed object reference of this collector +func (c Collector) Reference() types.ManagedObjectReference { + return c.r +} + +// Client returns the vim25 client used by this collector +func (c Collector) Client() *vim25.Client { + return c.c +} + +// Properties wraps property.DefaultCollector().RetrieveOne() and returns +// properties for the specified managed object reference +func (c Collector) Properties(ctx context.Context, r types.ManagedObjectReference, ps []string, dst interface{}) error { + return property.DefaultCollector(c.c).RetrieveOne(ctx, r, ps, dst) +} + +func (c Collector) Destroy(ctx context.Context) error { + req := types.DestroyCollector{ + This: c.r, + } + + _, err := methods.DestroyCollector(ctx, c.c, &req) + return err +} + +func (c Collector) Reset(ctx context.Context) error { + req := types.ResetCollector{ + This: c.r, + } + + _, err := methods.ResetCollector(ctx, c.c, &req) + return err +} + +func (c Collector) Rewind(ctx context.Context) error { + req := types.RewindCollector{ + This: c.r, + } + + _, err := methods.RewindCollector(ctx, c.c, &req) + return err +} + +func (c Collector) SetPageSize(ctx context.Context, maxCount int32) error { + req := types.SetCollectorPageSize{ + This: c.r, + MaxCount: maxCount, + } + + _, err := methods.SetCollectorPageSize(ctx, c.c, &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/internal/helpers.go b/vendor/github.com/vmware/govmomi/internal/helpers.go new file mode 100644 index 0000000000..41e533fd75 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/internal/helpers.go @@ -0,0 +1,141 @@ +/* +Copyright (c) 2020-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "context" + "fmt" + "net" + "net/http" + "net/url" + "os" + "path" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +const ( + vCenterHostGatewaySocket = "/var/run/envoy-hgw/hgw-pipe" + vCenterHostGatewaySocketEnv = "VCENTER_ENVOY_HOST_GATEWAY" +) + +// InventoryPath composed of entities by Name +func InventoryPath(entities []mo.ManagedEntity) string { + val := "/" + + for _, entity := range entities { + // Skip root folder in building inventory path. + if entity.Parent == nil { + continue + } + val = path.Join(val, entity.Name) + } + + return val +} + +func HostSystemManagementIPs(config []types.VirtualNicManagerNetConfig) []net.IP { + var ips []net.IP + + for _, nc := range config { + if nc.NicType != string(types.HostVirtualNicManagerNicTypeManagement) { + continue + } + for ix := range nc.CandidateVnic { + for _, selectedVnicKey := range nc.SelectedVnic { + if nc.CandidateVnic[ix].Key != selectedVnicKey { + continue + } + ip := net.ParseIP(nc.CandidateVnic[ix].Spec.Ip.IpAddress) + if ip != nil { + ips = append(ips, ip) + } + } + } + } + + return ips +} + +// UsingEnvoySidecar determines if the given *vim25.Client is using vCenter's +// local Envoy sidecar (as opposed to using the HTTPS port.) +// Returns a boolean indicating whether to use the sidecar or not. +func UsingEnvoySidecar(c *vim25.Client) bool { + envoySidecarPort := os.Getenv("GOVMOMI_ENVOY_SIDECAR_PORT") + if envoySidecarPort == "" { + envoySidecarPort = "1080" + } + envoySidecarHost := os.Getenv("GOVMOMI_ENVOY_SIDECAR_HOST") + if envoySidecarHost == "" { + envoySidecarHost = "localhost" + } + return c.URL().Hostname() == envoySidecarHost && c.URL().Scheme == "http" && c.URL().Port() == envoySidecarPort +} + +// ClientWithEnvoyHostGateway clones the provided soap.Client and returns a new +// one that uses a Unix socket to leverage vCenter's local Envoy host +// gateway. +// This should be used to construct clients that talk to ESX. +// This method returns a new *vim25.Client and does not modify the original input. +// This client disables HTTP keep alives and is intended for a single round +// trip. (eg. guest file transfer, datastore file transfer) +func ClientWithEnvoyHostGateway(vc *vim25.Client) *vim25.Client { + // Override the vim client with a new one that wraps a Unix socket transport. + // Using HTTP here so secure means nothing. + sc := soap.NewClient(vc.URL(), true) + // Clone the underlying HTTP transport, only replacing the dialer logic. + transport := sc.DefaultTransport().Clone() + hostGatewaySocketPath := os.Getenv(vCenterHostGatewaySocketEnv) + if hostGatewaySocketPath == "" { + hostGatewaySocketPath = vCenterHostGatewaySocket + } + transport.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { + return net.Dial("unix", hostGatewaySocketPath) + } + // We use this client for a single request, so we don't require keepalives. + transport.DisableKeepAlives = true + sc.Client = http.Client{ + Transport: transport, + } + newVC := &vim25.Client{ + Client: sc, + } + return newVC +} + +// HostGatewayTransferURL rewrites the provided URL to be suitable for use +// with the Envoy host gateway on vCenter. +// It returns a copy of the provided URL with the host, scheme rewritten as needed. +// Receivers of such URLs must typically also use ClientWithEnvoyHostGateway to +// use the appropriate http.Transport to be able to make use of the host +// gateway. +// nil input yields an uninitialized struct. +func HostGatewayTransferURL(u *url.URL, hostMoref types.ManagedObjectReference) *url.URL { + if u == nil { + return &url.URL{} + } + // Make a copy of the provided URL. + turl := *u + turl.Host = "localhost" + turl.Scheme = "http" + oldPath := turl.Path + turl.Path = fmt.Sprintf("/hgw/%s%s", hostMoref.Value, oldPath) + return &turl +} diff --git a/vendor/github.com/vmware/govmomi/internal/methods.go b/vendor/github.com/vmware/govmomi/internal/methods.go new file mode 100644 index 0000000000..95ccee8d24 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/internal/methods.go @@ -0,0 +1,123 @@ +/* +Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "context" + + "github.com/vmware/govmomi/vim25/soap" +) + +type RetrieveDynamicTypeManagerBody struct { + Req *RetrieveDynamicTypeManagerRequest `xml:"urn:vim25 RetrieveDynamicTypeManager"` + Res *RetrieveDynamicTypeManagerResponse `xml:"urn:vim25 RetrieveDynamicTypeManagerResponse"` + Fault_ *soap.Fault +} + +func (b *RetrieveDynamicTypeManagerBody) Fault() *soap.Fault { return b.Fault_ } + +func RetrieveDynamicTypeManager(ctx context.Context, r soap.RoundTripper, req *RetrieveDynamicTypeManagerRequest) (*RetrieveDynamicTypeManagerResponse, error) { + var reqBody, resBody RetrieveDynamicTypeManagerBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type RetrieveManagedMethodExecuterBody struct { + Req *RetrieveManagedMethodExecuterRequest `xml:"urn:vim25 RetrieveManagedMethodExecuter"` + Res *RetrieveManagedMethodExecuterResponse `xml:"urn:vim25 RetrieveManagedMethodExecuterResponse"` + Fault_ *soap.Fault +} + +func (b *RetrieveManagedMethodExecuterBody) Fault() *soap.Fault { return b.Fault_ } + +func RetrieveManagedMethodExecuter(ctx context.Context, r soap.RoundTripper, req *RetrieveManagedMethodExecuterRequest) (*RetrieveManagedMethodExecuterResponse, error) { + var reqBody, resBody RetrieveManagedMethodExecuterBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type DynamicTypeMgrQueryMoInstancesBody struct { + Req *DynamicTypeMgrQueryMoInstancesRequest `xml:"urn:vim25 DynamicTypeMgrQueryMoInstances"` + Res *DynamicTypeMgrQueryMoInstancesResponse `xml:"urn:vim25 DynamicTypeMgrQueryMoInstancesResponse"` + Fault_ *soap.Fault +} + +func (b *DynamicTypeMgrQueryMoInstancesBody) Fault() *soap.Fault { return b.Fault_ } + +func DynamicTypeMgrQueryMoInstances(ctx context.Context, r soap.RoundTripper, req *DynamicTypeMgrQueryMoInstancesRequest) (*DynamicTypeMgrQueryMoInstancesResponse, error) { + var reqBody, resBody DynamicTypeMgrQueryMoInstancesBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type DynamicTypeMgrQueryTypeInfoBody struct { + Req *DynamicTypeMgrQueryTypeInfoRequest `xml:"urn:vim25 DynamicTypeMgrQueryTypeInfo"` + Res *DynamicTypeMgrQueryTypeInfoResponse `xml:"urn:vim25 DynamicTypeMgrQueryTypeInfoResponse"` + Fault_ *soap.Fault +} + +func (b *DynamicTypeMgrQueryTypeInfoBody) Fault() *soap.Fault { return b.Fault_ } + +func DynamicTypeMgrQueryTypeInfo(ctx context.Context, r soap.RoundTripper, req *DynamicTypeMgrQueryTypeInfoRequest) (*DynamicTypeMgrQueryTypeInfoResponse, error) { + var reqBody, resBody DynamicTypeMgrQueryTypeInfoBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type ExecuteSoapBody struct { + Req *ExecuteSoapRequest `xml:"urn:vim25 ExecuteSoap"` + Res *ExecuteSoapResponse `xml:"urn:vim25 ExecuteSoapResponse"` + Fault_ *soap.Fault +} + +func (b *ExecuteSoapBody) Fault() *soap.Fault { return b.Fault_ } + +func ExecuteSoap(ctx context.Context, r soap.RoundTripper, req *ExecuteSoapRequest) (*ExecuteSoapResponse, error) { + var reqBody, resBody ExecuteSoapBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} diff --git a/vendor/github.com/vmware/govmomi/internal/types.go b/vendor/github.com/vmware/govmomi/internal/types.go new file mode 100644 index 0000000000..b84103b89b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/internal/types.go @@ -0,0 +1,270 @@ +/* +Copyright (c) 2014 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "reflect" + + "github.com/vmware/govmomi/vim25/types" +) + +type DynamicTypeMgrQueryMoInstancesRequest struct { + This types.ManagedObjectReference `xml:"_this"` + FilterSpec BaseDynamicTypeMgrFilterSpec `xml:"filterSpec,omitempty,typeattr"` +} + +type DynamicTypeMgrQueryMoInstancesResponse struct { + Returnval []DynamicTypeMgrMoInstance `xml:"urn:vim25 returnval"` +} + +type DynamicTypeEnumTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + WsdlName string `xml:"wsdlName"` + Version string `xml:"version"` + Value []string `xml:"value,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeEnumTypeInfo", reflect.TypeOf((*DynamicTypeEnumTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrAllTypeInfoRequest struct { + types.DynamicData + + ManagedTypeInfo []DynamicTypeMgrManagedTypeInfo `xml:"managedTypeInfo,omitempty"` + EnumTypeInfo []DynamicTypeEnumTypeInfo `xml:"enumTypeInfo,omitempty"` + DataTypeInfo []DynamicTypeMgrDataTypeInfo `xml:"dataTypeInfo,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrAllTypeInfo", reflect.TypeOf((*DynamicTypeMgrAllTypeInfoRequest)(nil)).Elem()) +} + +type DynamicTypeMgrAnnotation struct { + types.DynamicData + + Name string `xml:"name"` + Parameter []string `xml:"parameter,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrAnnotation", reflect.TypeOf((*DynamicTypeMgrAnnotation)(nil)).Elem()) +} + +type DynamicTypeMgrDataTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + WsdlName string `xml:"wsdlName"` + Version string `xml:"version"` + Base []string `xml:"base,omitempty"` + Property []DynamicTypeMgrPropertyTypeInfo `xml:"property,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrDataTypeInfo", reflect.TypeOf((*DynamicTypeMgrDataTypeInfo)(nil)).Elem()) +} + +func (b *DynamicTypeMgrFilterSpec) GetDynamicTypeMgrFilterSpec() *DynamicTypeMgrFilterSpec { return b } + +type BaseDynamicTypeMgrFilterSpec interface { + GetDynamicTypeMgrFilterSpec() *DynamicTypeMgrFilterSpec +} + +type DynamicTypeMgrFilterSpec struct { + types.DynamicData +} + +func init() { + types.Add("DynamicTypeMgrFilterSpec", reflect.TypeOf((*DynamicTypeMgrFilterSpec)(nil)).Elem()) +} + +type DynamicTypeMgrManagedTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + WsdlName string `xml:"wsdlName"` + Version string `xml:"version"` + Base []string `xml:"base,omitempty"` + Property []DynamicTypeMgrPropertyTypeInfo `xml:"property,omitempty"` + Method []DynamicTypeMgrMethodTypeInfo `xml:"method,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrManagedTypeInfo", reflect.TypeOf((*DynamicTypeMgrManagedTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrMethodTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + WsdlName string `xml:"wsdlName"` + Version string `xml:"version"` + ParamTypeInfo []DynamicTypeMgrParamTypeInfo `xml:"paramTypeInfo,omitempty"` + ReturnTypeInfo *DynamicTypeMgrParamTypeInfo `xml:"returnTypeInfo,omitempty"` + Fault []string `xml:"fault,omitempty"` + PrivId string `xml:"privId,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrMethodTypeInfo", reflect.TypeOf((*DynamicTypeMgrMethodTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrMoFilterSpec struct { + DynamicTypeMgrFilterSpec + + Id string `xml:"id,omitempty"` + TypeSubstr string `xml:"typeSubstr,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrMoFilterSpec", reflect.TypeOf((*DynamicTypeMgrMoFilterSpec)(nil)).Elem()) +} + +type DynamicTypeMgrMoInstance struct { + types.DynamicData + + Id string `xml:"id"` + MoType string `xml:"moType"` +} + +func init() { + types.Add("DynamicTypeMgrMoInstance", reflect.TypeOf((*DynamicTypeMgrMoInstance)(nil)).Elem()) +} + +type DynamicTypeMgrParamTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + Version string `xml:"version"` + Type string `xml:"type"` + PrivId string `xml:"privId,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrParamTypeInfo", reflect.TypeOf((*DynamicTypeMgrParamTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrPropertyTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + Version string `xml:"version"` + Type string `xml:"type"` + PrivId string `xml:"privId,omitempty"` + MsgIdFormat string `xml:"msgIdFormat,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +type DynamicTypeMgrQueryTypeInfoRequest struct { + This types.ManagedObjectReference `xml:"_this"` + FilterSpec BaseDynamicTypeMgrFilterSpec `xml:"filterSpec,omitempty,typeattr"` +} + +type DynamicTypeMgrQueryTypeInfoResponse struct { + Returnval DynamicTypeMgrAllTypeInfoRequest `xml:"urn:vim25 returnval"` +} + +func init() { + types.Add("DynamicTypeMgrPropertyTypeInfo", reflect.TypeOf((*DynamicTypeMgrPropertyTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrTypeFilterSpec struct { + DynamicTypeMgrFilterSpec + + TypeSubstr string `xml:"typeSubstr,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrTypeFilterSpec", reflect.TypeOf((*DynamicTypeMgrTypeFilterSpec)(nil)).Elem()) +} + +type ReflectManagedMethodExecuterSoapArgument struct { + types.DynamicData + + Name string `xml:"name"` + Val string `xml:"val"` +} + +func init() { + types.Add("ReflectManagedMethodExecuterSoapArgument", reflect.TypeOf((*ReflectManagedMethodExecuterSoapArgument)(nil)).Elem()) +} + +type ReflectManagedMethodExecuterSoapFault struct { + types.DynamicData + + FaultMsg string `xml:"faultMsg"` + FaultDetail string `xml:"faultDetail,omitempty"` +} + +func init() { + types.Add("ReflectManagedMethodExecuterSoapFault", reflect.TypeOf((*ReflectManagedMethodExecuterSoapFault)(nil)).Elem()) +} + +type ReflectManagedMethodExecuterSoapResult struct { + types.DynamicData + + Response string `xml:"response,omitempty"` + Fault *ReflectManagedMethodExecuterSoapFault `xml:"fault,omitempty"` +} + +type RetrieveDynamicTypeManagerRequest struct { + This types.ManagedObjectReference `xml:"_this"` +} + +type RetrieveDynamicTypeManagerResponse struct { + Returnval *InternalDynamicTypeManager `xml:"urn:vim25 returnval"` +} + +type RetrieveManagedMethodExecuterRequest struct { + This types.ManagedObjectReference `xml:"_this"` +} + +func init() { + types.Add("RetrieveManagedMethodExecuter", reflect.TypeOf((*RetrieveManagedMethodExecuterRequest)(nil)).Elem()) +} + +type RetrieveManagedMethodExecuterResponse struct { + Returnval *ReflectManagedMethodExecuter `xml:"urn:vim25 returnval"` +} + +type InternalDynamicTypeManager struct { + types.ManagedObjectReference +} + +type ReflectManagedMethodExecuter struct { + types.ManagedObjectReference +} + +type ExecuteSoapRequest struct { + This types.ManagedObjectReference `xml:"_this"` + Moid string `xml:"moid"` + Version string `xml:"version"` + Method string `xml:"method"` + Argument []ReflectManagedMethodExecuterSoapArgument `xml:"argument,omitempty"` +} + +type ExecuteSoapResponse struct { + Returnval *ReflectManagedMethodExecuterSoapResult `xml:"urn:vim25 returnval"` +} diff --git a/vendor/github.com/vmware/govmomi/internal/version/version.go b/vendor/github.com/vmware/govmomi/internal/version/version.go new file mode 100644 index 0000000000..f1e0f3d0ee --- /dev/null +++ b/vendor/github.com/vmware/govmomi/internal/version/version.go @@ -0,0 +1,25 @@ +/* +Copyright (c) 2014-2022 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 version + +const ( + // ClientName is the name of this SDK + ClientName = "govmomi" + + // ClientVersion is the version of this SDK + ClientVersion = "0.38.0" +) diff --git a/vendor/github.com/vmware/govmomi/nfc/lease.go b/vendor/github.com/vmware/govmomi/nfc/lease.go new file mode 100644 index 0000000000..406edebfb0 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/nfc/lease.go @@ -0,0 +1,237 @@ +/* +Copyright (c) 2015-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 nfc + +import ( + "context" + "fmt" + "io" + "path" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/task" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +type Lease struct { + types.ManagedObjectReference + + c *vim25.Client +} + +func NewLease(c *vim25.Client, ref types.ManagedObjectReference) *Lease { + return &Lease{ref, c} +} + +// Abort wraps methods.Abort +func (l *Lease) Abort(ctx context.Context, fault *types.LocalizedMethodFault) error { + req := types.HttpNfcLeaseAbort{ + This: l.Reference(), + Fault: fault, + } + + _, err := methods.HttpNfcLeaseAbort(ctx, l.c, &req) + if err != nil { + return err + } + + return nil +} + +// Complete wraps methods.Complete +func (l *Lease) Complete(ctx context.Context) error { + req := types.HttpNfcLeaseComplete{ + This: l.Reference(), + } + + _, err := methods.HttpNfcLeaseComplete(ctx, l.c, &req) + if err != nil { + return err + } + + return nil +} + +// GetManifest wraps methods.GetManifest +func (l *Lease) GetManifest(ctx context.Context) ([]types.HttpNfcLeaseManifestEntry, error) { + req := types.HttpNfcLeaseGetManifest{ + This: l.Reference(), + } + + res, err := methods.HttpNfcLeaseGetManifest(ctx, l.c, &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +// Progress wraps methods.Progress +func (l *Lease) Progress(ctx context.Context, percent int32) error { + req := types.HttpNfcLeaseProgress{ + This: l.Reference(), + Percent: percent, + } + + _, err := methods.HttpNfcLeaseProgress(ctx, l.c, &req) + if err != nil { + return err + } + + return nil +} + +type LeaseInfo struct { + types.HttpNfcLeaseInfo + + Items []FileItem +} + +func (l *Lease) newLeaseInfo(li *types.HttpNfcLeaseInfo, items []types.OvfFileItem) (*LeaseInfo, error) { + info := &LeaseInfo{ + HttpNfcLeaseInfo: *li, + } + + for _, device := range li.DeviceUrl { + u, err := l.c.ParseURL(device.Url) + if err != nil { + return nil, err + } + + if device.SslThumbprint != "" { + // TODO: prefer host management IP + l.c.SetThumbprint(u.Host, device.SslThumbprint) + } + + if len(items) == 0 { + // this is an export + item := types.OvfFileItem{ + DeviceId: device.Key, + Path: device.TargetId, + Size: device.FileSize, + } + + if item.Size == 0 { + item.Size = li.TotalDiskCapacityInKB * 1024 + } + + if item.Path == "" { + item.Path = path.Base(device.Url) + } + + info.Items = append(info.Items, NewFileItem(u, item)) + + continue + } + + // this is an import + for _, item := range items { + if device.ImportKey == item.DeviceId { + fi := NewFileItem(u, item) + fi.Thumbprint = device.SslThumbprint + + info.Items = append(info.Items, fi) + + break + } + } + } + + return info, nil +} + +func (l *Lease) Wait(ctx context.Context, items []types.OvfFileItem) (*LeaseInfo, error) { + var lease mo.HttpNfcLease + + pc := property.DefaultCollector(l.c) + err := property.Wait(ctx, pc, l.Reference(), []string{"state", "info", "error"}, func(pc []types.PropertyChange) bool { + done := false + + for _, c := range pc { + if c.Val == nil { + continue + } + + switch c.Name { + case "error": + val := c.Val.(types.LocalizedMethodFault) + lease.Error = &val + done = true + case "info": + val := c.Val.(types.HttpNfcLeaseInfo) + lease.Info = &val + case "state": + lease.State = c.Val.(types.HttpNfcLeaseState) + if lease.State != types.HttpNfcLeaseStateInitializing { + done = true + } + } + } + + return done + }) + + if err != nil { + return nil, err + } + + if lease.State == types.HttpNfcLeaseStateReady { + return l.newLeaseInfo(lease.Info, items) + } + + if lease.Error != nil { + return nil, &task.Error{LocalizedMethodFault: lease.Error} + } + + return nil, fmt.Errorf("unexpected nfc lease state: %s", lease.State) +} + +func (l *Lease) StartUpdater(ctx context.Context, info *LeaseInfo) *LeaseUpdater { + return newLeaseUpdater(ctx, l, info) +} + +func (l *Lease) Upload(ctx context.Context, item FileItem, f io.Reader, opts soap.Upload) error { + if opts.Progress == nil { + opts.Progress = item + } + + // Non-disk files (such as .iso) use the PUT method. + // Overwrite: t header is also required in this case (ovftool does the same) + if item.Create { + opts.Method = "PUT" + opts.Headers = map[string]string{ + "Overwrite": "t", + } + } else { + opts.Method = "POST" + opts.Type = "application/x-vnd.vmware-streamVmdk" + } + + return l.c.Upload(ctx, f, item.URL, &opts) +} + +func (l *Lease) DownloadFile(ctx context.Context, file string, item FileItem, opts soap.Download) error { + if opts.Progress == nil { + opts.Progress = item + } + + return l.c.DownloadFile(ctx, file, item.URL, &opts) +} diff --git a/vendor/github.com/vmware/govmomi/nfc/lease_updater.go b/vendor/github.com/vmware/govmomi/nfc/lease_updater.go new file mode 100644 index 0000000000..baa196c674 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/nfc/lease_updater.go @@ -0,0 +1,148 @@ +/* +Copyright (c) 2014-2015 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 nfc + +import ( + "context" + "log" + "net/url" + "sync" + "sync/atomic" + "time" + + "github.com/vmware/govmomi/vim25/progress" + "github.com/vmware/govmomi/vim25/types" +) + +type FileItem struct { + types.OvfFileItem + + URL *url.URL + Thumbprint string + + ch chan progress.Report +} + +func NewFileItem(u *url.URL, item types.OvfFileItem) FileItem { + return FileItem{ + OvfFileItem: item, + URL: u, + ch: make(chan progress.Report), + } +} + +func (o FileItem) Sink() chan<- progress.Report { + return o.ch +} + +// File converts the FileItem.OvfFileItem to an OvfFile +func (o FileItem) File() types.OvfFile { + return types.OvfFile{ + DeviceId: o.DeviceId, + Path: o.Path, + Size: o.Size, + } +} + +type LeaseUpdater struct { + pos int64 // Number of bytes (keep first to ensure 64 bit alignment) + total int64 // Total number of bytes (keep first to ensure 64 bit alignment) + + lease *Lease + + done chan struct{} // When lease updater should stop + + wg sync.WaitGroup // Track when update loop is done +} + +func newLeaseUpdater(ctx context.Context, lease *Lease, info *LeaseInfo) *LeaseUpdater { + l := LeaseUpdater{ + lease: lease, + + done: make(chan struct{}), + } + + for _, item := range info.Items { + l.total += item.Size + go l.waitForProgress(item) + } + + // Kickstart update loop + l.wg.Add(1) + go l.run() + + return &l +} + +func (l *LeaseUpdater) waitForProgress(item FileItem) { + var pos, total int64 + + total = item.Size + + for { + select { + case <-l.done: + return + case p, ok := <-item.ch: + // Return in case of error + if ok && p.Error() != nil { + return + } + + if !ok { + // Last element on the channel, add to total + atomic.AddInt64(&l.pos, total-pos) + return + } + + // Approximate progress in number of bytes + x := int64(float32(total) * (p.Percentage() / 100.0)) + atomic.AddInt64(&l.pos, x-pos) + pos = x + } + } +} + +func (l *LeaseUpdater) run() { + defer l.wg.Done() + + tick := time.NewTicker(2 * time.Second) + defer tick.Stop() + + for { + select { + case <-l.done: + return + case <-tick.C: + // From the vim api HttpNfcLeaseProgress(percent) doc, percent == + // "Completion status represented as an integer in the 0-100 range." + // Always report the current value of percent, as it will renew the + // lease even if the value hasn't changed or is 0. + percent := int32(float32(100*atomic.LoadInt64(&l.pos)) / float32(l.total)) + err := l.lease.Progress(context.TODO(), percent) + if err != nil { + log.Printf("NFC lease progress: %s", err) + return + } + } + } +} + +func (l *LeaseUpdater) Done() { + close(l.done) + l.wg.Wait() +} diff --git a/vendor/github.com/vmware/govmomi/object/authorization_manager.go b/vendor/github.com/vmware/govmomi/object/authorization_manager.go new file mode 100644 index 0000000000..5cd6851a87 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/authorization_manager.go @@ -0,0 +1,221 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type AuthorizationManager struct { + Common +} + +func NewAuthorizationManager(c *vim25.Client) *AuthorizationManager { + m := AuthorizationManager{ + Common: NewCommon(c, *c.ServiceContent.AuthorizationManager), + } + + return &m +} + +type AuthorizationRoleList []types.AuthorizationRole + +func (l AuthorizationRoleList) ById(id int32) *types.AuthorizationRole { + for _, role := range l { + if role.RoleId == id { + return &role + } + } + + return nil +} + +func (l AuthorizationRoleList) ByName(name string) *types.AuthorizationRole { + for _, role := range l { + if role.Name == name { + return &role + } + } + + return nil +} + +func (m AuthorizationManager) RoleList(ctx context.Context) (AuthorizationRoleList, error) { + var am mo.AuthorizationManager + + err := m.Properties(ctx, m.Reference(), []string{"roleList"}, &am) + if err != nil { + return nil, err + } + + return AuthorizationRoleList(am.RoleList), nil +} + +func (m AuthorizationManager) RetrieveEntityPermissions(ctx context.Context, entity types.ManagedObjectReference, inherited bool) ([]types.Permission, error) { + req := types.RetrieveEntityPermissions{ + This: m.Reference(), + Entity: entity, + Inherited: inherited, + } + + res, err := methods.RetrieveEntityPermissions(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) RemoveEntityPermission(ctx context.Context, entity types.ManagedObjectReference, user string, isGroup bool) error { + req := types.RemoveEntityPermission{ + This: m.Reference(), + Entity: entity, + User: user, + IsGroup: isGroup, + } + + _, err := methods.RemoveEntityPermission(ctx, m.Client(), &req) + return err +} + +func (m AuthorizationManager) SetEntityPermissions(ctx context.Context, entity types.ManagedObjectReference, permission []types.Permission) error { + req := types.SetEntityPermissions{ + This: m.Reference(), + Entity: entity, + Permission: permission, + } + + _, err := methods.SetEntityPermissions(ctx, m.Client(), &req) + return err +} + +func (m AuthorizationManager) RetrieveRolePermissions(ctx context.Context, id int32) ([]types.Permission, error) { + req := types.RetrieveRolePermissions{ + This: m.Reference(), + RoleId: id, + } + + res, err := methods.RetrieveRolePermissions(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) RetrieveAllPermissions(ctx context.Context) ([]types.Permission, error) { + req := types.RetrieveAllPermissions{ + This: m.Reference(), + } + + res, err := methods.RetrieveAllPermissions(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) AddRole(ctx context.Context, name string, ids []string) (int32, error) { + req := types.AddAuthorizationRole{ + This: m.Reference(), + Name: name, + PrivIds: ids, + } + + res, err := methods.AddAuthorizationRole(ctx, m.Client(), &req) + if err != nil { + return -1, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) RemoveRole(ctx context.Context, id int32, failIfUsed bool) error { + req := types.RemoveAuthorizationRole{ + This: m.Reference(), + RoleId: id, + FailIfUsed: failIfUsed, + } + + _, err := methods.RemoveAuthorizationRole(ctx, m.Client(), &req) + return err +} + +func (m AuthorizationManager) UpdateRole(ctx context.Context, id int32, name string, ids []string) error { + req := types.UpdateAuthorizationRole{ + This: m.Reference(), + RoleId: id, + NewName: name, + PrivIds: ids, + } + + _, err := methods.UpdateAuthorizationRole(ctx, m.Client(), &req) + return err +} + +func (m AuthorizationManager) HasUserPrivilegeOnEntities(ctx context.Context, entities []types.ManagedObjectReference, userName string, privID []string) ([]types.EntityPrivilege, error) { + req := types.HasUserPrivilegeOnEntities{ + This: m.Reference(), + Entities: entities, + UserName: userName, + PrivId: privID, + } + + res, err := methods.HasUserPrivilegeOnEntities(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) HasPrivilegeOnEntity(ctx context.Context, entity types.ManagedObjectReference, sessionID string, privID []string) ([]bool, error) { + req := types.HasPrivilegeOnEntity{ + This: m.Reference(), + Entity: entity, + SessionId: sessionID, + PrivId: privID, + } + + res, err := methods.HasPrivilegeOnEntity(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) FetchUserPrivilegeOnEntities(ctx context.Context, entities []types.ManagedObjectReference, userName string) ([]types.UserPrivilegeResult, error) { + req := types.FetchUserPrivilegeOnEntities{ + This: m.Reference(), + Entities: entities, + UserName: userName, + } + + res, err := methods.FetchUserPrivilegeOnEntities(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/authorization_manager_internal.go b/vendor/github.com/vmware/govmomi/object/authorization_manager_internal.go new file mode 100644 index 0000000000..4fa520f5ad --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/authorization_manager_internal.go @@ -0,0 +1,86 @@ +/* +Copyright (c) 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +type DisabledMethodRequest struct { + Method string `xml:"method"` + Reason string `xml:"reasonId"` +} + +type disableMethodsRequest struct { + This types.ManagedObjectReference `xml:"_this"` + Entity []types.ManagedObjectReference `xml:"entity"` + Method []DisabledMethodRequest `xml:"method"` + Source string `xml:"sourceId"` + Scope bool `xml:"sessionScope,omitempty"` +} + +type disableMethodsBody struct { + Req *disableMethodsRequest `xml:"urn:internalvim25 DisableMethods,omitempty"` + Res interface{} `xml:"urn:vim25 DisableMethodsResponse,omitempty"` + Err *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *disableMethodsBody) Fault() *soap.Fault { return b.Err } + +func (m AuthorizationManager) DisableMethods(ctx context.Context, entity []types.ManagedObjectReference, method []DisabledMethodRequest, source string) error { + var reqBody, resBody disableMethodsBody + + reqBody.Req = &disableMethodsRequest{ + This: m.Reference(), + Entity: entity, + Method: method, + Source: source, + } + + return m.Client().RoundTrip(ctx, &reqBody, &resBody) +} + +type enableMethodsRequest struct { + This types.ManagedObjectReference `xml:"_this"` + Entity []types.ManagedObjectReference `xml:"entity"` + Method []string `xml:"method"` + Source string `xml:"sourceId"` +} + +type enableMethodsBody struct { + Req *enableMethodsRequest `xml:"urn:internalvim25 EnableMethods,omitempty"` + Res interface{} `xml:"urn:vim25 EnableMethodsResponse,omitempty"` + Err *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *enableMethodsBody) Fault() *soap.Fault { return b.Err } + +func (m AuthorizationManager) EnableMethods(ctx context.Context, entity []types.ManagedObjectReference, method []string, source string) error { + var reqBody, resBody enableMethodsBody + + reqBody.Req = &enableMethodsRequest{ + This: m.Reference(), + Entity: entity, + Method: method, + Source: source, + } + + return m.Client().RoundTrip(ctx, &reqBody, &resBody) +} diff --git a/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go b/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go new file mode 100644 index 0000000000..018372dfe0 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go @@ -0,0 +1,103 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type ClusterComputeResource struct { + ComputeResource +} + +func NewClusterComputeResource(c *vim25.Client, ref types.ManagedObjectReference) *ClusterComputeResource { + return &ClusterComputeResource{ + ComputeResource: *NewComputeResource(c, ref), + } +} + +func (c ClusterComputeResource) Configuration(ctx context.Context) (*types.ClusterConfigInfoEx, error) { + var obj mo.ClusterComputeResource + + err := c.Properties(ctx, c.Reference(), []string{"configurationEx"}, &obj) + if err != nil { + return nil, err + } + + return obj.ConfigurationEx.(*types.ClusterConfigInfoEx), nil +} + +func (c ClusterComputeResource) AddHost(ctx context.Context, spec types.HostConnectSpec, asConnected bool, license *string, resourcePool *types.ManagedObjectReference) (*Task, error) { + req := types.AddHost_Task{ + This: c.Reference(), + Spec: spec, + AsConnected: asConnected, + } + + if license != nil { + req.License = *license + } + + if resourcePool != nil { + req.ResourcePool = resourcePool + } + + res, err := methods.AddHost_Task(ctx, c.c, &req) + if err != nil { + return nil, err + } + + 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 +} + +func (c ClusterComputeResource) PlaceVm(ctx context.Context, spec types.PlacementSpec) (*types.PlacementResult, error) { + req := types.PlaceVm{ + This: c.Reference(), + PlacementSpec: spec, + } + + res, err := methods.PlaceVm(ctx, c.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/common.go b/vendor/github.com/vmware/govmomi/object/common.go new file mode 100644 index 0000000000..88ce78fce5 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/common.go @@ -0,0 +1,148 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "errors" + "fmt" + "path" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +var ( + ErrNotSupported = errors.New("product/version specific feature not supported by target") +) + +// Common contains the fields and functions common to all objects. +type Common struct { + InventoryPath string + + c *vim25.Client + r types.ManagedObjectReference +} + +func (c Common) String() string { + ref := fmt.Sprintf("%v", c.Reference()) + + if c.InventoryPath == "" { + return ref + } + + return fmt.Sprintf("%s @ %s", ref, c.InventoryPath) +} + +func NewCommon(c *vim25.Client, r types.ManagedObjectReference) Common { + return Common{c: c, r: r} +} + +func (c Common) Reference() types.ManagedObjectReference { + return c.r +} + +func (c Common) Client() *vim25.Client { + return c.c +} + +// Name returns the base name of the InventoryPath field +func (c Common) Name() string { + if c.InventoryPath == "" { + return "" + } + return path.Base(c.InventoryPath) +} + +func (c *Common) SetInventoryPath(p string) { + c.InventoryPath = p +} + +// ObjectName fetches the mo.ManagedEntity.Name field via the property collector. +func (c Common) ObjectName(ctx context.Context) (string, error) { + var content []types.ObjectContent + + err := c.Properties(ctx, c.Reference(), []string{"name"}, &content) + if err != nil { + return "", err + } + + for i := range content { + for _, prop := range content[i].PropSet { + return prop.Val.(string), nil + } + } + + return "", nil +} + +// Properties is a wrapper for property.DefaultCollector().RetrieveOne() +func (c Common) Properties(ctx context.Context, r types.ManagedObjectReference, ps []string, dst interface{}) error { + return property.DefaultCollector(c.c).RetrieveOne(ctx, r, ps, dst) +} + +func (c Common) Destroy(ctx context.Context) (*Task, error) { + req := types.Destroy_Task{ + This: c.Reference(), + } + + res, err := methods.Destroy_Task(ctx, c.c, &req) + if err != nil { + return nil, err + } + + return NewTask(c.c, res.Returnval), nil +} + +func (c Common) Rename(ctx context.Context, name string) (*Task, error) { + req := types.Rename_Task{ + This: c.Reference(), + NewName: name, + } + + res, err := methods.Rename_Task(ctx, c.c, &req) + if err != nil { + return nil, err + } + + return NewTask(c.c, res.Returnval), nil +} + +func (c Common) SetCustomValue(ctx context.Context, key string, value string) error { + req := types.SetCustomValue{ + This: c.Reference(), + Key: key, + Value: value, + } + + _, err := methods.SetCustomValue(ctx, c.c, &req) + return err +} + +func ReferenceFromString(s string) *types.ManagedObjectReference { + var ref types.ManagedObjectReference + if !ref.FromString(s) { + return nil + } + if mo.IsManagedObjectType(ref.Type) { + return &ref + } + return nil +} diff --git a/vendor/github.com/vmware/govmomi/object/compute_resource.go b/vendor/github.com/vmware/govmomi/object/compute_resource.go new file mode 100644 index 0000000000..4a2db74117 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/compute_resource.go @@ -0,0 +1,127 @@ +/* +Copyright (c) 2015-2023 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 object + +import ( + "context" + "fmt" + "path" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type ComputeResource struct { + Common +} + +func NewComputeResource(c *vim25.Client, ref types.ManagedObjectReference) *ComputeResource { + return &ComputeResource{ + Common: NewCommon(c, ref), + } +} + +func (c ComputeResource) Hosts(ctx context.Context) ([]*HostSystem, error) { + var cr mo.ComputeResource + + err := c.Properties(ctx, c.Reference(), []string{"host"}, &cr) + if err != nil { + return nil, err + } + + if len(cr.Host) == 0 { + return nil, nil + } + + var hs []mo.HostSystem + pc := property.DefaultCollector(c.Client()) + err = pc.Retrieve(ctx, cr.Host, []string{"name"}, &hs) + if err != nil { + return nil, err + } + + var hosts []*HostSystem + + for _, h := range hs { + host := NewHostSystem(c.Client(), h.Reference()) + host.InventoryPath = path.Join(c.InventoryPath, h.Name) + hosts = append(hosts, host) + } + + return hosts, nil +} + +func (c ComputeResource) Datastores(ctx context.Context) ([]*Datastore, error) { + var cr mo.ComputeResource + + err := c.Properties(ctx, c.Reference(), []string{"datastore"}, &cr) + if err != nil { + return nil, err + } + + var dss []*Datastore + for _, ref := range cr.Datastore { + ds := NewDatastore(c.c, ref) + dss = append(dss, ds) + } + + return dss, nil +} + +func (c ComputeResource) EnvironmentBrowser(ctx context.Context) (*EnvironmentBrowser, error) { + var cr mo.ComputeResource + + err := c.Properties(ctx, c.Reference(), []string{"environmentBrowser"}, &cr) + if err != nil { + return nil, err + } + + if cr.EnvironmentBrowser == nil { + return nil, fmt.Errorf("%s: nil environmentBrowser", c.Reference()) + } + + return NewEnvironmentBrowser(c.c, *cr.EnvironmentBrowser), nil +} + +func (c ComputeResource) ResourcePool(ctx context.Context) (*ResourcePool, error) { + var cr mo.ComputeResource + + err := c.Properties(ctx, c.Reference(), []string{"resourcePool"}, &cr) + if err != nil { + return nil, err + } + + return NewResourcePool(c.c, *cr.ResourcePool), nil +} + +func (c ComputeResource) Reconfigure(ctx context.Context, spec types.BaseComputeResourceConfigSpec, modify bool) (*Task, error) { + req := types.ReconfigureComputeResource_Task{ + This: c.Reference(), + Spec: spec, + Modify: modify, + } + + res, err := methods.ReconfigureComputeResource_Task(ctx, c.c, &req) + if err != nil { + return nil, err + } + + return NewTask(c.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/custom_fields_manager.go b/vendor/github.com/vmware/govmomi/object/custom_fields_manager.go new file mode 100644 index 0000000000..ef748ef2c1 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/custom_fields_manager.go @@ -0,0 +1,146 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "errors" + "strconv" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +var ( + ErrKeyNameNotFound = errors.New("key name not found") +) + +type CustomFieldsManager struct { + Common +} + +// GetCustomFieldsManager wraps NewCustomFieldsManager, returning ErrNotSupported +// when the client is not connected to a vCenter instance. +func GetCustomFieldsManager(c *vim25.Client) (*CustomFieldsManager, error) { + if c.ServiceContent.CustomFieldsManager == nil { + return nil, ErrNotSupported + } + return NewCustomFieldsManager(c), nil +} + +func NewCustomFieldsManager(c *vim25.Client) *CustomFieldsManager { + m := CustomFieldsManager{ + Common: NewCommon(c, *c.ServiceContent.CustomFieldsManager), + } + + return &m +} + +func (m CustomFieldsManager) Add(ctx context.Context, name string, moType string, fieldDefPolicy *types.PrivilegePolicyDef, fieldPolicy *types.PrivilegePolicyDef) (*types.CustomFieldDef, error) { + req := types.AddCustomFieldDef{ + This: m.Reference(), + Name: name, + MoType: moType, + FieldDefPolicy: fieldDefPolicy, + FieldPolicy: fieldPolicy, + } + + res, err := methods.AddCustomFieldDef(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +func (m CustomFieldsManager) Remove(ctx context.Context, key int32) error { + req := types.RemoveCustomFieldDef{ + This: m.Reference(), + Key: key, + } + + _, err := methods.RemoveCustomFieldDef(ctx, m.c, &req) + return err +} + +func (m CustomFieldsManager) Rename(ctx context.Context, key int32, name string) error { + req := types.RenameCustomFieldDef{ + This: m.Reference(), + Key: key, + Name: name, + } + + _, err := methods.RenameCustomFieldDef(ctx, m.c, &req) + return err +} + +func (m CustomFieldsManager) Set(ctx context.Context, entity types.ManagedObjectReference, key int32, value string) error { + req := types.SetField{ + This: m.Reference(), + Entity: entity, + Key: key, + Value: value, + } + + _, err := methods.SetField(ctx, m.c, &req) + return err +} + +type CustomFieldDefList []types.CustomFieldDef + +func (m CustomFieldsManager) Field(ctx context.Context) (CustomFieldDefList, error) { + var fm mo.CustomFieldsManager + + err := m.Properties(ctx, m.Reference(), []string{"field"}, &fm) + if err != nil { + return nil, err + } + + return fm.Field, nil +} + +func (m CustomFieldsManager) FindKey(ctx context.Context, name string) (int32, error) { + field, err := m.Field(ctx) + if err != nil { + return -1, err + } + + for _, def := range field { + if def.Name == name { + return def.Key, nil + } + } + + k, err := strconv.Atoi(name) + if err == nil { + // assume literal int key + return int32(k), nil + } + + return -1, ErrKeyNameNotFound +} + +func (l CustomFieldDefList) ByKey(key int32) *types.CustomFieldDef { + for _, def := range l { + if def.Key == key { + return &def + } + } + return nil +} diff --git a/vendor/github.com/vmware/govmomi/object/customization_spec_manager.go b/vendor/github.com/vmware/govmomi/object/customization_spec_manager.go new file mode 100644 index 0000000000..e9a3914d9d --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/customization_spec_manager.go @@ -0,0 +1,173 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type CustomizationSpecManager struct { + Common +} + +func NewCustomizationSpecManager(c *vim25.Client) *CustomizationSpecManager { + cs := CustomizationSpecManager{ + Common: NewCommon(c, *c.ServiceContent.CustomizationSpecManager), + } + + return &cs +} + +func (cs CustomizationSpecManager) Info(ctx context.Context) ([]types.CustomizationSpecInfo, error) { + var m mo.CustomizationSpecManager + err := cs.Properties(ctx, cs.Reference(), []string{"info"}, &m) + return m.Info, err +} + +func (cs CustomizationSpecManager) DoesCustomizationSpecExist(ctx context.Context, name string) (bool, error) { + req := types.DoesCustomizationSpecExist{ + This: cs.Reference(), + Name: name, + } + + res, err := methods.DoesCustomizationSpecExist(ctx, cs.c, &req) + + if err != nil { + return false, err + } + + return res.Returnval, nil +} + +func (cs CustomizationSpecManager) GetCustomizationSpec(ctx context.Context, name string) (*types.CustomizationSpecItem, error) { + req := types.GetCustomizationSpec{ + This: cs.Reference(), + Name: name, + } + + res, err := methods.GetCustomizationSpec(ctx, cs.c, &req) + + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +func (cs CustomizationSpecManager) CreateCustomizationSpec(ctx context.Context, item types.CustomizationSpecItem) error { + req := types.CreateCustomizationSpec{ + This: cs.Reference(), + Item: item, + } + + _, err := methods.CreateCustomizationSpec(ctx, cs.c, &req) + if err != nil { + return err + } + + return nil +} + +func (cs CustomizationSpecManager) OverwriteCustomizationSpec(ctx context.Context, item types.CustomizationSpecItem) error { + req := types.OverwriteCustomizationSpec{ + This: cs.Reference(), + Item: item, + } + + _, err := methods.OverwriteCustomizationSpec(ctx, cs.c, &req) + if err != nil { + return err + } + + return nil +} + +func (cs CustomizationSpecManager) DeleteCustomizationSpec(ctx context.Context, name string) error { + req := types.DeleteCustomizationSpec{ + This: cs.Reference(), + Name: name, + } + + _, err := methods.DeleteCustomizationSpec(ctx, cs.c, &req) + if err != nil { + return err + } + + return nil +} + +func (cs CustomizationSpecManager) DuplicateCustomizationSpec(ctx context.Context, name string, newName string) error { + req := types.DuplicateCustomizationSpec{ + This: cs.Reference(), + Name: name, + NewName: newName, + } + + _, err := methods.DuplicateCustomizationSpec(ctx, cs.c, &req) + if err != nil { + return err + } + + return nil +} + +func (cs CustomizationSpecManager) RenameCustomizationSpec(ctx context.Context, name string, newName string) error { + req := types.RenameCustomizationSpec{ + This: cs.Reference(), + Name: name, + NewName: newName, + } + + _, err := methods.RenameCustomizationSpec(ctx, cs.c, &req) + if err != nil { + return err + } + + return nil +} + +func (cs CustomizationSpecManager) CustomizationSpecItemToXml(ctx context.Context, item types.CustomizationSpecItem) (string, error) { + req := types.CustomizationSpecItemToXml{ + This: cs.Reference(), + Item: item, + } + + res, err := methods.CustomizationSpecItemToXml(ctx, cs.c, &req) + if err != nil { + return "", err + } + + return res.Returnval, nil +} + +func (cs CustomizationSpecManager) XmlToCustomizationSpecItem(ctx context.Context, xml string) (*types.CustomizationSpecItem, error) { + req := types.XmlToCustomizationSpecItem{ + This: cs.Reference(), + SpecItemXml: xml, + } + + res, err := methods.XmlToCustomizationSpecItem(ctx, cs.c, &req) + if err != nil { + return nil, err + } + return &res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/datacenter.go b/vendor/github.com/vmware/govmomi/object/datacenter.go new file mode 100644 index 0000000000..41fa352657 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/datacenter.go @@ -0,0 +1,129 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type DatacenterFolders struct { + VmFolder *Folder + HostFolder *Folder + DatastoreFolder *Folder + NetworkFolder *Folder +} + +type Datacenter struct { + Common +} + +func NewDatacenter(c *vim25.Client, ref types.ManagedObjectReference) *Datacenter { + return &Datacenter{ + Common: NewCommon(c, ref), + } +} + +func (d *Datacenter) Folders(ctx context.Context) (*DatacenterFolders, error) { + var md mo.Datacenter + + ps := []string{"name", "vmFolder", "hostFolder", "datastoreFolder", "networkFolder"} + err := d.Properties(ctx, d.Reference(), ps, &md) + if err != nil { + return nil, err + } + + df := &DatacenterFolders{ + VmFolder: NewFolder(d.c, md.VmFolder), + HostFolder: NewFolder(d.c, md.HostFolder), + DatastoreFolder: NewFolder(d.c, md.DatastoreFolder), + NetworkFolder: NewFolder(d.c, md.NetworkFolder), + } + + paths := []struct { + name string + path *string + }{ + {"vm", &df.VmFolder.InventoryPath}, + {"host", &df.HostFolder.InventoryPath}, + {"datastore", &df.DatastoreFolder.InventoryPath}, + {"network", &df.NetworkFolder.InventoryPath}, + } + + for _, p := range paths { + *p.path = fmt.Sprintf("/%s/%s", md.Name, p.name) + } + + return df, nil +} + +func (d Datacenter) Destroy(ctx context.Context) (*Task, error) { + req := types.Destroy_Task{ + This: d.Reference(), + } + + res, err := methods.Destroy_Task(ctx, d.c, &req) + if err != nil { + return nil, err + } + + return NewTask(d.c, res.Returnval), nil +} + +// PowerOnVM powers on multiple virtual machines with a single vCenter call. +// If called against ESX, serially powers on the list of VMs and the returned *Task will always be nil. +func (d Datacenter) PowerOnVM(ctx context.Context, vm []types.ManagedObjectReference, option ...types.BaseOptionValue) (*Task, error) { + if d.Client().IsVC() { + req := types.PowerOnMultiVM_Task{ + This: d.Reference(), + Vm: vm, + Option: option, + } + + res, err := methods.PowerOnMultiVM_Task(ctx, d.c, &req) + if err != nil { + return nil, err + } + + return NewTask(d.c, res.Returnval), nil + } + + for _, ref := range vm { + obj := NewVirtualMachine(d.Client(), ref) + task, err := obj.PowerOn(ctx) + if err != nil { + return nil, err + } + + err = task.Wait(ctx) + if err != nil { + // Ignore any InvalidPowerState fault, as it indicates the VM is already powered on + if f, ok := err.(types.HasFault); ok { + if _, ok = f.Fault().(*types.InvalidPowerState); !ok { + return nil, err + } + } + } + } + + return nil, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/datastore.go b/vendor/github.com/vmware/govmomi/object/datastore.go new file mode 100644 index 0000000000..991ad4f822 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/datastore.go @@ -0,0 +1,498 @@ +/* +Copyright (c) 2015-2016 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 object + +import ( + "context" + "fmt" + "io" + "math/rand" + "net/http" + "net/url" + "os" + "path" + "strings" + + "github.com/vmware/govmomi/internal" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/session" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// DatastoreNoSuchDirectoryError is returned when a directory could not be found. +type DatastoreNoSuchDirectoryError struct { + verb string + subject string +} + +func (e DatastoreNoSuchDirectoryError) Error() string { + return fmt.Sprintf("cannot %s '%s': No such directory", e.verb, e.subject) +} + +// DatastoreNoSuchFileError is returned when a file could not be found. +type DatastoreNoSuchFileError struct { + verb string + subject string +} + +func (e DatastoreNoSuchFileError) Error() string { + return fmt.Sprintf("cannot %s '%s': No such file", e.verb, e.subject) +} + +type Datastore struct { + Common + + DatacenterPath string +} + +func NewDatastore(c *vim25.Client, ref types.ManagedObjectReference) *Datastore { + return &Datastore{ + Common: NewCommon(c, ref), + } +} + +// FindInventoryPath sets InventoryPath and DatacenterPath, +// needed by NewURL() to compose an upload/download endpoint URL +func (d *Datastore) FindInventoryPath(ctx context.Context) error { + entities, err := mo.Ancestors(ctx, d.c, d.c.ServiceContent.PropertyCollector, d.r) + if err != nil { + return err + } + + val := "/" + + for _, entity := range entities { + if entity.Parent == nil { + continue // root folder + } + val = path.Join(val, entity.Name) + if entity.Self.Type == "Datacenter" { + d.DatacenterPath = val + } + } + + d.InventoryPath = val + + return nil +} + +func (d Datastore) Path(path string) string { + var p DatastorePath + if p.FromString(path) { + return p.String() // already in "[datastore] path" format + } + + return (&DatastorePath{ + Datastore: d.Name(), + Path: path, + }).String() +} + +// NewURL constructs a url.URL with the given file path for datastore access over HTTP. +func (d Datastore) NewURL(path string) *url.URL { + u := d.c.URL() + + scheme := u.Scheme + // In rare cases where vCenter and ESX are accessed using different schemes. + if overrideScheme := os.Getenv("GOVMOMI_DATASTORE_ACCESS_SCHEME"); overrideScheme != "" { + scheme = overrideScheme + } + + return &url.URL{ + Scheme: scheme, + Host: u.Host, + Path: fmt.Sprintf("/folder/%s", path), + RawQuery: url.Values{ + "dcPath": []string{d.DatacenterPath}, + "dsName": []string{d.Name()}, + }.Encode(), + } +} + +func (d Datastore) Browser(ctx context.Context) (*HostDatastoreBrowser, error) { + var do mo.Datastore + + err := d.Properties(ctx, d.Reference(), []string{"browser"}, &do) + if err != nil { + return nil, err + } + + return NewHostDatastoreBrowser(d.c, do.Browser), nil +} + +func (d Datastore) useServiceTicket() bool { + // If connected to workstation, service ticketing not supported + // If connected to ESX, service ticketing not needed + if !d.c.IsVC() { + return false + } + + key := "GOVMOMI_USE_SERVICE_TICKET" + + val := d.c.URL().Query().Get(key) + if val == "" { + val = os.Getenv(key) + } + + if val == "1" || val == "true" { + return true + } + + return false +} + +func (d Datastore) useServiceTicketHostName(name string) bool { + // No need if talking directly to ESX. + if !d.c.IsVC() { + return false + } + + // If version happens to be < 5.1 + if name == "" { + return false + } + + // If the HostSystem is using DHCP on a network without dynamic DNS, + // HostSystem.Config.Network.DnsConfig.HostName is set to "localhost" by default. + // This resolves to "localhost.localdomain" by default via /etc/hosts on ESX. + // In that case, we will stick with the HostSystem.Name which is the IP address that + // was used to connect the host to VC. + if name == "localhost.localdomain" { + return false + } + + // Still possible to have HostName that don't resolve via DNS, + // so we default to false. + key := "GOVMOMI_USE_SERVICE_TICKET_HOSTNAME" + + val := d.c.URL().Query().Get(key) + if val == "" { + val = os.Getenv(key) + } + + if val == "1" || val == "true" { + return true + } + + return false +} + +type datastoreServiceTicketHostKey struct{} + +// HostContext returns a Context where the given host will be used for datastore HTTP access +// via the ServiceTicket method. +func (d Datastore) HostContext(ctx context.Context, host *HostSystem) context.Context { + return context.WithValue(ctx, datastoreServiceTicketHostKey{}, host) +} + +// ServiceTicket obtains a ticket via AcquireGenericServiceTicket and returns it an http.Cookie with the url.URL +// that can be used along with the ticket cookie to access the given path. An host is chosen at random unless the +// the given Context was created with a specific host via the HostContext method. +func (d Datastore) ServiceTicket(ctx context.Context, path string, method string) (*url.URL, *http.Cookie, error) { + if d.InventoryPath == "" { + _ = d.FindInventoryPath(ctx) + } + + u := d.NewURL(path) + + host, ok := ctx.Value(datastoreServiceTicketHostKey{}).(*HostSystem) + + if !ok { + if !d.useServiceTicket() { + return u, nil, nil + } + + hosts, err := d.AttachedHosts(ctx) + if err != nil { + return nil, nil, err + } + + if len(hosts) == 0 { + // Fallback to letting vCenter choose a host + return u, nil, nil + } + + // Pick a random attached host + host = hosts[rand.Intn(len(hosts))] + } + + ips, err := host.ManagementIPs(ctx) + if err != nil { + return nil, nil, err + } + + if len(ips) > 0 { + // prefer a ManagementIP + u.Host = ips[0].String() + } else { + // fallback to inventory name + u.Host, err = host.ObjectName(ctx) + if err != nil { + return nil, nil, err + } + } + + // VC datacenter path will not be valid against ESX + q := u.Query() + delete(q, "dcPath") + u.RawQuery = q.Encode() + + // Now that we have a host selected, take a copy of the URL. + transferURL := *u + + if internal.UsingEnvoySidecar(d.Client()) { + // Rewrite the host URL to go through the Envoy sidecar on VC. + // Reciever must use a custom dialer. + u = internal.HostGatewayTransferURL(u, host.Reference()) + } + + spec := types.SessionManagerHttpServiceRequestSpec{ + // Use the original URL (without rewrites) for the session ticket. + Url: transferURL.String(), + // See SessionManagerHttpServiceRequestSpecMethod enum + Method: fmt.Sprintf("http%s%s", method[0:1], strings.ToLower(method[1:])), + } + + sm := session.NewManager(d.Client()) + + ticket, err := sm.AcquireGenericServiceTicket(ctx, &spec) + if err != nil { + return nil, nil, err + } + + cookie := &http.Cookie{ + Name: "vmware_cgi_ticket", + Value: ticket.Id, + } + + if d.useServiceTicketHostName(ticket.HostName) { + u.Host = ticket.HostName + } + + d.Client().SetThumbprint(u.Host, ticket.SslThumbprint) + + return u, cookie, nil +} + +func (d Datastore) uploadTicket(ctx context.Context, path string, param *soap.Upload) (*url.URL, *soap.Upload, error) { + p := soap.DefaultUpload + if param != nil { + p = *param // copy + } + + u, ticket, err := d.ServiceTicket(ctx, path, p.Method) + if err != nil { + return nil, nil, err + } + + if ticket != nil { + p.Ticket = ticket + p.Close = true // disable Keep-Alive connection to ESX + } + + return u, &p, nil +} + +func (d Datastore) downloadTicket(ctx context.Context, path string, param *soap.Download) (*url.URL, *soap.Download, error) { + p := soap.DefaultDownload + if param != nil { + p = *param // copy + } + + u, ticket, err := d.ServiceTicket(ctx, path, p.Method) + if err != nil { + return nil, nil, err + } + + if ticket != nil { + p.Ticket = ticket + p.Close = true // disable Keep-Alive connection to ESX + } + + return u, &p, nil +} + +// Upload via soap.Upload with an http service ticket +func (d Datastore) Upload(ctx context.Context, f io.Reader, path string, param *soap.Upload) error { + u, p, err := d.uploadTicket(ctx, path, param) + if err != nil { + return err + } + return d.Client().Upload(ctx, f, u, p) +} + +// UploadFile via soap.Upload with an http service ticket +func (d Datastore) UploadFile(ctx context.Context, file string, path string, param *soap.Upload) error { + u, p, err := d.uploadTicket(ctx, path, param) + if err != nil { + return err + } + vc := d.Client() + if internal.UsingEnvoySidecar(vc) { + // Override the vim client with a new one that wraps a Unix socket transport. + // Using HTTP here so secure means nothing. + vc = internal.ClientWithEnvoyHostGateway(vc) + } + return vc.UploadFile(ctx, file, u, p) +} + +// Download via soap.Download with an http service ticket +func (d Datastore) Download(ctx context.Context, path string, param *soap.Download) (io.ReadCloser, int64, error) { + u, p, err := d.downloadTicket(ctx, path, param) + if err != nil { + return nil, 0, err + } + return d.Client().Download(ctx, u, p) +} + +// DownloadFile via soap.Download with an http service ticket +func (d Datastore) DownloadFile(ctx context.Context, path string, file string, param *soap.Download) error { + u, p, err := d.downloadTicket(ctx, path, param) + if err != nil { + return err + } + vc := d.Client() + if internal.UsingEnvoySidecar(vc) { + // Override the vim client with a new one that wraps a Unix socket transport. + // Using HTTP here so secure means nothing. + vc = internal.ClientWithEnvoyHostGateway(vc) + } + return vc.DownloadFile(ctx, file, u, p) +} + +// AttachedHosts returns hosts that have this Datastore attached, accessible and writable. +func (d Datastore) AttachedHosts(ctx context.Context) ([]*HostSystem, error) { + var ds mo.Datastore + var hosts []*HostSystem + + pc := property.DefaultCollector(d.Client()) + err := pc.RetrieveOne(ctx, d.Reference(), []string{"host"}, &ds) + if err != nil { + return nil, err + } + + mounts := make(map[types.ManagedObjectReference]types.DatastoreHostMount) + var refs []types.ManagedObjectReference + for _, host := range ds.Host { + refs = append(refs, host.Key) + mounts[host.Key] = host + } + + var hs []mo.HostSystem + err = pc.Retrieve(ctx, refs, []string{"runtime.connectionState", "runtime.powerState"}, &hs) + if err != nil { + return nil, err + } + + for _, host := range hs { + if host.Runtime.ConnectionState == types.HostSystemConnectionStateConnected && + host.Runtime.PowerState == types.HostSystemPowerStatePoweredOn { + + mount := mounts[host.Reference()] + info := mount.MountInfo + + if *info.Mounted && *info.Accessible && info.AccessMode == string(types.HostMountModeReadWrite) { + hosts = append(hosts, NewHostSystem(d.Client(), mount.Key)) + } + } + } + + return hosts, nil +} + +// AttachedClusterHosts returns hosts that have this Datastore attached, accessible and writable and are members of the given cluster. +func (d Datastore) AttachedClusterHosts(ctx context.Context, cluster *ComputeResource) ([]*HostSystem, error) { + var hosts []*HostSystem + + clusterHosts, err := cluster.Hosts(ctx) + if err != nil { + return nil, err + } + + attachedHosts, err := d.AttachedHosts(ctx) + if err != nil { + return nil, err + } + + refs := make(map[types.ManagedObjectReference]bool) + for _, host := range attachedHosts { + refs[host.Reference()] = true + } + + for _, host := range clusterHosts { + if refs[host.Reference()] { + hosts = append(hosts, host) + } + } + + return hosts, nil +} + +func (d Datastore) Stat(ctx context.Context, file string) (types.BaseFileInfo, error) { + b, err := d.Browser(ctx) + if err != nil { + return nil, err + } + + spec := types.HostDatastoreBrowserSearchSpec{ + Details: &types.FileQueryFlags{ + FileType: true, + FileSize: true, + Modification: true, + FileOwner: types.NewBool(true), + }, + MatchPattern: []string{path.Base(file)}, + } + + dsPath := d.Path(path.Dir(file)) + task, err := b.SearchDatastore(ctx, dsPath, &spec) + if err != nil { + return nil, err + } + + info, err := task.WaitForResult(ctx, nil) + if err != nil { + if types.IsFileNotFound(err) { + // FileNotFound means the base path doesn't exist. + return nil, DatastoreNoSuchDirectoryError{"stat", dsPath} + } + + return nil, err + } + + res := info.Result.(types.HostDatastoreBrowserSearchResults) + if len(res.File) == 0 { + // File doesn't exist + return nil, DatastoreNoSuchFileError{"stat", d.Path(file)} + } + + return res.File[0], nil + +} + +// Type returns the type of file system volume. +func (d Datastore) Type(ctx context.Context) (types.HostFileSystemVolumeFileSystemType, error) { + var mds mo.Datastore + + if err := d.Properties(ctx, d.Reference(), []string{"summary.type"}, &mds); err != nil { + return types.HostFileSystemVolumeFileSystemType(""), err + } + return types.HostFileSystemVolumeFileSystemType(mds.Summary.Type), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/datastore_file.go b/vendor/github.com/vmware/govmomi/object/datastore_file.go new file mode 100644 index 0000000000..86d7d9c728 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/datastore_file.go @@ -0,0 +1,412 @@ +/* +Copyright (c) 2016-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 object + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "net/http" + "os" + "path" + "sync" + "time" + + "github.com/vmware/govmomi/vim25/soap" +) + +// DatastoreFile implements io.Reader, io.Seeker and io.Closer interfaces for datastore file access. +type DatastoreFile struct { + d Datastore + ctx context.Context + name string + + buf io.Reader + body io.ReadCloser + length int64 + offset struct { + read, seek int64 + } +} + +// Open opens the named file relative to the Datastore. +func (d Datastore) Open(ctx context.Context, name string) (*DatastoreFile, error) { + return &DatastoreFile{ + d: d, + name: name, + length: -1, + ctx: ctx, + }, nil +} + +// Read reads up to len(b) bytes from the DatastoreFile. +func (f *DatastoreFile) Read(b []byte) (int, error) { + if f.offset.read != f.offset.seek { + // A Seek() call changed the offset, we need to issue a new GET + _ = f.Close() + + f.offset.read = f.offset.seek + } else if f.buf != nil { + // f.buf + f behaves like an io.MultiReader + n, err := f.buf.Read(b) + if err == io.EOF { + f.buf = nil // buffer has been drained + } + if n > 0 { + return n, nil + } + } + + body, err := f.get() + if err != nil { + return 0, err + } + + n, err := body.Read(b) + + f.offset.read += int64(n) + f.offset.seek += int64(n) + + return n, err +} + +// Close closes the DatastoreFile. +func (f *DatastoreFile) Close() error { + var err error + + if f.body != nil { + err = f.body.Close() + f.body = nil + } + + f.buf = nil + + return err +} + +// Seek sets the offset for the next Read on the DatastoreFile. +func (f *DatastoreFile) Seek(offset int64, whence int) (int64, error) { + switch whence { + case io.SeekStart: + case io.SeekCurrent: + offset += f.offset.seek + case io.SeekEnd: + if f.length < 0 { + _, err := f.Stat() + if err != nil { + return 0, err + } + } + offset += f.length + default: + return 0, errors.New("Seek: invalid whence") + } + + // allow negative SeekStart for initial Range request + if offset < 0 { + return 0, errors.New("Seek: invalid offset") + } + + f.offset.seek = offset + + return offset, nil +} + +type fileStat struct { + file *DatastoreFile + header http.Header +} + +func (s *fileStat) Name() string { + return path.Base(s.file.name) +} + +func (s *fileStat) Size() int64 { + return s.file.length +} + +func (s *fileStat) Mode() os.FileMode { + return 0 +} + +func (s *fileStat) ModTime() time.Time { + return time.Now() // no Last-Modified +} + +func (s *fileStat) IsDir() bool { + return false +} + +func (s *fileStat) Sys() interface{} { + return s.header +} + +func statusError(res *http.Response) error { + if res.StatusCode == http.StatusNotFound { + return os.ErrNotExist + } + return errors.New(res.Status) +} + +// Stat returns the os.FileInfo interface describing file. +func (f *DatastoreFile) Stat() (os.FileInfo, error) { + // TODO: consider using Datastore.Stat() instead + u, p, err := f.d.downloadTicket(f.ctx, f.name, &soap.Download{Method: "HEAD"}) + if err != nil { + return nil, err + } + + res, err := f.d.Client().DownloadRequest(f.ctx, u, p) + if err != nil { + return nil, err + } + + if res.StatusCode != http.StatusOK { + return nil, statusError(res) + } + + f.length = res.ContentLength + + return &fileStat{f, res.Header}, nil +} + +func (f *DatastoreFile) get() (io.Reader, error) { + if f.body != nil { + return f.body, nil + } + + u, p, err := f.d.downloadTicket(f.ctx, f.name, nil) + if err != nil { + return nil, err + } + + if f.offset.read != 0 { + p.Headers = map[string]string{ + "Range": fmt.Sprintf("bytes=%d-", f.offset.read), + } + } + + res, err := f.d.Client().DownloadRequest(f.ctx, u, p) + if err != nil { + return nil, err + } + + switch res.StatusCode { + case http.StatusOK: + f.length = res.ContentLength + case http.StatusPartialContent: + var start, end int + cr := res.Header.Get("Content-Range") + _, err = fmt.Sscanf(cr, "bytes %d-%d/%d", &start, &end, &f.length) + if err != nil { + f.length = -1 + } + case http.StatusRequestedRangeNotSatisfiable: + // ok: Read() will return io.EOF + default: + return nil, statusError(res) + } + + if f.length < 0 { + _ = res.Body.Close() + return nil, errors.New("unable to determine file size") + } + + f.body = res.Body + + return f.body, nil +} + +func lastIndexLines(s []byte, line *int, include func(l int, m string) bool) (int64, bool) { + i := len(s) - 1 + done := false + + for i > 0 { + o := bytes.LastIndexByte(s[:i], '\n') + if o < 0 { + break + } + + msg := string(s[o+1 : i+1]) + if !include(*line, msg) { + done = true + break + } else { + i = o + *line++ + } + } + + return int64(i), done +} + +// Tail seeks to the position of the last N lines of the file. +func (f *DatastoreFile) Tail(n int) error { + return f.TailFunc(n, func(line int, _ string) bool { return n > line }) +} + +// TailFunc will seek backwards in the datastore file until it hits a line that does +// not satisfy the supplied `include` function. +func (f *DatastoreFile) TailFunc(lines int, include func(line int, message string) bool) error { + // Read the file in reverse using bsize chunks + const bsize = int64(1024 * 16) + + fsize, err := f.Seek(0, io.SeekEnd) + if err != nil { + return err + } + + if lines == 0 { + return nil + } + + chunk := int64(-1) + + buf := bytes.NewBuffer(make([]byte, 0, bsize)) + line := 0 + + for { + var eof bool + var pos int64 + + nread := bsize + + offset := chunk * bsize + remain := fsize + offset + + if remain < 0 { + if pos, err = f.Seek(0, io.SeekStart); err != nil { + return err + } + + nread = bsize + remain + eof = true + } else if pos, err = f.Seek(offset, io.SeekEnd); err != nil { + return err + } + + if _, err = io.CopyN(buf, f, nread); err != nil { + if err != io.EOF { + return err + } + } + + b := buf.Bytes() + idx, done := lastIndexLines(b, &line, include) + + if done { + if chunk == -1 { + // We found all N lines in the last chunk of the file. + // The seek offset is also now at the current end of file. + // Save this buffer to avoid another GET request when Read() is called. + buf.Next(int(idx + 1)) + f.buf = buf + return nil + } + + if _, err = f.Seek(pos+idx+1, io.SeekStart); err != nil { + return err + } + + break + } + + if eof { + if remain < 0 { + // We found < N lines in the entire file, so seek to the start. + _, _ = f.Seek(0, io.SeekStart) + } + break + } + + chunk-- + buf.Reset() + } + + return nil +} + +type followDatastoreFile struct { + r *DatastoreFile + c chan struct{} + i time.Duration + o sync.Once +} + +// Read reads up to len(b) bytes from the DatastoreFile being followed. +// This method will block until data is read, an error other than io.EOF is returned or Close() is called. +func (f *followDatastoreFile) Read(p []byte) (int, error) { + offset := f.r.offset.seek + stop := false + + for { + n, err := f.r.Read(p) + if err != nil && err == io.EOF { + _ = f.r.Close() // GET request body has been drained. + if stop { + return n, err + } + err = nil + } + + if n > 0 { + return n, err + } + + select { + case <-f.c: + // Wake up and stop polling once the body has been drained + stop = true + case <-time.After(f.i): + } + + info, serr := f.r.Stat() + if serr != nil { + // Return EOF rather than 404 if the file goes away + if serr == os.ErrNotExist { + _ = f.r.Close() + return 0, io.EOF + } + return 0, serr + } + + if info.Size() < offset { + // assume file has be truncated + offset, err = f.r.Seek(0, io.SeekStart) + if err != nil { + return 0, err + } + } + } +} + +// Close will stop Follow polling and close the underlying DatastoreFile. +func (f *followDatastoreFile) Close() error { + f.o.Do(func() { close(f.c) }) + return nil +} + +// Follow returns an io.ReadCloser to stream the file contents as data is appended. +func (f *DatastoreFile) Follow(interval time.Duration) io.ReadCloser { + return &followDatastoreFile{ + r: f, + c: make(chan struct{}), + i: interval, + } +} diff --git a/vendor/github.com/vmware/govmomi/object/datastore_file_manager.go b/vendor/github.com/vmware/govmomi/object/datastore_file_manager.go new file mode 100644 index 0000000000..a6e29c2c56 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/datastore_file_manager.go @@ -0,0 +1,228 @@ +/* +Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package object + +import ( + "bufio" + "bytes" + "context" + "fmt" + "io" + "log" + "path" + "strings" + + "github.com/vmware/govmomi/vim25/progress" + "github.com/vmware/govmomi/vim25/soap" +) + +// DatastoreFileManager combines FileManager and VirtualDiskManager to manage files on a Datastore +type DatastoreFileManager struct { + Datacenter *Datacenter + Datastore *Datastore + FileManager *FileManager + VirtualDiskManager *VirtualDiskManager + + Force bool + DatacenterTarget *Datacenter +} + +// NewFileManager creates a new instance of DatastoreFileManager +func (d Datastore) NewFileManager(dc *Datacenter, force bool) *DatastoreFileManager { + c := d.Client() + + m := &DatastoreFileManager{ + Datacenter: dc, + Datastore: &d, + FileManager: NewFileManager(c), + VirtualDiskManager: NewVirtualDiskManager(c), + Force: force, + DatacenterTarget: dc, + } + + return m +} + +func (m *DatastoreFileManager) WithProgress(ctx context.Context, s progress.Sinker) context.Context { + return context.WithValue(ctx, m, s) +} + +func (m *DatastoreFileManager) wait(ctx context.Context, task *Task) error { + var logger progress.Sinker + if s, ok := ctx.Value(m).(progress.Sinker); ok { + logger = s + } + _, err := task.WaitForResult(ctx, logger) + return err +} + +// Delete dispatches to the appropriate Delete method based on file name extension +func (m *DatastoreFileManager) Delete(ctx context.Context, name string) error { + switch path.Ext(name) { + case ".vmdk": + return m.DeleteVirtualDisk(ctx, name) + default: + return m.DeleteFile(ctx, name) + } +} + +// DeleteFile calls FileManager.DeleteDatastoreFile +func (m *DatastoreFileManager) DeleteFile(ctx context.Context, name string) error { + p := m.Path(name) + + task, err := m.FileManager.DeleteDatastoreFile(ctx, p.String(), m.Datacenter) + if err != nil { + return err + } + + return m.wait(ctx, task) +} + +// DeleteVirtualDisk calls VirtualDiskManager.DeleteVirtualDisk +// Regardless of the Datastore type, DeleteVirtualDisk will fail if 'ddb.deletable=false', +// so if Force=true this method attempts to set 'ddb.deletable=true' before starting the delete task. +func (m *DatastoreFileManager) DeleteVirtualDisk(ctx context.Context, name string) error { + p := m.Path(name) + + var merr error + + if m.Force { + merr = m.markDiskAsDeletable(ctx, p) + } + + task, err := m.VirtualDiskManager.DeleteVirtualDisk(ctx, p.String(), m.Datacenter) + if err != nil { + log.Printf("markDiskAsDeletable(%s): %s", p, merr) + return err + } + + return m.wait(ctx, task) +} + +// CopyFile calls FileManager.CopyDatastoreFile +func (m *DatastoreFileManager) CopyFile(ctx context.Context, src string, dst string) error { + srcp := m.Path(src) + dstp := m.Path(dst) + + task, err := m.FileManager.CopyDatastoreFile(ctx, srcp.String(), m.Datacenter, dstp.String(), m.DatacenterTarget, m.Force) + if err != nil { + return err + } + + return m.wait(ctx, task) +} + +// Copy dispatches to the appropriate FileManager or VirtualDiskManager Copy method based on file name extension +func (m *DatastoreFileManager) Copy(ctx context.Context, src string, dst string) error { + srcp := m.Path(src) + dstp := m.Path(dst) + + f := m.FileManager.CopyDatastoreFile + + if srcp.IsVMDK() { + // types.VirtualDiskSpec=nil as it is not implemented by vCenter + f = func(ctx context.Context, src string, srcDC *Datacenter, dst string, dstDC *Datacenter, force bool) (*Task, error) { + return m.VirtualDiskManager.CopyVirtualDisk(ctx, src, srcDC, dst, dstDC, nil, force) + } + } + + task, err := f(ctx, srcp.String(), m.Datacenter, dstp.String(), m.DatacenterTarget, m.Force) + if err != nil { + return err + } + + return m.wait(ctx, task) +} + +// MoveFile calls FileManager.MoveDatastoreFile +func (m *DatastoreFileManager) MoveFile(ctx context.Context, src string, dst string) error { + srcp := m.Path(src) + dstp := m.Path(dst) + + task, err := m.FileManager.MoveDatastoreFile(ctx, srcp.String(), m.Datacenter, dstp.String(), m.DatacenterTarget, m.Force) + if err != nil { + return err + } + + return m.wait(ctx, task) +} + +// Move dispatches to the appropriate FileManager or VirtualDiskManager Move method based on file name extension +func (m *DatastoreFileManager) Move(ctx context.Context, src string, dst string) error { + srcp := m.Path(src) + dstp := m.Path(dst) + + f := m.FileManager.MoveDatastoreFile + + if srcp.IsVMDK() { + f = m.VirtualDiskManager.MoveVirtualDisk + } + + task, err := f(ctx, srcp.String(), m.Datacenter, dstp.String(), m.DatacenterTarget, m.Force) + if err != nil { + return err + } + + return m.wait(ctx, task) +} + +// Path converts path name to a DatastorePath +func (m *DatastoreFileManager) Path(name string) *DatastorePath { + var p DatastorePath + + if !p.FromString(name) { + p.Path = name + p.Datastore = m.Datastore.Name() + } + + return &p +} + +func (m *DatastoreFileManager) markDiskAsDeletable(ctx context.Context, path *DatastorePath) error { + r, _, err := m.Datastore.Download(ctx, path.Path, &soap.DefaultDownload) + if err != nil { + return err + } + + defer r.Close() + + hasFlag := false + buf := new(bytes.Buffer) + + s := bufio.NewScanner(&io.LimitedReader{R: r, N: 2048}) // should be only a few hundred bytes, limit to be sure + + for s.Scan() { + line := s.Text() + if strings.HasPrefix(line, "ddb.deletable") { + hasFlag = true + continue + } + + fmt.Fprintln(buf, line) + } + + if err := s.Err(); err != nil { + return err // any error other than EOF + } + + if !hasFlag { + return nil // already deletable, so leave as-is + } + + // rewrite the .vmdk with ddb.deletable flag removed (the default is true) + return m.Datastore.Upload(ctx, buf, path.Path, &soap.DefaultUpload) +} diff --git a/vendor/github.com/vmware/govmomi/object/datastore_path.go b/vendor/github.com/vmware/govmomi/object/datastore_path.go new file mode 100644 index 0000000000..104c7dfe35 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/datastore_path.go @@ -0,0 +1,71 @@ +/* +Copyright (c) 2016 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 object + +import ( + "fmt" + "path" + "strings" +) + +// DatastorePath contains the components of a datastore path. +type DatastorePath struct { + Datastore string + Path string +} + +// FromString parses a datastore path. +// Returns true if the path could be parsed, false otherwise. +func (p *DatastorePath) FromString(s string) bool { + if s == "" { + return false + } + + s = strings.TrimSpace(s) + + if !strings.HasPrefix(s, "[") { + return false + } + + s = s[1:] + + ix := strings.Index(s, "]") + if ix < 0 { + return false + } + + p.Datastore = s[:ix] + p.Path = strings.TrimSpace(s[ix+1:]) + + return true +} + +// String formats a datastore path. +func (p *DatastorePath) String() string { + s := fmt.Sprintf("[%s]", p.Datastore) + + if p.Path == "" { + return s + } + + return strings.Join([]string{s, p.Path}, " ") +} + +// IsVMDK returns true if Path has a ".vmdk" extension +func (p *DatastorePath) IsVMDK() bool { + return path.Ext(p.Path) == ".vmdk" +} diff --git a/vendor/github.com/vmware/govmomi/object/diagnostic_log.go b/vendor/github.com/vmware/govmomi/object/diagnostic_log.go new file mode 100644 index 0000000000..466d0ee915 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/diagnostic_log.go @@ -0,0 +1,76 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "fmt" + "io" + "math" +) + +// DiagnosticLog wraps DiagnosticManager.BrowseLog +type DiagnosticLog struct { + m DiagnosticManager + + Key string + Host *HostSystem + + Start int32 +} + +// Seek to log position starting at the last nlines of the log +func (l *DiagnosticLog) Seek(ctx context.Context, nlines int32) error { + h, err := l.m.BrowseLog(ctx, l.Host, l.Key, math.MaxInt32, 0) + if err != nil { + return err + } + + l.Start = h.LineEnd - nlines + + return nil +} + +// Copy log starting from l.Start to the given io.Writer +// Returns on error or when end of log is reached. +func (l *DiagnosticLog) Copy(ctx context.Context, w io.Writer) (int, error) { + const max = 500 // VC max == 500, ESX max == 1000 + written := 0 + + for { + h, err := l.m.BrowseLog(ctx, l.Host, l.Key, l.Start, max) + if err != nil { + return 0, err + } + + for _, line := range h.LineText { + n, err := fmt.Fprintln(w, line) + written += n + if err != nil { + return written, err + } + } + + l.Start += int32(len(h.LineText)) + + if l.Start >= h.LineEnd { + break + } + } + + return written, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/diagnostic_manager.go b/vendor/github.com/vmware/govmomi/object/diagnostic_manager.go new file mode 100644 index 0000000000..026dc1cb5e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/diagnostic_manager.go @@ -0,0 +1,102 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type DiagnosticManager struct { + Common +} + +func NewDiagnosticManager(c *vim25.Client) *DiagnosticManager { + m := DiagnosticManager{ + Common: NewCommon(c, *c.ServiceContent.DiagnosticManager), + } + + return &m +} + +func (m DiagnosticManager) Log(ctx context.Context, host *HostSystem, key string) *DiagnosticLog { + return &DiagnosticLog{ + m: m, + Key: key, + Host: host, + } +} + +func (m DiagnosticManager) BrowseLog(ctx context.Context, host *HostSystem, key string, start, lines int32) (*types.DiagnosticManagerLogHeader, error) { + req := types.BrowseDiagnosticLog{ + This: m.Reference(), + Key: key, + Start: start, + Lines: lines, + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.BrowseDiagnosticLog(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +func (m DiagnosticManager) GenerateLogBundles(ctx context.Context, includeDefault bool, host []*HostSystem) (*Task, error) { + req := types.GenerateLogBundles_Task{ + This: m.Reference(), + IncludeDefault: includeDefault, + } + + for _, h := range host { + req.Host = append(req.Host, h.Reference()) + } + + res, err := methods.GenerateLogBundles_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return NewTask(m.c, res.Returnval), nil +} + +func (m DiagnosticManager) QueryDescriptions(ctx context.Context, host *HostSystem) ([]types.DiagnosticManagerLogDescriptor, error) { + req := types.QueryDescriptions{ + This: m.Reference(), + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.QueryDescriptions(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go b/vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go new file mode 100644 index 0000000000..c2abb8fabd --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go @@ -0,0 +1,90 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type DistributedVirtualPortgroup struct { + Common +} + +func NewDistributedVirtualPortgroup(c *vim25.Client, ref types.ManagedObjectReference) *DistributedVirtualPortgroup { + return &DistributedVirtualPortgroup{ + Common: NewCommon(c, ref), + } +} + +func (p DistributedVirtualPortgroup) GetInventoryPath() string { + return p.InventoryPath +} + +// EthernetCardBackingInfo returns the VirtualDeviceBackingInfo for this DistributedVirtualPortgroup +func (p DistributedVirtualPortgroup) EthernetCardBackingInfo(ctx context.Context) (types.BaseVirtualDeviceBackingInfo, error) { + var dvp mo.DistributedVirtualPortgroup + var dvs mo.DistributedVirtualSwitch + prop := "config.distributedVirtualSwitch" + + if err := p.Properties(ctx, p.Reference(), []string{"key", prop}, &dvp); err != nil { + return nil, err + } + + // From the docs at https://code.vmware.com/apis/196/vsphere/doc/vim.dvs.DistributedVirtualPortgroup.ConfigInfo.html: + // "This property should always be set unless the user's setting does not have System.Read privilege on the object referred to by this property." + // Note that "the object" refers to the Switch, not the PortGroup. + if dvp.Config.DistributedVirtualSwitch == nil { + name := p.InventoryPath + if name == "" { + name = p.Reference().String() + } + return nil, fmt.Errorf("failed to create EthernetCardBackingInfo for %s: System.Read privilege required for %s", name, prop) + } + + if err := p.Properties(ctx, *dvp.Config.DistributedVirtualSwitch, []string{"uuid"}, &dvs); err != nil { + return nil, err + } + + backing := &types.VirtualEthernetCardDistributedVirtualPortBackingInfo{ + Port: types.DistributedVirtualSwitchPortConnection{ + PortgroupKey: dvp.Key, + SwitchUuid: dvs.Uuid, + }, + } + + return backing, nil +} + +func (p DistributedVirtualPortgroup) Reconfigure(ctx context.Context, spec types.DVPortgroupConfigSpec) (*Task, error) { + req := types.ReconfigureDVPortgroup_Task{ + This: p.Reference(), + Spec: spec, + } + + res, err := methods.ReconfigureDVPortgroup_Task(ctx, p.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(p.Client(), res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go b/vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go new file mode 100644 index 0000000000..66650e1d06 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go @@ -0,0 +1,118 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type DistributedVirtualSwitch struct { + Common +} + +func NewDistributedVirtualSwitch(c *vim25.Client, ref types.ManagedObjectReference) *DistributedVirtualSwitch { + return &DistributedVirtualSwitch{ + Common: NewCommon(c, ref), + } +} + +func (s DistributedVirtualSwitch) GetInventoryPath() string { + return s.InventoryPath +} + +func (s DistributedVirtualSwitch) EthernetCardBackingInfo(ctx context.Context) (types.BaseVirtualDeviceBackingInfo, error) { + ref := s.Reference() + name := s.InventoryPath + if name == "" { + name = ref.String() + } + return nil, fmt.Errorf("type %s (%s) cannot be used for EthernetCardBackingInfo", ref.Type, name) +} + +func (s DistributedVirtualSwitch) Reconfigure(ctx context.Context, spec types.BaseDVSConfigSpec) (*Task, error) { + req := types.ReconfigureDvs_Task{ + This: s.Reference(), + Spec: spec, + } + + res, err := methods.ReconfigureDvs_Task(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(s.Client(), res.Returnval), nil +} + +func (s DistributedVirtualSwitch) AddPortgroup(ctx context.Context, spec []types.DVPortgroupConfigSpec) (*Task, error) { + req := types.AddDVPortgroup_Task{ + This: s.Reference(), + Spec: spec, + } + + res, err := methods.AddDVPortgroup_Task(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(s.Client(), res.Returnval), nil +} + +func (s DistributedVirtualSwitch) FetchDVPorts(ctx context.Context, criteria *types.DistributedVirtualSwitchPortCriteria) ([]types.DistributedVirtualPort, error) { + req := &types.FetchDVPorts{ + This: s.Reference(), + Criteria: criteria, + } + + res, err := methods.FetchDVPorts(ctx, s.Client(), req) + if err != nil { + return nil, err + } + return res.Returnval, nil +} + +func (s DistributedVirtualSwitch) ReconfigureDVPort(ctx context.Context, spec []types.DVPortConfigSpec) (*Task, error) { + req := types.ReconfigureDVPort_Task{ + This: s.Reference(), + Port: spec, + } + + res, err := methods.ReconfigureDVPort_Task(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(s.Client(), res.Returnval), nil +} + +func (s DistributedVirtualSwitch) ReconfigureLACP(ctx context.Context, spec []types.VMwareDvsLacpGroupSpec) (*Task, error) { + req := types.UpdateDVSLacpGroupConfig_Task{ + This: s.Reference(), + LacpGroupSpec: spec, + } + + res, err := methods.UpdateDVSLacpGroupConfig_Task(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(s.Client(), res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/environment_browser.go b/vendor/github.com/vmware/govmomi/object/environment_browser.go new file mode 100644 index 0000000000..54ab4cb8d5 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/environment_browser.go @@ -0,0 +1,98 @@ +/* +Copyright (c) 2023-2023 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type EnvironmentBrowser struct { + Common +} + +func NewEnvironmentBrowser(c *vim25.Client, ref types.ManagedObjectReference) *EnvironmentBrowser { + return &EnvironmentBrowser{ + Common: NewCommon(c, ref), + } +} + +func (b EnvironmentBrowser) QueryConfigTarget(ctx context.Context, host *HostSystem) (*types.ConfigTarget, error) { + req := types.QueryConfigTarget{ + This: b.Reference(), + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.QueryConfigTarget(ctx, b.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (b EnvironmentBrowser) QueryTargetCapabilities(ctx context.Context, host *HostSystem) (*types.HostCapability, error) { + req := types.QueryTargetCapabilities{ + This: b.Reference(), + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.QueryTargetCapabilities(ctx, b.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (b EnvironmentBrowser) QueryConfigOption(ctx context.Context, spec *types.EnvironmentBrowserConfigOptionQuerySpec) (*types.VirtualMachineConfigOption, error) { + req := types.QueryConfigOptionEx{ + This: b.Reference(), + Spec: spec, + } + + res, err := methods.QueryConfigOptionEx(ctx, b.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (b EnvironmentBrowser) QueryConfigOptionDescriptor(ctx context.Context) ([]types.VirtualMachineConfigOptionDescriptor, error) { + req := types.QueryConfigOptionDescriptor{ + This: b.Reference(), + } + + res, err := methods.QueryConfigOptionDescriptor(ctx, b.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/extension_manager.go b/vendor/github.com/vmware/govmomi/object/extension_manager.go new file mode 100644 index 0000000000..94ade017c2 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/extension_manager.go @@ -0,0 +1,113 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type ExtensionManager struct { + Common +} + +// GetExtensionManager wraps NewExtensionManager, returning ErrNotSupported +// when the client is not connected to a vCenter instance. +func GetExtensionManager(c *vim25.Client) (*ExtensionManager, error) { + if c.ServiceContent.ExtensionManager == nil { + return nil, ErrNotSupported + } + return NewExtensionManager(c), nil +} + +func NewExtensionManager(c *vim25.Client) *ExtensionManager { + o := ExtensionManager{ + Common: NewCommon(c, *c.ServiceContent.ExtensionManager), + } + + return &o +} + +func (m ExtensionManager) List(ctx context.Context) ([]types.Extension, error) { + var em mo.ExtensionManager + + err := m.Properties(ctx, m.Reference(), []string{"extensionList"}, &em) + if err != nil { + return nil, err + } + + return em.ExtensionList, nil +} + +func (m ExtensionManager) Find(ctx context.Context, key string) (*types.Extension, error) { + req := types.FindExtension{ + This: m.Reference(), + ExtensionKey: key, + } + + res, err := methods.FindExtension(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m ExtensionManager) Register(ctx context.Context, extension types.Extension) error { + req := types.RegisterExtension{ + This: m.Reference(), + Extension: extension, + } + + _, err := methods.RegisterExtension(ctx, m.c, &req) + return err +} + +func (m ExtensionManager) SetCertificate(ctx context.Context, key string, certificatePem string) error { + req := types.SetExtensionCertificate{ + This: m.Reference(), + ExtensionKey: key, + CertificatePem: certificatePem, + } + + _, err := methods.SetExtensionCertificate(ctx, m.c, &req) + return err +} + +func (m ExtensionManager) Unregister(ctx context.Context, key string) error { + req := types.UnregisterExtension{ + This: m.Reference(), + ExtensionKey: key, + } + + _, err := methods.UnregisterExtension(ctx, m.c, &req) + return err +} + +func (m ExtensionManager) Update(ctx context.Context, extension types.Extension) error { + req := types.UpdateExtension{ + This: m.Reference(), + Extension: extension, + } + + _, err := methods.UpdateExtension(ctx, m.c, &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/file_manager.go b/vendor/github.com/vmware/govmomi/object/file_manager.go new file mode 100644 index 0000000000..8e8f5d3b0c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/file_manager.go @@ -0,0 +1,126 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type FileManager struct { + Common +} + +func NewFileManager(c *vim25.Client) *FileManager { + f := FileManager{ + Common: NewCommon(c, *c.ServiceContent.FileManager), + } + + return &f +} + +func (f FileManager) CopyDatastoreFile(ctx context.Context, sourceName string, sourceDatacenter *Datacenter, destinationName string, destinationDatacenter *Datacenter, force bool) (*Task, error) { + req := types.CopyDatastoreFile_Task{ + This: f.Reference(), + SourceName: sourceName, + DestinationName: destinationName, + Force: types.NewBool(force), + } + + if sourceDatacenter != nil { + ref := sourceDatacenter.Reference() + req.SourceDatacenter = &ref + } + + if destinationDatacenter != nil { + ref := destinationDatacenter.Reference() + req.DestinationDatacenter = &ref + } + + res, err := methods.CopyDatastoreFile_Task(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewTask(f.c, res.Returnval), nil +} + +// DeleteDatastoreFile deletes the specified file or folder from the datastore. +func (f FileManager) DeleteDatastoreFile(ctx context.Context, name string, dc *Datacenter) (*Task, error) { + req := types.DeleteDatastoreFile_Task{ + This: f.Reference(), + Name: name, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.DeleteDatastoreFile_Task(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewTask(f.c, res.Returnval), nil +} + +// MakeDirectory creates a folder using the specified name. +func (f FileManager) MakeDirectory(ctx context.Context, name string, dc *Datacenter, createParentDirectories bool) error { + req := types.MakeDirectory{ + This: f.Reference(), + Name: name, + CreateParentDirectories: types.NewBool(createParentDirectories), + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + _, err := methods.MakeDirectory(ctx, f.c, &req) + return err +} + +func (f FileManager) MoveDatastoreFile(ctx context.Context, sourceName string, sourceDatacenter *Datacenter, destinationName string, destinationDatacenter *Datacenter, force bool) (*Task, error) { + req := types.MoveDatastoreFile_Task{ + This: f.Reference(), + SourceName: sourceName, + DestinationName: destinationName, + Force: types.NewBool(force), + } + + if sourceDatacenter != nil { + ref := sourceDatacenter.Reference() + req.SourceDatacenter = &ref + } + + if destinationDatacenter != nil { + ref := destinationDatacenter.Reference() + req.DestinationDatacenter = &ref + } + + res, err := methods.MoveDatastoreFile_Task(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewTask(f.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/folder.go b/vendor/github.com/vmware/govmomi/object/folder.go new file mode 100644 index 0000000000..6e0a7649b9 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/folder.go @@ -0,0 +1,241 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type Folder struct { + Common +} + +func NewFolder(c *vim25.Client, ref types.ManagedObjectReference) *Folder { + return &Folder{ + Common: NewCommon(c, ref), + } +} + +func NewRootFolder(c *vim25.Client) *Folder { + f := NewFolder(c, c.ServiceContent.RootFolder) + f.InventoryPath = "/" + return f +} + +func (f Folder) Children(ctx context.Context) ([]Reference, error) { + var mf mo.Folder + + err := f.Properties(ctx, f.Reference(), []string{"childEntity"}, &mf) + if err != nil { + return nil, err + } + + var rs []Reference + for _, e := range mf.ChildEntity { + if r := NewReference(f.c, e); r != nil { + rs = append(rs, r) + } + } + + return rs, nil +} + +func (f Folder) CreateDatacenter(ctx context.Context, datacenter string) (*Datacenter, error) { + req := types.CreateDatacenter{ + This: f.Reference(), + Name: datacenter, + } + + res, err := methods.CreateDatacenter(ctx, f.c, &req) + if err != nil { + return nil, err + } + + // Response will be nil if this is an ESX host that does not belong to a vCenter + if res == nil { + return nil, nil + } + + return NewDatacenter(f.c, res.Returnval), nil +} + +func (f Folder) CreateCluster(ctx context.Context, cluster string, spec types.ClusterConfigSpecEx) (*ClusterComputeResource, error) { + req := types.CreateClusterEx{ + This: f.Reference(), + Name: cluster, + Spec: spec, + } + + res, err := methods.CreateClusterEx(ctx, f.c, &req) + if err != nil { + return nil, err + } + + // Response will be nil if this is an ESX host that does not belong to a vCenter + if res == nil { + return nil, nil + } + + return NewClusterComputeResource(f.c, res.Returnval), nil +} + +func (f Folder) CreateFolder(ctx context.Context, name string) (*Folder, error) { + req := types.CreateFolder{ + This: f.Reference(), + Name: name, + } + + res, err := methods.CreateFolder(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewFolder(f.c, res.Returnval), err +} + +func (f Folder) CreateStoragePod(ctx context.Context, name string) (*StoragePod, error) { + req := types.CreateStoragePod{ + This: f.Reference(), + Name: name, + } + + res, err := methods.CreateStoragePod(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewStoragePod(f.c, res.Returnval), err +} + +func (f Folder) AddStandaloneHost(ctx context.Context, spec types.HostConnectSpec, addConnected bool, license *string, compResSpec *types.BaseComputeResourceConfigSpec) (*Task, error) { + req := types.AddStandaloneHost_Task{ + This: f.Reference(), + Spec: spec, + AddConnected: addConnected, + } + + if license != nil { + req.License = *license + } + + if compResSpec != nil { + req.CompResSpec = *compResSpec + } + + res, err := methods.AddStandaloneHost_Task(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewTask(f.c, res.Returnval), nil +} + +func (f Folder) CreateVM(ctx context.Context, config types.VirtualMachineConfigSpec, pool *ResourcePool, host *HostSystem) (*Task, error) { + req := types.CreateVM_Task{ + This: f.Reference(), + Config: config, + Pool: pool.Reference(), + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.CreateVM_Task(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewTask(f.c, res.Returnval), nil +} + +func (f Folder) RegisterVM(ctx context.Context, path string, name string, asTemplate bool, pool *ResourcePool, host *HostSystem) (*Task, error) { + req := types.RegisterVM_Task{ + This: f.Reference(), + Path: path, + AsTemplate: asTemplate, + } + + if name != "" { + req.Name = name + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + if pool != nil { + ref := pool.Reference() + req.Pool = &ref + } + + res, err := methods.RegisterVM_Task(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewTask(f.c, res.Returnval), nil +} + +func (f Folder) CreateDVS(ctx context.Context, spec types.DVSCreateSpec) (*Task, error) { + req := types.CreateDVS_Task{ + This: f.Reference(), + Spec: spec, + } + + res, err := methods.CreateDVS_Task(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewTask(f.c, res.Returnval), nil +} + +func (f Folder) MoveInto(ctx context.Context, list []types.ManagedObjectReference) (*Task, error) { + req := types.MoveIntoFolder_Task{ + This: f.Reference(), + List: list, + } + + res, err := methods.MoveIntoFolder_Task(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return NewTask(f.c, res.Returnval), nil +} + +func (f Folder) PlaceVmsXCluster(ctx context.Context, spec types.PlaceVmsXClusterSpec) (*types.PlaceVmsXClusterResult, error) { + req := types.PlaceVmsXCluster{ + This: f.Reference(), + PlacementSpec: spec, + } + + res, err := methods.PlaceVmsXCluster(ctx, f.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_account_manager.go b/vendor/github.com/vmware/govmomi/object/host_account_manager.go new file mode 100644 index 0000000000..640aff8603 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_account_manager.go @@ -0,0 +1,65 @@ +/* +Copyright (c) 2016 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostAccountManager struct { + Common +} + +func NewHostAccountManager(c *vim25.Client, ref types.ManagedObjectReference) *HostAccountManager { + return &HostAccountManager{ + Common: NewCommon(c, ref), + } +} + +func (m HostAccountManager) Create(ctx context.Context, user *types.HostAccountSpec) error { + req := types.CreateUser{ + This: m.Reference(), + User: user, + } + + _, err := methods.CreateUser(ctx, m.Client(), &req) + return err +} + +func (m HostAccountManager) Update(ctx context.Context, user *types.HostAccountSpec) error { + req := types.UpdateUser{ + This: m.Reference(), + User: user, + } + + _, err := methods.UpdateUser(ctx, m.Client(), &req) + return err +} + +func (m HostAccountManager) Remove(ctx context.Context, userName string) error { + req := types.RemoveUser{ + This: m.Reference(), + UserName: userName, + } + + _, err := methods.RemoveUser(ctx, m.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/host_certificate_info.go b/vendor/github.com/vmware/govmomi/object/host_certificate_info.go new file mode 100644 index 0000000000..0d56e7e7be --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_certificate_info.go @@ -0,0 +1,253 @@ +/* +Copyright (c) 2016-2024 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 object + +import ( + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/pem" + "errors" + "fmt" + "io" + "net/url" + "strings" + "text/tabwriter" + + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// HostCertificateInfo provides helpers for types.HostCertificateManagerCertificateInfo +type HostCertificateInfo struct { + types.HostCertificateManagerCertificateInfo + + ThumbprintSHA1 string `json:"thumbprintSHA1"` + ThumbprintSHA256 string `json:"thumbprintSHA256"` + + Err error `json:"err"` + Certificate *x509.Certificate `json:"-"` + + subjectName *pkix.Name + issuerName *pkix.Name +} + +// FromCertificate converts x509.Certificate to HostCertificateInfo +func (info *HostCertificateInfo) FromCertificate(cert *x509.Certificate) *HostCertificateInfo { + info.Certificate = cert + info.subjectName = &cert.Subject + info.issuerName = &cert.Issuer + + info.Issuer = info.fromName(info.issuerName) + info.NotBefore = &cert.NotBefore + info.NotAfter = &cert.NotAfter + info.Subject = info.fromName(info.subjectName) + + info.ThumbprintSHA1 = soap.ThumbprintSHA1(cert) + info.ThumbprintSHA256 = soap.ThumbprintSHA256(cert) + + if info.Status == "" { + info.Status = string(types.HostCertificateManagerCertificateInfoCertificateStatusUnknown) + } + + return info +} + +func (info *HostCertificateInfo) FromPEM(cert []byte) (*HostCertificateInfo, error) { + block, _ := pem.Decode(cert) + if block == nil { + return nil, errors.New("failed to pem.Decode cert") + } + x, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + return info.FromCertificate(x), nil +} + +// FromURL connects to the given URL.Host via tls.Dial with the given tls.Config and populates the HostCertificateInfo +// via tls.ConnectionState. If the certificate was verified with the given tls.Config, the Err field will be nil. +// Otherwise, Err will be set to the x509.UnknownAuthorityError or x509.HostnameError. +// If tls.Dial returns an error of any other type, that error is returned. +func (info *HostCertificateInfo) FromURL(u *url.URL, config *tls.Config) error { + addr := u.Host + if !(strings.LastIndex(addr, ":") > strings.LastIndex(addr, "]")) { + addr += ":443" + } + + conn, err := tls.Dial("tcp", addr, config) + if err != nil { + if !soap.IsCertificateUntrusted(err) { + return err + } + + info.Err = err + + conn, err = tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true}) + if err != nil { + return err + } + } else { + info.Status = string(types.HostCertificateManagerCertificateInfoCertificateStatusGood) + } + + state := conn.ConnectionState() + _ = conn.Close() + info.FromCertificate(state.PeerCertificates[0]) + + return nil +} + +var emailAddressOID = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1} + +func (info *HostCertificateInfo) fromName(name *pkix.Name) string { + var attrs []string + + oids := map[string]string{ + emailAddressOID.String(): "emailAddress", + } + + for _, attr := range name.Names { + if key, ok := oids[attr.Type.String()]; ok { + attrs = append(attrs, fmt.Sprintf("%s=%s", key, attr.Value)) + } + } + + attrs = append(attrs, fmt.Sprintf("CN=%s", name.CommonName)) + + add := func(key string, vals []string) { + for _, val := range vals { + attrs = append(attrs, fmt.Sprintf("%s=%s", key, val)) + } + } + + elts := []struct { + key string + val []string + }{ + {"OU", name.OrganizationalUnit}, + {"O", name.Organization}, + {"L", name.Locality}, + {"ST", name.Province}, + {"C", name.Country}, + } + + for _, elt := range elts { + add(elt.key, elt.val) + } + + return strings.Join(attrs, ",") +} + +func (info *HostCertificateInfo) toName(s string) *pkix.Name { + var name pkix.Name + + for _, pair := range strings.Split(s, ",") { + attr := strings.SplitN(pair, "=", 2) + if len(attr) != 2 { + continue + } + + v := attr[1] + + switch strings.ToLower(attr[0]) { + case "cn": + name.CommonName = v + case "ou": + name.OrganizationalUnit = append(name.OrganizationalUnit, v) + case "o": + name.Organization = append(name.Organization, v) + case "l": + name.Locality = append(name.Locality, v) + case "st": + name.Province = append(name.Province, v) + case "c": + name.Country = append(name.Country, v) + case "emailaddress": + name.Names = append(name.Names, pkix.AttributeTypeAndValue{Type: emailAddressOID, Value: v}) + } + } + + return &name +} + +// SubjectName parses Subject into a pkix.Name +func (info *HostCertificateInfo) SubjectName() *pkix.Name { + if info.subjectName != nil { + return info.subjectName + } + + return info.toName(info.Subject) +} + +// IssuerName parses Issuer into a pkix.Name +func (info *HostCertificateInfo) IssuerName() *pkix.Name { + if info.issuerName != nil { + return info.issuerName + } + + return info.toName(info.Issuer) +} + +// Write outputs info similar to the Chrome Certificate Viewer. +func (info *HostCertificateInfo) Write(w io.Writer) error { + tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0) + + s := func(val string) string { + if val != "" { + return val + } + return "" + } + + ss := func(val []string) string { + return s(strings.Join(val, ",")) + } + + name := func(n *pkix.Name) { + fmt.Fprintf(tw, " Common Name (CN):\t%s\n", s(n.CommonName)) + fmt.Fprintf(tw, " Organization (O):\t%s\n", ss(n.Organization)) + fmt.Fprintf(tw, " Organizational Unit (OU):\t%s\n", ss(n.OrganizationalUnit)) + } + + status := info.Status + if info.Err != nil { + status = fmt.Sprintf("ERROR %s", info.Err) + } + fmt.Fprintf(tw, "Certificate Status:\t%s\n", status) + + fmt.Fprintln(tw, "Issued To:\t") + name(info.SubjectName()) + + fmt.Fprintln(tw, "Issued By:\t") + name(info.IssuerName()) + + fmt.Fprintln(tw, "Validity Period:\t") + fmt.Fprintf(tw, " Issued On:\t%s\n", info.NotBefore) + fmt.Fprintf(tw, " Expires On:\t%s\n", info.NotAfter) + + if info.ThumbprintSHA1 != "" { + fmt.Fprintln(tw, "Thumbprints:\t") + if info.ThumbprintSHA256 != "" { + fmt.Fprintf(tw, " SHA-256 Thumbprint:\t%s\n", info.ThumbprintSHA256) + } + fmt.Fprintf(tw, " SHA-1 Thumbprint:\t%s\n", info.ThumbprintSHA1) + } + + return tw.Flush() +} diff --git a/vendor/github.com/vmware/govmomi/object/host_certificate_manager.go b/vendor/github.com/vmware/govmomi/object/host_certificate_manager.go new file mode 100644 index 0000000000..30787e7a47 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_certificate_manager.go @@ -0,0 +1,169 @@ +/* +Copyright (c) 2016-2024 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 object + +import ( + "context" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// HostCertificateManager provides helper methods around the HostSystem.ConfigManager.CertificateManager +type HostCertificateManager struct { + Common + Host *HostSystem +} + +// NewHostCertificateManager creates a new HostCertificateManager helper +func NewHostCertificateManager(c *vim25.Client, ref types.ManagedObjectReference, host types.ManagedObjectReference) *HostCertificateManager { + return &HostCertificateManager{ + Common: NewCommon(c, ref), + Host: NewHostSystem(c, host), + } +} + +// CertificateInfo wraps the host CertificateManager certificateInfo property with the HostCertificateInfo helper. +// The ThumbprintSHA1 field is set to HostSystem.Summary.Config.SslThumbprint if the host system is managed by a vCenter. +func (m HostCertificateManager) CertificateInfo(ctx context.Context) (*HostCertificateInfo, error) { + var hs mo.HostSystem + var cm mo.HostCertificateManager + + pc := property.DefaultCollector(m.Client()) + + err := pc.RetrieveOne(ctx, m.Reference(), []string{"certificateInfo"}, &cm) + if err != nil { + return nil, err + } + + _ = pc.RetrieveOne(ctx, m.Host.Reference(), []string{"summary.config.sslThumbprint"}, &hs) + + return &HostCertificateInfo{ + HostCertificateManagerCertificateInfo: cm.CertificateInfo, + ThumbprintSHA1: hs.Summary.Config.SslThumbprint, + }, nil +} + +// GenerateCertificateSigningRequest requests the host system to generate a certificate-signing request (CSR) for itself. +// The CSR is then typically provided to a Certificate Authority to sign and issue the SSL certificate for the host system. +// Use InstallServerCertificate to import this certificate. +func (m HostCertificateManager) GenerateCertificateSigningRequest(ctx context.Context, useIPAddressAsCommonName bool) (string, error) { + req := types.GenerateCertificateSigningRequest{ + This: m.Reference(), + UseIpAddressAsCommonName: useIPAddressAsCommonName, + } + + res, err := methods.GenerateCertificateSigningRequest(ctx, m.Client(), &req) + if err != nil { + return "", err + } + + return res.Returnval, nil +} + +// GenerateCertificateSigningRequestByDn requests the host system to generate a certificate-signing request (CSR) for itself. +// Alternative version similar to GenerateCertificateSigningRequest but takes a Distinguished Name (DN) as a parameter. +func (m HostCertificateManager) GenerateCertificateSigningRequestByDn(ctx context.Context, distinguishedName string) (string, error) { + req := types.GenerateCertificateSigningRequestByDn{ + This: m.Reference(), + DistinguishedName: distinguishedName, + } + + res, err := methods.GenerateCertificateSigningRequestByDn(ctx, m.Client(), &req) + if err != nil { + return "", err + } + + return res.Returnval, nil +} + +// InstallServerCertificate imports the given SSL certificate to the host system. +func (m HostCertificateManager) InstallServerCertificate(ctx context.Context, cert string) error { + req := types.InstallServerCertificate{ + This: m.Reference(), + Cert: cert, + } + + _, err := methods.InstallServerCertificate(ctx, m.Client(), &req) + if err != nil { + return err + } + + // NotifyAffectedService is internal, not exposing as we don't have a use case other than with InstallServerCertificate + // Without this call, hostd needs to be restarted to use the updated certificate + // Note: using Refresh as it has the same struct/signature, we just need to use different xml name tags + body := struct { + Req *types.Refresh `xml:"urn:vim25 NotifyAffectedServices,omitempty"` + Res *types.RefreshResponse `xml:"urn:vim25 NotifyAffectedServicesResponse,omitempty"` + methods.RefreshBody + }{ + Req: &types.Refresh{This: m.Reference()}, + } + + err = m.Client().RoundTrip(ctx, &body, &body) + if err != nil && soap.IsSoapFault(err) { + if _, ok := soap.ToSoapFault(err).VimFault().(types.MethodNotFound); ok { + return nil + } + } + return err +} + +// ListCACertificateRevocationLists returns the SSL CRLs of Certificate Authorities that are trusted by the host system. +func (m HostCertificateManager) ListCACertificateRevocationLists(ctx context.Context) ([]string, error) { + req := types.ListCACertificateRevocationLists{ + This: m.Reference(), + } + + res, err := methods.ListCACertificateRevocationLists(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +// ListCACertificates returns the SSL certificates of Certificate Authorities that are trusted by the host system. +func (m HostCertificateManager) ListCACertificates(ctx context.Context) ([]string, error) { + req := types.ListCACertificates{ + This: m.Reference(), + } + + res, err := methods.ListCACertificates(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +// ReplaceCACertificatesAndCRLs replaces the trusted CA certificates and CRL used by the host system. +// These determine whether the server can verify the identity of an external entity. +func (m HostCertificateManager) ReplaceCACertificatesAndCRLs(ctx context.Context, caCert []string, caCrl []string) error { + req := types.ReplaceCACertificatesAndCRLs{ + This: m.Reference(), + CaCert: caCert, + CaCrl: caCrl, + } + + _, err := methods.ReplaceCACertificatesAndCRLs(ctx, m.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/host_config_manager.go b/vendor/github.com/vmware/govmomi/object/host_config_manager.go new file mode 100644 index 0000000000..eac59a32eb --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_config_manager.go @@ -0,0 +1,171 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/types" +) + +type HostConfigManager struct { + Common +} + +func NewHostConfigManager(c *vim25.Client, ref types.ManagedObjectReference) *HostConfigManager { + return &HostConfigManager{ + Common: NewCommon(c, ref), + } +} + +// reference returns the ManagedObjectReference for the given HostConfigManager property name. +// An error is returned if the field is nil, of type ErrNotSupported if versioned is true. +func (m HostConfigManager) reference(ctx context.Context, name string, versioned ...bool) (types.ManagedObjectReference, error) { + prop := "configManager." + name + var content []types.ObjectContent + + err := m.Properties(ctx, m.Reference(), []string{prop}, &content) + if err != nil { + return types.ManagedObjectReference{}, err + } + + for _, c := range content { + for _, p := range c.PropSet { + if p.Name != prop { + continue + } + if ref, ok := p.Val.(types.ManagedObjectReference); ok { + return ref, nil + } + } + } + + err = fmt.Errorf("%s %s is nil", m.Reference(), prop) + if len(versioned) == 1 && versioned[0] { + err = ErrNotSupported + } + return types.ManagedObjectReference{}, err +} + +func (m HostConfigManager) DatastoreSystem(ctx context.Context) (*HostDatastoreSystem, error) { + ref, err := m.reference(ctx, "datastoreSystem") + if err != nil { + return nil, err + } + return NewHostDatastoreSystem(m.c, ref), nil +} + +func (m HostConfigManager) NetworkSystem(ctx context.Context) (*HostNetworkSystem, error) { + ref, err := m.reference(ctx, "networkSystem") + if err != nil { + return nil, err + } + return NewHostNetworkSystem(m.c, ref), nil +} + +func (m HostConfigManager) FirewallSystem(ctx context.Context) (*HostFirewallSystem, error) { + ref, err := m.reference(ctx, "firewallSystem") + if err != nil { + return nil, err + } + + return NewHostFirewallSystem(m.c, ref), nil +} + +func (m HostConfigManager) StorageSystem(ctx context.Context) (*HostStorageSystem, error) { + ref, err := m.reference(ctx, "storageSystem") + if err != nil { + return nil, err + } + return NewHostStorageSystem(m.c, ref), nil +} + +func (m HostConfigManager) VirtualNicManager(ctx context.Context) (*HostVirtualNicManager, error) { + ref, err := m.reference(ctx, "virtualNicManager") + if err != nil { + return nil, err + } + return NewHostVirtualNicManager(m.c, ref, m.Reference()), nil +} + +func (m HostConfigManager) VsanSystem(ctx context.Context) (*HostVsanSystem, error) { + ref, err := m.reference(ctx, "vsanSystem", true) // Added in 5.5 + if err != nil { + return nil, err + } + return NewHostVsanSystem(m.c, ref), nil +} + +func (m HostConfigManager) VsanInternalSystem(ctx context.Context) (*HostVsanInternalSystem, error) { + ref, err := m.reference(ctx, "vsanInternalSystem", true) // Added in 5.5 + if err != nil { + return nil, err + } + return NewHostVsanInternalSystem(m.c, ref), nil +} + +func (m HostConfigManager) AccountManager(ctx context.Context) (*HostAccountManager, error) { + ref, err := m.reference(ctx, "accountManager", true) // Added in 5.5 + if err != nil { + if err == ErrNotSupported { + // Versions < 5.5 can use the ServiceContent ref, + // but only when connected directly to ESX. + if m.c.ServiceContent.AccountManager == nil { + return nil, err + } + ref = *m.c.ServiceContent.AccountManager + } else { + return nil, err + } + } + + return NewHostAccountManager(m.c, ref), nil +} + +func (m HostConfigManager) OptionManager(ctx context.Context) (*OptionManager, error) { + ref, err := m.reference(ctx, "advancedOption") + if err != nil { + return nil, err + } + return NewOptionManager(m.c, ref), nil +} + +func (m HostConfigManager) ServiceSystem(ctx context.Context) (*HostServiceSystem, error) { + ref, err := m.reference(ctx, "serviceSystem") + if err != nil { + return nil, err + } + return NewHostServiceSystem(m.c, ref), nil +} + +func (m HostConfigManager) CertificateManager(ctx context.Context) (*HostCertificateManager, error) { + ref, err := m.reference(ctx, "certificateManager", true) // Added in 6.0 + if err != nil { + return nil, err + } + return NewHostCertificateManager(m.c, ref, m.Reference()), nil +} + +func (m HostConfigManager) DateTimeSystem(ctx context.Context) (*HostDateTimeSystem, error) { + ref, err := m.reference(ctx, "dateTimeSystem") + if err != nil { + return nil, err + } + return NewHostDateTimeSystem(m.c, ref), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_datastore_browser.go b/vendor/github.com/vmware/govmomi/object/host_datastore_browser.go new file mode 100644 index 0000000000..b0c9e08a12 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_datastore_browser.go @@ -0,0 +1,65 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostDatastoreBrowser struct { + Common +} + +func NewHostDatastoreBrowser(c *vim25.Client, ref types.ManagedObjectReference) *HostDatastoreBrowser { + return &HostDatastoreBrowser{ + Common: NewCommon(c, ref), + } +} + +func (b HostDatastoreBrowser) SearchDatastore(ctx context.Context, datastorePath string, searchSpec *types.HostDatastoreBrowserSearchSpec) (*Task, error) { + req := types.SearchDatastore_Task{ + This: b.Reference(), + DatastorePath: datastorePath, + SearchSpec: searchSpec, + } + + res, err := methods.SearchDatastore_Task(ctx, b.c, &req) + if err != nil { + return nil, err + } + + return NewTask(b.c, res.Returnval), nil +} + +func (b HostDatastoreBrowser) SearchDatastoreSubFolders(ctx context.Context, datastorePath string, searchSpec *types.HostDatastoreBrowserSearchSpec) (*Task, error) { + req := types.SearchDatastoreSubFolders_Task{ + This: b.Reference(), + DatastorePath: datastorePath, + SearchSpec: searchSpec, + } + + res, err := methods.SearchDatastoreSubFolders_Task(ctx, b.c, &req) + if err != nil { + return nil, err + } + + return NewTask(b.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_datastore_system.go b/vendor/github.com/vmware/govmomi/object/host_datastore_system.go new file mode 100644 index 0000000000..64f3add917 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_datastore_system.go @@ -0,0 +1,135 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostDatastoreSystem struct { + Common +} + +func NewHostDatastoreSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostDatastoreSystem { + return &HostDatastoreSystem{ + Common: NewCommon(c, ref), + } +} + +func (s HostDatastoreSystem) CreateLocalDatastore(ctx context.Context, name string, path string) (*Datastore, error) { + req := types.CreateLocalDatastore{ + This: s.Reference(), + Name: name, + Path: path, + } + + res, err := methods.CreateLocalDatastore(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return NewDatastore(s.Client(), res.Returnval), nil +} + +func (s HostDatastoreSystem) CreateNasDatastore(ctx context.Context, spec types.HostNasVolumeSpec) (*Datastore, error) { + req := types.CreateNasDatastore{ + This: s.Reference(), + Spec: spec, + } + + res, err := methods.CreateNasDatastore(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return NewDatastore(s.Client(), res.Returnval), nil +} + +func (s HostDatastoreSystem) CreateVmfsDatastore(ctx context.Context, spec types.VmfsDatastoreCreateSpec) (*Datastore, error) { + req := types.CreateVmfsDatastore{ + This: s.Reference(), + Spec: spec, + } + + res, err := methods.CreateVmfsDatastore(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return NewDatastore(s.Client(), res.Returnval), nil +} + +func (s HostDatastoreSystem) Remove(ctx context.Context, ds *Datastore) error { + req := types.RemoveDatastore{ + This: s.Reference(), + Datastore: ds.Reference(), + } + + _, err := methods.RemoveDatastore(ctx, s.Client(), &req) + if err != nil { + return err + } + + return nil +} + +func (s HostDatastoreSystem) QueryAvailableDisksForVmfs(ctx context.Context) ([]types.HostScsiDisk, error) { + req := types.QueryAvailableDisksForVmfs{ + This: s.Reference(), + } + + res, err := methods.QueryAvailableDisksForVmfs(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (s HostDatastoreSystem) QueryVmfsDatastoreCreateOptions(ctx context.Context, devicePath string) ([]types.VmfsDatastoreOption, error) { + req := types.QueryVmfsDatastoreCreateOptions{ + This: s.Reference(), + DevicePath: devicePath, + } + + res, err := methods.QueryVmfsDatastoreCreateOptions(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (s HostDatastoreSystem) ResignatureUnresolvedVmfsVolumes(ctx context.Context, devicePaths []string) (*Task, error) { + req := &types.ResignatureUnresolvedVmfsVolume_Task{ + This: s.Reference(), + ResolutionSpec: types.HostUnresolvedVmfsResignatureSpec{ + ExtentDevicePath: devicePaths, + }, + } + + res, err := methods.ResignatureUnresolvedVmfsVolume_Task(ctx, s.Client(), req) + if err != nil { + return nil, err + } + + return NewTask(s.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_date_time_system.go b/vendor/github.com/vmware/govmomi/object/host_date_time_system.go new file mode 100644 index 0000000000..7c9203d7b6 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_date_time_system.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2016 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 object + +import ( + "context" + "time" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostDateTimeSystem struct { + Common +} + +func NewHostDateTimeSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostDateTimeSystem { + return &HostDateTimeSystem{ + Common: NewCommon(c, ref), + } +} + +func (s HostDateTimeSystem) UpdateConfig(ctx context.Context, config types.HostDateTimeConfig) error { + req := types.UpdateDateTimeConfig{ + This: s.Reference(), + Config: config, + } + + _, err := methods.UpdateDateTimeConfig(ctx, s.c, &req) + return err +} + +func (s HostDateTimeSystem) Update(ctx context.Context, date time.Time) error { + req := types.UpdateDateTime{ + This: s.Reference(), + DateTime: date, + } + + _, err := methods.UpdateDateTime(ctx, s.c, &req) + return err +} + +func (s HostDateTimeSystem) Query(ctx context.Context) (*time.Time, error) { + req := types.QueryDateTime{ + This: s.Reference(), + } + + res, err := methods.QueryDateTime(ctx, s.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_firewall_system.go b/vendor/github.com/vmware/govmomi/object/host_firewall_system.go new file mode 100644 index 0000000000..0b14402531 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_firewall_system.go @@ -0,0 +1,181 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type HostFirewallSystem struct { + Common +} + +func NewHostFirewallSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostFirewallSystem { + return &HostFirewallSystem{ + Common: NewCommon(c, ref), + } +} + +func (s HostFirewallSystem) DisableRuleset(ctx context.Context, id string) error { + req := types.DisableRuleset{ + This: s.Reference(), + Id: id, + } + + _, err := methods.DisableRuleset(ctx, s.c, &req) + return err +} + +func (s HostFirewallSystem) EnableRuleset(ctx context.Context, id string) error { + req := types.EnableRuleset{ + This: s.Reference(), + Id: id, + } + + _, err := methods.EnableRuleset(ctx, s.c, &req) + return err +} + +func (s HostFirewallSystem) Refresh(ctx context.Context) error { + req := types.RefreshFirewall{ + This: s.Reference(), + } + + _, err := methods.RefreshFirewall(ctx, s.c, &req) + return err +} + +func (s HostFirewallSystem) Info(ctx context.Context) (*types.HostFirewallInfo, error) { + var fs mo.HostFirewallSystem + + err := s.Properties(ctx, s.Reference(), []string{"firewallInfo"}, &fs) + if err != nil { + return nil, err + } + + return fs.FirewallInfo, nil +} + +// HostFirewallRulesetList provides helpers for a slice of types.HostFirewallRuleset +type HostFirewallRulesetList []types.HostFirewallRuleset + +// ByRule returns a HostFirewallRulesetList where Direction, PortType and Protocol are equal and Port is within range +func (l HostFirewallRulesetList) ByRule(rule types.HostFirewallRule) HostFirewallRulesetList { + var matches HostFirewallRulesetList + + for _, rs := range l { + for _, r := range rs.Rule { + if r.PortType != rule.PortType || + r.Protocol != rule.Protocol || + r.Direction != rule.Direction { + continue + } + + if r.EndPort == 0 && rule.Port == r.Port || + rule.Port >= r.Port && rule.Port <= r.EndPort { + matches = append(matches, rs) + break + } + } + } + + return matches +} + +// EnabledByRule returns a HostFirewallRulesetList with Match(rule) applied and filtered via Enabled() +// if enabled param is true, otherwise filtered via Disabled(). +// An error is returned if the resulting list is empty. +func (l HostFirewallRulesetList) EnabledByRule(rule types.HostFirewallRule, enabled bool) (HostFirewallRulesetList, error) { + var matched, skipped HostFirewallRulesetList + var matchedKind, skippedKind string + + l = l.ByRule(rule) + + if enabled { + matched = l.Enabled() + matchedKind = "enabled" + + skipped = l.Disabled() + skippedKind = "disabled" + } else { + matched = l.Disabled() + matchedKind = "disabled" + + skipped = l.Enabled() + skippedKind = "enabled" + } + + if len(matched) == 0 { + msg := fmt.Sprintf("%d %s firewall rulesets match %s %s %s %d, %d %s rulesets match", + len(matched), matchedKind, + rule.Direction, rule.Protocol, rule.PortType, rule.Port, + len(skipped), skippedKind) + + if len(skipped) != 0 { + msg += fmt.Sprintf(": %s", strings.Join(skipped.Keys(), ", ")) + } + + return nil, errors.New(msg) + } + + return matched, nil +} + +// Enabled returns a HostFirewallRulesetList with enabled rules +func (l HostFirewallRulesetList) Enabled() HostFirewallRulesetList { + var matches HostFirewallRulesetList + + for _, rs := range l { + if rs.Enabled { + matches = append(matches, rs) + } + } + + return matches +} + +// Disabled returns a HostFirewallRulesetList with disabled rules +func (l HostFirewallRulesetList) Disabled() HostFirewallRulesetList { + var matches HostFirewallRulesetList + + for _, rs := range l { + if !rs.Enabled { + matches = append(matches, rs) + } + } + + return matches +} + +// Keys returns the HostFirewallRuleset.Key for each ruleset in the list +func (l HostFirewallRulesetList) Keys() []string { + var keys []string + + for _, rs := range l { + keys = append(keys, rs.Key) + } + + return keys +} diff --git a/vendor/github.com/vmware/govmomi/object/host_network_system.go b/vendor/github.com/vmware/govmomi/object/host_network_system.go new file mode 100644 index 0000000000..340b764a51 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_network_system.go @@ -0,0 +1,358 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostNetworkSystem struct { + Common +} + +func NewHostNetworkSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostNetworkSystem { + return &HostNetworkSystem{ + Common: NewCommon(c, ref), + } +} + +// AddPortGroup wraps methods.AddPortGroup +func (o HostNetworkSystem) AddPortGroup(ctx context.Context, portgrp types.HostPortGroupSpec) error { + req := types.AddPortGroup{ + This: o.Reference(), + Portgrp: portgrp, + } + + _, err := methods.AddPortGroup(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// AddServiceConsoleVirtualNic wraps methods.AddServiceConsoleVirtualNic +func (o HostNetworkSystem) AddServiceConsoleVirtualNic(ctx context.Context, portgroup string, nic types.HostVirtualNicSpec) (string, error) { + req := types.AddServiceConsoleVirtualNic{ + This: o.Reference(), + Portgroup: portgroup, + Nic: nic, + } + + res, err := methods.AddServiceConsoleVirtualNic(ctx, o.c, &req) + if err != nil { + return "", err + } + + return res.Returnval, nil +} + +// AddVirtualNic wraps methods.AddVirtualNic +func (o HostNetworkSystem) AddVirtualNic(ctx context.Context, portgroup string, nic types.HostVirtualNicSpec) (string, error) { + req := types.AddVirtualNic{ + This: o.Reference(), + Portgroup: portgroup, + Nic: nic, + } + + res, err := methods.AddVirtualNic(ctx, o.c, &req) + if err != nil { + return "", err + } + + return res.Returnval, nil +} + +// AddVirtualSwitch wraps methods.AddVirtualSwitch +func (o HostNetworkSystem) AddVirtualSwitch(ctx context.Context, vswitchName string, spec *types.HostVirtualSwitchSpec) error { + req := types.AddVirtualSwitch{ + This: o.Reference(), + VswitchName: vswitchName, + Spec: spec, + } + + _, err := methods.AddVirtualSwitch(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// QueryNetworkHint wraps methods.QueryNetworkHint +func (o HostNetworkSystem) QueryNetworkHint(ctx context.Context, device []string) ([]types.PhysicalNicHintInfo, error) { + req := types.QueryNetworkHint{ + This: o.Reference(), + Device: device, + } + + res, err := methods.QueryNetworkHint(ctx, o.c, &req) + if err != nil { + return nil, err + } + + return res.Returnval, err +} + +// RefreshNetworkSystem wraps methods.RefreshNetworkSystem +func (o HostNetworkSystem) RefreshNetworkSystem(ctx context.Context) error { + req := types.RefreshNetworkSystem{ + This: o.Reference(), + } + + _, err := methods.RefreshNetworkSystem(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// RemovePortGroup wraps methods.RemovePortGroup +func (o HostNetworkSystem) RemovePortGroup(ctx context.Context, pgName string) error { + req := types.RemovePortGroup{ + This: o.Reference(), + PgName: pgName, + } + + _, err := methods.RemovePortGroup(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// RemoveServiceConsoleVirtualNic wraps methods.RemoveServiceConsoleVirtualNic +func (o HostNetworkSystem) RemoveServiceConsoleVirtualNic(ctx context.Context, device string) error { + req := types.RemoveServiceConsoleVirtualNic{ + This: o.Reference(), + Device: device, + } + + _, err := methods.RemoveServiceConsoleVirtualNic(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// RemoveVirtualNic wraps methods.RemoveVirtualNic +func (o HostNetworkSystem) RemoveVirtualNic(ctx context.Context, device string) error { + req := types.RemoveVirtualNic{ + This: o.Reference(), + Device: device, + } + + _, err := methods.RemoveVirtualNic(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// RemoveVirtualSwitch wraps methods.RemoveVirtualSwitch +func (o HostNetworkSystem) RemoveVirtualSwitch(ctx context.Context, vswitchName string) error { + req := types.RemoveVirtualSwitch{ + This: o.Reference(), + VswitchName: vswitchName, + } + + _, err := methods.RemoveVirtualSwitch(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// RestartServiceConsoleVirtualNic wraps methods.RestartServiceConsoleVirtualNic +func (o HostNetworkSystem) RestartServiceConsoleVirtualNic(ctx context.Context, device string) error { + req := types.RestartServiceConsoleVirtualNic{ + This: o.Reference(), + Device: device, + } + + _, err := methods.RestartServiceConsoleVirtualNic(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdateConsoleIpRouteConfig wraps methods.UpdateConsoleIpRouteConfig +func (o HostNetworkSystem) UpdateConsoleIpRouteConfig(ctx context.Context, config types.BaseHostIpRouteConfig) error { + req := types.UpdateConsoleIpRouteConfig{ + This: o.Reference(), + Config: config, + } + + _, err := methods.UpdateConsoleIpRouteConfig(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdateDnsConfig wraps methods.UpdateDnsConfig +func (o HostNetworkSystem) UpdateDnsConfig(ctx context.Context, config types.BaseHostDnsConfig) error { + req := types.UpdateDnsConfig{ + This: o.Reference(), + Config: config, + } + + _, err := methods.UpdateDnsConfig(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdateIpRouteConfig wraps methods.UpdateIpRouteConfig +func (o HostNetworkSystem) UpdateIpRouteConfig(ctx context.Context, config types.BaseHostIpRouteConfig) error { + req := types.UpdateIpRouteConfig{ + This: o.Reference(), + Config: config, + } + + _, err := methods.UpdateIpRouteConfig(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdateIpRouteTableConfig wraps methods.UpdateIpRouteTableConfig +func (o HostNetworkSystem) UpdateIpRouteTableConfig(ctx context.Context, config types.HostIpRouteTableConfig) error { + req := types.UpdateIpRouteTableConfig{ + This: o.Reference(), + Config: config, + } + + _, err := methods.UpdateIpRouteTableConfig(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdateNetworkConfig wraps methods.UpdateNetworkConfig +func (o HostNetworkSystem) UpdateNetworkConfig(ctx context.Context, config types.HostNetworkConfig, changeMode string) (*types.HostNetworkConfigResult, error) { + req := types.UpdateNetworkConfig{ + This: o.Reference(), + Config: config, + ChangeMode: changeMode, + } + + res, err := methods.UpdateNetworkConfig(ctx, o.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +// UpdatePhysicalNicLinkSpeed wraps methods.UpdatePhysicalNicLinkSpeed +func (o HostNetworkSystem) UpdatePhysicalNicLinkSpeed(ctx context.Context, device string, linkSpeed *types.PhysicalNicLinkInfo) error { + req := types.UpdatePhysicalNicLinkSpeed{ + This: o.Reference(), + Device: device, + LinkSpeed: linkSpeed, + } + + _, err := methods.UpdatePhysicalNicLinkSpeed(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdatePortGroup wraps methods.UpdatePortGroup +func (o HostNetworkSystem) UpdatePortGroup(ctx context.Context, pgName string, portgrp types.HostPortGroupSpec) error { + req := types.UpdatePortGroup{ + This: o.Reference(), + PgName: pgName, + Portgrp: portgrp, + } + + _, err := methods.UpdatePortGroup(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdateServiceConsoleVirtualNic wraps methods.UpdateServiceConsoleVirtualNic +func (o HostNetworkSystem) UpdateServiceConsoleVirtualNic(ctx context.Context, device string, nic types.HostVirtualNicSpec) error { + req := types.UpdateServiceConsoleVirtualNic{ + This: o.Reference(), + Device: device, + Nic: nic, + } + + _, err := methods.UpdateServiceConsoleVirtualNic(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdateVirtualNic wraps methods.UpdateVirtualNic +func (o HostNetworkSystem) UpdateVirtualNic(ctx context.Context, device string, nic types.HostVirtualNicSpec) error { + req := types.UpdateVirtualNic{ + This: o.Reference(), + Device: device, + Nic: nic, + } + + _, err := methods.UpdateVirtualNic(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} + +// UpdateVirtualSwitch wraps methods.UpdateVirtualSwitch +func (o HostNetworkSystem) UpdateVirtualSwitch(ctx context.Context, vswitchName string, spec types.HostVirtualSwitchSpec) error { + req := types.UpdateVirtualSwitch{ + This: o.Reference(), + VswitchName: vswitchName, + Spec: spec, + } + + _, err := methods.UpdateVirtualSwitch(ctx, o.c, &req) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_service_system.go b/vendor/github.com/vmware/govmomi/object/host_service_system.go new file mode 100644 index 0000000000..a66b32c17c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_service_system.go @@ -0,0 +1,88 @@ +/* +Copyright (c) 2016 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type HostServiceSystem struct { + Common +} + +func NewHostServiceSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostServiceSystem { + return &HostServiceSystem{ + Common: NewCommon(c, ref), + } +} + +func (s HostServiceSystem) Service(ctx context.Context) ([]types.HostService, error) { + var ss mo.HostServiceSystem + + err := s.Properties(ctx, s.Reference(), []string{"serviceInfo.service"}, &ss) + if err != nil { + return nil, err + } + + return ss.ServiceInfo.Service, nil +} + +func (s HostServiceSystem) Start(ctx context.Context, id string) error { + req := types.StartService{ + This: s.Reference(), + Id: id, + } + + _, err := methods.StartService(ctx, s.Client(), &req) + return err +} + +func (s HostServiceSystem) Stop(ctx context.Context, id string) error { + req := types.StopService{ + This: s.Reference(), + Id: id, + } + + _, err := methods.StopService(ctx, s.Client(), &req) + return err +} + +func (s HostServiceSystem) Restart(ctx context.Context, id string) error { + req := types.RestartService{ + This: s.Reference(), + Id: id, + } + + _, err := methods.RestartService(ctx, s.Client(), &req) + return err +} + +func (s HostServiceSystem) UpdatePolicy(ctx context.Context, id string, policy string) error { + req := types.UpdateServicePolicy{ + This: s.Reference(), + Id: id, + Policy: policy, + } + + _, err := methods.UpdateServicePolicy(ctx, s.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/host_storage_system.go b/vendor/github.com/vmware/govmomi/object/host_storage_system.go new file mode 100644 index 0000000000..5c9f08eee1 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_storage_system.go @@ -0,0 +1,200 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "errors" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostStorageSystem struct { + Common +} + +func NewHostStorageSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostStorageSystem { + return &HostStorageSystem{ + Common: NewCommon(c, ref), + } +} + +func (s HostStorageSystem) RetrieveDiskPartitionInfo(ctx context.Context, devicePath string) (*types.HostDiskPartitionInfo, error) { + req := types.RetrieveDiskPartitionInfo{ + This: s.Reference(), + DevicePath: []string{devicePath}, + } + + res, err := methods.RetrieveDiskPartitionInfo(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if res.Returnval == nil || len(res.Returnval) == 0 { + return nil, errors.New("no partition info") + } + + return &res.Returnval[0], nil +} + +func (s HostStorageSystem) ComputeDiskPartitionInfo(ctx context.Context, devicePath string, layout types.HostDiskPartitionLayout) (*types.HostDiskPartitionInfo, error) { + req := types.ComputeDiskPartitionInfo{ + This: s.Reference(), + DevicePath: devicePath, + Layout: layout, + } + + res, err := methods.ComputeDiskPartitionInfo(ctx, s.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +func (s HostStorageSystem) UpdateDiskPartitionInfo(ctx context.Context, devicePath string, spec types.HostDiskPartitionSpec) error { + req := types.UpdateDiskPartitions{ + This: s.Reference(), + DevicePath: devicePath, + Spec: spec, + } + + _, err := methods.UpdateDiskPartitions(ctx, s.c, &req) + return err +} + +func (s HostStorageSystem) RescanAllHba(ctx context.Context) error { + req := types.RescanAllHba{ + This: s.Reference(), + } + + _, err := methods.RescanAllHba(ctx, s.c, &req) + return err +} + +func (s HostStorageSystem) Refresh(ctx context.Context) error { + req := types.RefreshStorageSystem{ + This: s.Reference(), + } + + _, err := methods.RefreshStorageSystem(ctx, s.c, &req) + return err +} + +func (s HostStorageSystem) RescanVmfs(ctx context.Context) error { + req := types.RescanVmfs{ + This: s.Reference(), + } + + _, err := methods.RescanVmfs(ctx, s.c, &req) + return err +} + +func (s HostStorageSystem) MarkAsSsd(ctx context.Context, uuid string) (*Task, error) { + req := types.MarkAsSsd_Task{ + This: s.Reference(), + ScsiDiskUuid: uuid, + } + + res, err := methods.MarkAsSsd_Task(ctx, s.c, &req) + if err != nil { + return nil, err + } + + return NewTask(s.c, res.Returnval), nil +} + +func (s HostStorageSystem) MarkAsNonSsd(ctx context.Context, uuid string) (*Task, error) { + req := types.MarkAsNonSsd_Task{ + This: s.Reference(), + ScsiDiskUuid: uuid, + } + + res, err := methods.MarkAsNonSsd_Task(ctx, s.c, &req) + if err != nil { + return nil, err + } + + return NewTask(s.c, res.Returnval), nil +} + +func (s HostStorageSystem) MarkAsLocal(ctx context.Context, uuid string) (*Task, error) { + req := types.MarkAsLocal_Task{ + This: s.Reference(), + ScsiDiskUuid: uuid, + } + + res, err := methods.MarkAsLocal_Task(ctx, s.c, &req) + if err != nil { + return nil, err + } + + return NewTask(s.c, res.Returnval), nil +} + +func (s HostStorageSystem) MarkAsNonLocal(ctx context.Context, uuid string) (*Task, error) { + req := types.MarkAsNonLocal_Task{ + This: s.Reference(), + ScsiDiskUuid: uuid, + } + + res, err := methods.MarkAsNonLocal_Task(ctx, s.c, &req) + if err != nil { + return nil, err + } + + return NewTask(s.c, res.Returnval), nil +} + +func (s HostStorageSystem) AttachScsiLun(ctx context.Context, uuid string) error { + req := types.AttachScsiLun{ + This: s.Reference(), + LunUuid: uuid, + } + + _, err := methods.AttachScsiLun(ctx, s.c, &req) + + return err +} + +func (s HostStorageSystem) QueryUnresolvedVmfsVolumes(ctx context.Context) ([]types.HostUnresolvedVmfsVolume, error) { + req := &types.QueryUnresolvedVmfsVolume{ + This: s.Reference(), + } + + res, err := methods.QueryUnresolvedVmfsVolume(ctx, s.Client(), req) + if err != nil { + return nil, err + } + return res.Returnval, nil +} + +func (s HostStorageSystem) UnmountVmfsVolume(ctx context.Context, vmfsUuid string) error { + req := &types.UnmountVmfsVolume{ + This: s.Reference(), + VmfsUuid: vmfsUuid, + } + + _, err := methods.UnmountVmfsVolume(ctx, s.Client(), req) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_system.go b/vendor/github.com/vmware/govmomi/object/host_system.go new file mode 100644 index 0000000000..ddf6cb8f11 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_system.go @@ -0,0 +1,154 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + "fmt" + "net" + + "github.com/vmware/govmomi/internal" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type HostSystem struct { + Common +} + +func NewHostSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostSystem { + return &HostSystem{ + Common: NewCommon(c, ref), + } +} + +func (h HostSystem) ConfigManager() *HostConfigManager { + return NewHostConfigManager(h.c, h.Reference()) +} + +func (h HostSystem) ResourcePool(ctx context.Context) (*ResourcePool, error) { + var mh mo.HostSystem + + err := h.Properties(ctx, h.Reference(), []string{"parent"}, &mh) + if err != nil { + return nil, err + } + + var mcr *mo.ComputeResource + var parent interface{} + + switch mh.Parent.Type { + case "ComputeResource": + mcr = new(mo.ComputeResource) + parent = mcr + case "ClusterComputeResource": + mcc := new(mo.ClusterComputeResource) + mcr = &mcc.ComputeResource + parent = mcc + default: + return nil, fmt.Errorf("unknown host parent type: %s", mh.Parent.Type) + } + + err = h.Properties(ctx, *mh.Parent, []string{"resourcePool"}, parent) + if err != nil { + return nil, err + } + + pool := NewResourcePool(h.c, *mcr.ResourcePool) + return pool, nil +} + +func (h HostSystem) ManagementIPs(ctx context.Context) ([]net.IP, error) { + var mh mo.HostSystem + + err := h.Properties(ctx, h.Reference(), []string{"config.virtualNicManagerInfo.netConfig"}, &mh) + if err != nil { + return nil, err + } + + config := mh.Config + if config == nil { + return nil, nil + } + + info := config.VirtualNicManagerInfo + if info == nil { + return nil, nil + } + + return internal.HostSystemManagementIPs(info.NetConfig), nil +} + +func (h HostSystem) Disconnect(ctx context.Context) (*Task, error) { + req := types.DisconnectHost_Task{ + This: h.Reference(), + } + + res, err := methods.DisconnectHost_Task(ctx, h.c, &req) + if err != nil { + return nil, err + } + + return NewTask(h.c, res.Returnval), nil +} + +func (h HostSystem) Reconnect(ctx context.Context, cnxSpec *types.HostConnectSpec, reconnectSpec *types.HostSystemReconnectSpec) (*Task, error) { + req := types.ReconnectHost_Task{ + This: h.Reference(), + CnxSpec: cnxSpec, + ReconnectSpec: reconnectSpec, + } + + res, err := methods.ReconnectHost_Task(ctx, h.c, &req) + if err != nil { + return nil, err + } + + return NewTask(h.c, res.Returnval), nil +} + +func (h HostSystem) EnterMaintenanceMode(ctx context.Context, timeout int32, evacuate bool, spec *types.HostMaintenanceSpec) (*Task, error) { + req := types.EnterMaintenanceMode_Task{ + This: h.Reference(), + Timeout: timeout, + EvacuatePoweredOffVms: types.NewBool(evacuate), + MaintenanceSpec: spec, + } + + res, err := methods.EnterMaintenanceMode_Task(ctx, h.c, &req) + if err != nil { + return nil, err + } + + return NewTask(h.c, res.Returnval), nil +} + +func (h HostSystem) ExitMaintenanceMode(ctx context.Context, timeout int32) (*Task, error) { + req := types.ExitMaintenanceMode_Task{ + This: h.Reference(), + Timeout: timeout, + } + + res, err := methods.ExitMaintenanceMode_Task(ctx, h.c, &req) + if err != nil { + return nil, err + } + + return NewTask(h.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go b/vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go new file mode 100644 index 0000000000..01e7e9cd4b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type HostVirtualNicManager struct { + Common + Host *HostSystem +} + +func NewHostVirtualNicManager(c *vim25.Client, ref types.ManagedObjectReference, host types.ManagedObjectReference) *HostVirtualNicManager { + return &HostVirtualNicManager{ + Common: NewCommon(c, ref), + Host: NewHostSystem(c, host), + } +} + +func (m HostVirtualNicManager) Info(ctx context.Context) (*types.HostVirtualNicManagerInfo, error) { + var vnm mo.HostVirtualNicManager + + err := m.Properties(ctx, m.Reference(), []string{"info"}, &vnm) + if err != nil { + return nil, err + } + + return &vnm.Info, nil +} + +func (m HostVirtualNicManager) DeselectVnic(ctx context.Context, nicType string, device string) error { + if nicType == string(types.HostVirtualNicManagerNicTypeVsan) { + // Avoid fault.NotSupported: + // "Error deselecting device '$device': VSAN interfaces must be deselected using vim.host.VsanSystem" + s, err := m.Host.ConfigManager().VsanSystem(ctx) + if err != nil { + return err + } + + return s.updateVnic(ctx, device, false) + } + + req := types.DeselectVnicForNicType{ + This: m.Reference(), + NicType: nicType, + Device: device, + } + + _, err := methods.DeselectVnicForNicType(ctx, m.Client(), &req) + return err +} + +func (m HostVirtualNicManager) SelectVnic(ctx context.Context, nicType string, device string) error { + if nicType == string(types.HostVirtualNicManagerNicTypeVsan) { + // Avoid fault.NotSupported: + // "Error selecting device '$device': VSAN interfaces must be selected using vim.host.VsanSystem" + s, err := m.Host.ConfigManager().VsanSystem(ctx) + if err != nil { + return err + } + + return s.updateVnic(ctx, device, true) + } + + req := types.SelectVnicForNicType{ + This: m.Reference(), + NicType: nicType, + Device: device, + } + + _, err := methods.SelectVnicForNicType(ctx, m.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/host_vsan_internal_system.go b/vendor/github.com/vmware/govmomi/object/host_vsan_internal_system.go new file mode 100644 index 0000000000..1430e8a882 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_vsan_internal_system.go @@ -0,0 +1,117 @@ +/* +Copyright (c) 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 object + +import ( + "context" + "encoding/json" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostVsanInternalSystem struct { + Common +} + +func NewHostVsanInternalSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostVsanInternalSystem { + m := HostVsanInternalSystem{ + Common: NewCommon(c, ref), + } + + return &m +} + +// QueryVsanObjectUuidsByFilter returns vSAN DOM object uuids by filter. +func (m HostVsanInternalSystem) QueryVsanObjectUuidsByFilter(ctx context.Context, uuids []string, limit int32, version int32) ([]string, error) { + req := types.QueryVsanObjectUuidsByFilter{ + This: m.Reference(), + Uuids: uuids, + Limit: &limit, + Version: version, + } + + res, err := methods.QueryVsanObjectUuidsByFilter(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +type VsanObjExtAttrs struct { + Type string `json:"Object type"` + Class string `json:"Object class"` + Size string `json:"Object size"` + Path string `json:"Object path"` + Name string `json:"User friendly name"` +} + +func (a *VsanObjExtAttrs) DatastorePath(dir string) string { + l := len(dir) + path := a.Path + + if len(path) >= l { + path = a.Path[l:] + } + + if path != "" { + return path + } + + return a.Name // vmnamespace +} + +// GetVsanObjExtAttrs is internal and intended for troubleshooting/debugging situations in the field. +// WARNING: This API can be slow because we do IOs (reads) to all the objects. +func (m HostVsanInternalSystem) GetVsanObjExtAttrs(ctx context.Context, uuids []string) (map[string]VsanObjExtAttrs, error) { + req := types.GetVsanObjExtAttrs{ + This: m.Reference(), + Uuids: uuids, + } + + res, err := methods.GetVsanObjExtAttrs(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + var attrs map[string]VsanObjExtAttrs + + err = json.Unmarshal([]byte(res.Returnval), &attrs) + + return attrs, err +} + +// DeleteVsanObjects is internal and intended for troubleshooting/debugging only. +// WARNING: This API can be slow because we do IOs to all the objects. +// DOM won't allow access to objects which have lost quorum. Such objects can be deleted with the optional "force" flag. +// These objects may however re-appear with quorum if the absent components come back (network partition gets resolved, etc.) +func (m HostVsanInternalSystem) DeleteVsanObjects(ctx context.Context, uuids []string, force *bool) ([]types.HostVsanInternalSystemDeleteVsanObjectsResult, error) { + req := types.DeleteVsanObjects{ + This: m.Reference(), + Uuids: uuids, + Force: force, + } + + res, err := methods.DeleteVsanObjects(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_vsan_system.go b/vendor/github.com/vmware/govmomi/object/host_vsan_system.go new file mode 100644 index 0000000000..5ab234d5e5 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_vsan_system.go @@ -0,0 +1,88 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type HostVsanSystem struct { + Common +} + +func NewHostVsanSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostVsanSystem { + return &HostVsanSystem{ + Common: NewCommon(c, ref), + } +} + +func (s HostVsanSystem) Update(ctx context.Context, config types.VsanHostConfigInfo) (*Task, error) { + req := types.UpdateVsan_Task{ + This: s.Reference(), + Config: config, + } + + res, err := methods.UpdateVsan_Task(ctx, s.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(s.Client(), res.Returnval), nil +} + +// updateVnic in support of the HostVirtualNicManager.{SelectVnic,DeselectVnic} methods +func (s HostVsanSystem) updateVnic(ctx context.Context, device string, enable bool) error { + var vsan mo.HostVsanSystem + + err := s.Properties(ctx, s.Reference(), []string{"config.networkInfo.port"}, &vsan) + if err != nil { + return err + } + + info := vsan.Config + + var port []types.VsanHostConfigInfoNetworkInfoPortConfig + + for _, p := range info.NetworkInfo.Port { + if p.Device == device { + continue + } + + port = append(port, p) + } + + if enable { + port = append(port, types.VsanHostConfigInfoNetworkInfoPortConfig{ + Device: device, + }) + } + + info.NetworkInfo.Port = port + + task, err := s.Update(ctx, info) + if err != nil { + return err + } + + _, err = task.WaitForResult(ctx, nil) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/namespace_manager.go b/vendor/github.com/vmware/govmomi/object/namespace_manager.go new file mode 100644 index 0000000000..f463b368cd --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/namespace_manager.go @@ -0,0 +1,76 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type DatastoreNamespaceManager struct { + Common +} + +func NewDatastoreNamespaceManager(c *vim25.Client) *DatastoreNamespaceManager { + n := DatastoreNamespaceManager{ + Common: NewCommon(c, *c.ServiceContent.DatastoreNamespaceManager), + } + + return &n +} + +// CreateDirectory creates a top-level directory on the given vsan datastore, using +// the given user display name hint and opaque storage policy. +func (nm DatastoreNamespaceManager) CreateDirectory(ctx context.Context, ds *Datastore, displayName string, policy string) (string, error) { + + req := &types.CreateDirectory{ + This: nm.Reference(), + Datastore: ds.Reference(), + DisplayName: displayName, + Policy: policy, + } + + resp, err := methods.CreateDirectory(ctx, nm.c, req) + if err != nil { + return "", err + } + + return resp.Returnval, nil +} + +// DeleteDirectory deletes the given top-level directory from a vsan datastore. +func (nm DatastoreNamespaceManager) DeleteDirectory(ctx context.Context, dc *Datacenter, datastorePath string) error { + + req := &types.DeleteDirectory{ + This: nm.Reference(), + DatastorePath: datastorePath, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + if _, err := methods.DeleteDirectory(ctx, nm.c, req); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/vmware/govmomi/object/network.go b/vendor/github.com/vmware/govmomi/object/network.go new file mode 100644 index 0000000000..f209a7ac4c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/network.go @@ -0,0 +1,54 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/types" +) + +type Network struct { + Common +} + +func NewNetwork(c *vim25.Client, ref types.ManagedObjectReference) *Network { + return &Network{ + Common: NewCommon(c, ref), + } +} + +func (n Network) GetInventoryPath() string { + return n.InventoryPath +} + +// EthernetCardBackingInfo returns the VirtualDeviceBackingInfo for this Network +func (n Network) EthernetCardBackingInfo(ctx context.Context) (types.BaseVirtualDeviceBackingInfo, error) { + name, err := n.ObjectName(ctx) + if err != nil { + return nil, err + } + + backing := &types.VirtualEthernetCardNetworkBackingInfo{ + VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{ + DeviceName: name, + }, + } + + return backing, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/network_reference.go b/vendor/github.com/vmware/govmomi/object/network_reference.go new file mode 100644 index 0000000000..f1a41cd59b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/network_reference.go @@ -0,0 +1,31 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25/types" +) + +// The NetworkReference interface is implemented by managed objects +// which can be used as the backing for a VirtualEthernetCard. +type NetworkReference interface { + Reference + GetInventoryPath() string + EthernetCardBackingInfo(ctx context.Context) (types.BaseVirtualDeviceBackingInfo, error) +} diff --git a/vendor/github.com/vmware/govmomi/object/opaque_network.go b/vendor/github.com/vmware/govmomi/object/opaque_network.go new file mode 100644 index 0000000000..6797d325de --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/opaque_network.go @@ -0,0 +1,72 @@ +/* +Copyright (c) 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 object + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type OpaqueNetwork struct { + Common +} + +func NewOpaqueNetwork(c *vim25.Client, ref types.ManagedObjectReference) *OpaqueNetwork { + return &OpaqueNetwork{ + Common: NewCommon(c, ref), + } +} + +func (n OpaqueNetwork) GetInventoryPath() string { + return n.InventoryPath +} + +// EthernetCardBackingInfo returns the VirtualDeviceBackingInfo for this Network +func (n OpaqueNetwork) EthernetCardBackingInfo(ctx context.Context) (types.BaseVirtualDeviceBackingInfo, error) { + summary, err := n.Summary(ctx) + if err != nil { + return nil, err + } + + backing := &types.VirtualEthernetCardOpaqueNetworkBackingInfo{ + OpaqueNetworkId: summary.OpaqueNetworkId, + OpaqueNetworkType: summary.OpaqueNetworkType, + } + + return backing, nil +} + +// Summary returns the mo.OpaqueNetwork.Summary property +func (n OpaqueNetwork) Summary(ctx context.Context) (*types.OpaqueNetworkSummary, error) { + var props mo.OpaqueNetwork + + err := n.Properties(ctx, n.Reference(), []string{"summary"}, &props) + if err != nil { + return nil, err + } + + summary, ok := props.Summary.(*types.OpaqueNetworkSummary) + if !ok { + return nil, fmt.Errorf("%s unsupported network summary type: %T", n, props.Summary) + } + + return summary, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/option_manager.go b/vendor/github.com/vmware/govmomi/object/option_manager.go new file mode 100644 index 0000000000..7f93273aac --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/option_manager.go @@ -0,0 +1,59 @@ +/* +Copyright (c) 2016 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type OptionManager struct { + Common +} + +func NewOptionManager(c *vim25.Client, ref types.ManagedObjectReference) *OptionManager { + return &OptionManager{ + Common: NewCommon(c, ref), + } +} + +func (m OptionManager) Query(ctx context.Context, name string) ([]types.BaseOptionValue, error) { + req := types.QueryOptions{ + This: m.Reference(), + Name: name, + } + + res, err := methods.QueryOptions(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m OptionManager) Update(ctx context.Context, value []types.BaseOptionValue) error { + req := types.UpdateOptions{ + This: m.Reference(), + ChangedValue: value, + } + + _, err := methods.UpdateOptions(ctx, m.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/option_value_list.go b/vendor/github.com/vmware/govmomi/object/option_value_list.go new file mode 100644 index 0000000000..9f91253cc4 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/option_value_list.go @@ -0,0 +1,206 @@ +/* +Copyright (c) 2024-2024 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 object + +import ( + "fmt" + "reflect" + + "github.com/vmware/govmomi/vim25/types" +) + +// OptionValueList simplifies manipulation of properties that are arrays of +// types.BaseOptionValue, such as ExtraConfig. +type OptionValueList []types.BaseOptionValue + +// OptionValueListFromMap returns a new OptionValueList object from the provided +// map. +func OptionValueListFromMap[T any](in map[string]T) OptionValueList { + if len(in) == 0 { + return nil + } + var ( + i int + out = make(OptionValueList, len(in)) + ) + for k, v := range in { + out[i] = &types.OptionValue{Key: k, Value: v} + i++ + } + return out +} + +// Get returns the value if exists, otherwise nil is returned. The second return +// value is a flag indicating whether the value exists or nil was the actual +// value. +func (ov OptionValueList) Get(key string) (any, bool) { + if ov == nil { + return nil, false + } + for i := range ov { + if optVal := ov[i].GetOptionValue(); optVal != nil { + if optVal.Key == key { + return optVal.Value, true + } + } + } + return nil, false +} + +// GetString returns the value as a string if the value exists. +func (ov OptionValueList) GetString(key string) (string, bool) { + if ov == nil { + return "", false + } + for i := range ov { + if optVal := ov[i].GetOptionValue(); optVal != nil { + if optVal.Key == key { + return getOptionValueAsString(optVal.Value), true + } + } + } + return "", false +} + +// Additions returns a diff that includes only the elements from the provided +// list that do not already exist. +func (ov OptionValueList) Additions(in ...types.BaseOptionValue) OptionValueList { + return ov.diff(in, true) +} + +// Diff returns a diff that includes the elements from the provided list that do +// not already exist or have different values. +func (ov OptionValueList) Diff(in ...types.BaseOptionValue) OptionValueList { + return ov.diff(in, false) +} + +func (ov OptionValueList) diff(in OptionValueList, addOnly bool) OptionValueList { + if ov == nil && in == nil { + return nil + } + var ( + out OptionValueList + leftOptVals = ov.Map() + ) + for i := range in { + if rightOptVal := in[i].GetOptionValue(); rightOptVal != nil { + k, v := rightOptVal.Key, rightOptVal.Value + if ov == nil { + out = append(out, &types.OptionValue{Key: k, Value: v}) + } else if leftOptVal, ok := leftOptVals[k]; !ok { + out = append(out, &types.OptionValue{Key: k, Value: v}) + } else if !addOnly && v != leftOptVal { + out = append(out, &types.OptionValue{Key: k, Value: v}) + } + } + } + if len(out) == 0 { + return nil + } + return out +} + +// Join combines this list with the provided one and returns the result, joining +// the two lists on their shared keys. +// Please note, Join(left, right) means the values from right will be appended +// to left, without overwriting any values that have shared keys. To overwrite +// the shared keys in left from right, use Join(right, left) instead. +func (ov OptionValueList) Join(in ...types.BaseOptionValue) OptionValueList { + var ( + out OptionValueList + outKeys map[string]struct{} + ) + + // Init the out slice from the left side. + if len(ov) > 0 { + outKeys = map[string]struct{}{} + for i := range ov { + if optVal := ov[i].GetOptionValue(); optVal != nil { + kv := &types.OptionValue{Key: optVal.Key, Value: optVal.Value} + out = append(out, kv) + outKeys[optVal.Key] = struct{}{} + } + } + } + + // Join the values from the right side. + for i := range in { + if rightOptVal := in[i].GetOptionValue(); rightOptVal != nil { + k, v := rightOptVal.Key, rightOptVal.Value + if _, ok := outKeys[k]; !ok { + out = append(out, &types.OptionValue{Key: k, Value: v}) + } + } + } + + if len(out) == 0 { + return nil + } + + return out +} + +// Map returns the list of option values as a map. A nil value is returned if +// the list is empty. +func (ov OptionValueList) Map() map[string]any { + if len(ov) == 0 { + return nil + } + out := map[string]any{} + for i := range ov { + if optVal := ov[i].GetOptionValue(); optVal != nil { + out[optVal.Key] = optVal.Value + } + } + if len(out) == 0 { + return nil + } + return out +} + +// StringMap returns the list of option values as a map where the values are +// strings. A nil value is returned if the list is empty. +func (ov OptionValueList) StringMap() map[string]string { + if len(ov) == 0 { + return nil + } + out := map[string]string{} + for i := range ov { + if optVal := ov[i].GetOptionValue(); optVal != nil { + out[optVal.Key] = getOptionValueAsString(optVal.Value) + } + } + if len(out) == 0 { + return nil + } + return out +} + +func getOptionValueAsString(val any) string { + switch tval := val.(type) { + case string: + return tval + default: + if rv := reflect.ValueOf(val); rv.Kind() == reflect.Pointer { + if rv.IsNil() { + return "" + } + return fmt.Sprintf("%v", rv.Elem().Interface()) + } + return fmt.Sprintf("%v", tval) + } +} diff --git a/vendor/github.com/vmware/govmomi/object/resource_pool.go b/vendor/github.com/vmware/govmomi/object/resource_pool.go new file mode 100644 index 0000000000..e510006b40 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/resource_pool.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/nfc" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type ResourcePool struct { + Common +} + +func NewResourcePool(c *vim25.Client, ref types.ManagedObjectReference) *ResourcePool { + return &ResourcePool{ + Common: NewCommon(c, ref), + } +} + +// Owner returns the ResourcePool owner as a ClusterComputeResource or ComputeResource. +func (p ResourcePool) Owner(ctx context.Context) (Reference, error) { + var pool mo.ResourcePool + + err := p.Properties(ctx, p.Reference(), []string{"owner"}, &pool) + if err != nil { + return nil, err + } + + return NewReference(p.Client(), pool.Owner), nil +} + +func (p ResourcePool) ImportVApp(ctx context.Context, spec types.BaseImportSpec, folder *Folder, host *HostSystem) (*nfc.Lease, error) { + req := types.ImportVApp{ + This: p.Reference(), + Spec: spec, + } + + if folder != nil { + ref := folder.Reference() + req.Folder = &ref + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.ImportVApp(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return nfc.NewLease(p.c, res.Returnval), nil +} + +func (p ResourcePool) Create(ctx context.Context, name string, spec types.ResourceConfigSpec) (*ResourcePool, error) { + req := types.CreateResourcePool{ + This: p.Reference(), + Name: name, + Spec: spec, + } + + res, err := methods.CreateResourcePool(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewResourcePool(p.c, res.Returnval), nil +} + +func (p ResourcePool) CreateVApp(ctx context.Context, name string, resSpec types.ResourceConfigSpec, configSpec types.VAppConfigSpec, folder *Folder) (*VirtualApp, error) { + req := types.CreateVApp{ + This: p.Reference(), + Name: name, + ResSpec: resSpec, + ConfigSpec: configSpec, + } + + if folder != nil { + ref := folder.Reference() + req.VmFolder = &ref + } + + res, err := methods.CreateVApp(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewVirtualApp(p.c, res.Returnval), nil +} + +func (p ResourcePool) UpdateConfig(ctx context.Context, name string, config *types.ResourceConfigSpec) error { + req := types.UpdateConfig{ + This: p.Reference(), + Name: name, + Config: config, + } + + if config != nil && config.Entity == nil { + ref := p.Reference() + + // Create copy of config so changes won't leak back to the caller + newConfig := *config + newConfig.Entity = &ref + req.Config = &newConfig + } + + _, err := methods.UpdateConfig(ctx, p.c, &req) + return err +} + +func (p ResourcePool) DestroyChildren(ctx context.Context) error { + req := types.DestroyChildren{ + This: p.Reference(), + } + + _, err := methods.DestroyChildren(ctx, p.c, &req) + return err +} + +func (p ResourcePool) Destroy(ctx context.Context) (*Task, error) { + req := types.Destroy_Task{ + This: p.Reference(), + } + + res, err := methods.Destroy_Task(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewTask(p.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/search_index.go b/vendor/github.com/vmware/govmomi/object/search_index.go new file mode 100644 index 0000000000..288f78097c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/search_index.go @@ -0,0 +1,259 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type SearchIndex struct { + Common +} + +func NewSearchIndex(c *vim25.Client) *SearchIndex { + s := SearchIndex{ + Common: NewCommon(c, *c.ServiceContent.SearchIndex), + } + + return &s +} + +// FindByDatastorePath finds a virtual machine by its location on a datastore. +func (s SearchIndex) FindByDatastorePath(ctx context.Context, dc *Datacenter, path string) (Reference, error) { + req := types.FindByDatastorePath{ + This: s.Reference(), + Datacenter: dc.Reference(), + Path: path, + } + + res, err := methods.FindByDatastorePath(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if res.Returnval == nil { + return nil, nil + } + return NewReference(s.c, *res.Returnval), nil +} + +// FindByDnsName finds a virtual machine or host by DNS name. +func (s SearchIndex) FindByDnsName(ctx context.Context, dc *Datacenter, dnsName string, vmSearch bool) (Reference, error) { + req := types.FindByDnsName{ + This: s.Reference(), + DnsName: dnsName, + VmSearch: vmSearch, + } + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.FindByDnsName(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if res.Returnval == nil { + return nil, nil + } + return NewReference(s.c, *res.Returnval), nil +} + +// FindByInventoryPath finds a managed entity based on its location in the inventory. +func (s SearchIndex) FindByInventoryPath(ctx context.Context, path string) (Reference, error) { + req := types.FindByInventoryPath{ + This: s.Reference(), + InventoryPath: path, + } + + res, err := methods.FindByInventoryPath(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if res.Returnval == nil { + return nil, nil + } + + r := NewReference(s.c, *res.Returnval) + + type common interface { + SetInventoryPath(string) + } + + if c, ok := r.(common); ok { + c.SetInventoryPath(path) + } + + return r, nil +} + +// FindByIp finds a virtual machine or host by IP address. +func (s SearchIndex) FindByIp(ctx context.Context, dc *Datacenter, ip string, vmSearch bool) (Reference, error) { + req := types.FindByIp{ + This: s.Reference(), + Ip: ip, + VmSearch: vmSearch, + } + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.FindByIp(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if res.Returnval == nil { + return nil, nil + } + return NewReference(s.c, *res.Returnval), nil +} + +// FindByUuid finds a virtual machine or host by UUID. +func (s SearchIndex) FindByUuid(ctx context.Context, dc *Datacenter, uuid string, vmSearch bool, instanceUuid *bool) (Reference, error) { + req := types.FindByUuid{ + This: s.Reference(), + Uuid: uuid, + VmSearch: vmSearch, + InstanceUuid: instanceUuid, + } + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.FindByUuid(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if res.Returnval == nil { + return nil, nil + } + return NewReference(s.c, *res.Returnval), nil +} + +// FindChild finds a particular child based on a managed entity name. +func (s SearchIndex) FindChild(ctx context.Context, entity Reference, name string) (Reference, error) { + req := types.FindChild{ + This: s.Reference(), + Entity: entity.Reference(), + Name: name, + } + + res, err := methods.FindChild(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if res.Returnval == nil { + return nil, nil + } + return NewReference(s.c, *res.Returnval), nil +} + +// FindAllByDnsName finds all virtual machines or hosts by DNS name. +func (s SearchIndex) FindAllByDnsName(ctx context.Context, dc *Datacenter, dnsName string, vmSearch bool) ([]Reference, error) { + req := types.FindAllByDnsName{ + This: s.Reference(), + DnsName: dnsName, + VmSearch: vmSearch, + } + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.FindAllByDnsName(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if len(res.Returnval) == 0 { + return nil, nil + } + + var references []Reference + for _, returnval := range res.Returnval { + references = append(references, NewReference(s.c, returnval)) + } + return references, nil +} + +// FindAllByIp finds all virtual machines or hosts by IP address. +func (s SearchIndex) FindAllByIp(ctx context.Context, dc *Datacenter, ip string, vmSearch bool) ([]Reference, error) { + req := types.FindAllByIp{ + This: s.Reference(), + Ip: ip, + VmSearch: vmSearch, + } + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.FindAllByIp(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if len(res.Returnval) == 0 { + return nil, nil + } + + var references []Reference + for _, returnval := range res.Returnval { + references = append(references, NewReference(s.c, returnval)) + } + return references, nil +} + +// FindAllByUuid finds all virtual machines or hosts by UUID. +func (s SearchIndex) FindAllByUuid(ctx context.Context, dc *Datacenter, uuid string, vmSearch bool, instanceUuid *bool) ([]Reference, error) { + req := types.FindAllByUuid{ + This: s.Reference(), + Uuid: uuid, + VmSearch: vmSearch, + InstanceUuid: instanceUuid, + } + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.FindAllByUuid(ctx, s.c, &req) + if err != nil { + return nil, err + } + + if len(res.Returnval) == 0 { + return nil, nil + } + + var references []Reference + for _, returnval := range res.Returnval { + references = append(references, NewReference(s.c, returnval)) + } + return references, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/storage_pod.go b/vendor/github.com/vmware/govmomi/object/storage_pod.go new file mode 100644 index 0000000000..188b91a002 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/storage_pod.go @@ -0,0 +1,34 @@ +/* +Copyright (c) 2015 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 object + +import ( + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/types" +) + +type StoragePod struct { + *Folder +} + +func NewStoragePod(c *vim25.Client, ref types.ManagedObjectReference) *StoragePod { + return &StoragePod{ + Folder: &Folder{ + Common: NewCommon(c, ref), + }, + } +} diff --git a/vendor/github.com/vmware/govmomi/object/storage_resource_manager.go b/vendor/github.com/vmware/govmomi/object/storage_resource_manager.go new file mode 100644 index 0000000000..579bcd4d7e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/storage_resource_manager.go @@ -0,0 +1,179 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type StorageResourceManager struct { + Common +} + +func NewStorageResourceManager(c *vim25.Client) *StorageResourceManager { + sr := StorageResourceManager{ + Common: NewCommon(c, *c.ServiceContent.StorageResourceManager), + } + + return &sr +} + +func (sr StorageResourceManager) ApplyStorageDrsRecommendation(ctx context.Context, key []string) (*Task, error) { + req := types.ApplyStorageDrsRecommendation_Task{ + This: sr.Reference(), + Key: key, + } + + res, err := methods.ApplyStorageDrsRecommendation_Task(ctx, sr.c, &req) + if err != nil { + return nil, err + } + + return NewTask(sr.c, res.Returnval), nil +} + +func (sr StorageResourceManager) ApplyStorageDrsRecommendationToPod(ctx context.Context, pod *StoragePod, key string) (*Task, error) { + req := types.ApplyStorageDrsRecommendationToPod_Task{ + This: sr.Reference(), + Key: key, + } + + if pod != nil { + req.Pod = pod.Reference() + } + + res, err := methods.ApplyStorageDrsRecommendationToPod_Task(ctx, sr.c, &req) + if err != nil { + return nil, err + } + + return NewTask(sr.c, res.Returnval), nil +} + +func (sr StorageResourceManager) CancelStorageDrsRecommendation(ctx context.Context, key []string) error { + req := types.CancelStorageDrsRecommendation{ + This: sr.Reference(), + Key: key, + } + + _, err := methods.CancelStorageDrsRecommendation(ctx, sr.c, &req) + + return err +} + +func (sr StorageResourceManager) ConfigureDatastoreIORM(ctx context.Context, datastore *Datastore, spec types.StorageIORMConfigSpec, key string) (*Task, error) { + req := types.ConfigureDatastoreIORM_Task{ + This: sr.Reference(), + Spec: spec, + } + + if datastore != nil { + req.Datastore = datastore.Reference() + } + + res, err := methods.ConfigureDatastoreIORM_Task(ctx, sr.c, &req) + if err != nil { + return nil, err + } + + return NewTask(sr.c, res.Returnval), nil +} + +func (sr StorageResourceManager) ConfigureStorageDrsForPod(ctx context.Context, pod *StoragePod, spec types.StorageDrsConfigSpec, modify bool) (*Task, error) { + req := types.ConfigureStorageDrsForPod_Task{ + This: sr.Reference(), + Spec: spec, + Modify: modify, + } + + if pod != nil { + req.Pod = pod.Reference() + } + + res, err := methods.ConfigureStorageDrsForPod_Task(ctx, sr.c, &req) + if err != nil { + return nil, err + } + + return NewTask(sr.c, res.Returnval), nil +} + +func (sr StorageResourceManager) QueryDatastorePerformanceSummary(ctx context.Context, datastore *Datastore) ([]types.StoragePerformanceSummary, error) { + req := types.QueryDatastorePerformanceSummary{ + This: sr.Reference(), + } + + if datastore != nil { + req.Datastore = datastore.Reference() + } + + res, err := methods.QueryDatastorePerformanceSummary(ctx, sr.c, &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (sr StorageResourceManager) QueryIORMConfigOption(ctx context.Context, host *HostSystem) (*types.StorageIORMConfigOption, error) { + req := types.QueryIORMConfigOption{ + This: sr.Reference(), + } + + if host != nil { + req.Host = host.Reference() + } + + res, err := methods.QueryIORMConfigOption(ctx, sr.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +func (sr StorageResourceManager) RecommendDatastores(ctx context.Context, storageSpec types.StoragePlacementSpec) (*types.StoragePlacementResult, error) { + req := types.RecommendDatastores{ + This: sr.Reference(), + StorageSpec: storageSpec, + } + + res, err := methods.RecommendDatastores(ctx, sr.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +func (sr StorageResourceManager) RefreshStorageDrsRecommendation(ctx context.Context, pod *StoragePod) error { + req := types.RefreshStorageDrsRecommendation{ + This: sr.Reference(), + } + + if pod != nil { + req.Pod = pod.Reference() + } + + _, err := methods.RefreshStorageDrsRecommendation(ctx, sr.c, &req) + + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/task.go b/vendor/github.com/vmware/govmomi/object/task.go new file mode 100644 index 0000000000..583bcc6e01 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/task.go @@ -0,0 +1,146 @@ +/* +Copyright (c) 2015-2024 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 object + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/task" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/progress" + "github.com/vmware/govmomi/vim25/types" +) + +// Task is a convenience wrapper around task.Task that keeps a reference to +// the client that was used to create it. This allows users to call the Wait() +// function with only a context parameter, instead of a context parameter, a +// soap.RoundTripper, and reference to the root property collector. +type Task struct { + Common +} + +func NewTask(c *vim25.Client, ref types.ManagedObjectReference) *Task { + t := Task{ + Common: NewCommon(c, ref), + } + + return &t +} + +// Wait waits for a task to complete. +// NOTE: This method create a thread-safe PropertyCollector instance per-call, so it is thread safe. +// The downside of this approach is the additional resource usage on the vCenter side for each call. +func (t *Task) Wait(ctx context.Context) error { + _, err := t.WaitForResult(ctx, nil) + return err +} + +// WaitForResult wait for a task to complete. +// NOTE: This method create a thread-safe PropertyCollector instance per-call, so it is thread safe. +// The downside of this approach is the additional resource usage on the vCenter side for each call. +func (t *Task) WaitForResult(ctx context.Context, s ...progress.Sinker) (taskInfo *types.TaskInfo, result error) { + var pr progress.Sinker + if len(s) == 1 { + pr = s[0] + } + p, err := property.DefaultCollector(t.c).Create(ctx) + if err != nil { + return nil, err + } + + // Attempt to destroy the collector using the background context, as the + // specified context may have timed out or have been canceled. + defer func() { + if err := p.Destroy(context.Background()); err != nil { + if result == nil { + result = err + } else { + result = fmt.Errorf( + "destroy property collector failed with %s after failing to wait for updates: %w", + err, + result) + } + } + }() + + return task.WaitEx(ctx, t.Reference(), p, pr) +} + +// WaitEx waits for a task to complete. +// NOTE: This method use the same PropertyCollector instance in each call, thus reducing resource usage on the vCenter side. +// The downside of this approach is that this method is not thread safe. +func (t *Task) WaitEx(ctx context.Context) error { + _, err := t.WaitForResultEx(ctx, nil) + return err +} + +// WaitForResultEx waits for a task to complete. +// NOTE: This method use the same PropertyCollector instance in each call, thus reducing resource usage on the vCenter side. +// The downside of this approach is that this method is not thread safe. +func (t *Task) WaitForResultEx(ctx context.Context, s ...progress.Sinker) (*types.TaskInfo, error) { + var pr progress.Sinker + if len(s) == 1 { + pr = s[0] + } + p := property.DefaultCollector(t.c) + return task.WaitEx(ctx, t.Reference(), p, pr) +} + +func (t *Task) Cancel(ctx context.Context) error { + _, err := methods.CancelTask(ctx, t.Client(), &types.CancelTask{ + This: t.Reference(), + }) + + return err +} + +// SetState sets task state and optionally sets results or fault, as appropriate for state. +func (t *Task) SetState(ctx context.Context, state types.TaskInfoState, result types.AnyType, fault *types.LocalizedMethodFault) error { + req := types.SetTaskState{ + This: t.Reference(), + State: state, + Result: result, + Fault: fault, + } + _, err := methods.SetTaskState(ctx, t.Common.Client(), &req) + return err +} + +// SetDescription updates task description to describe the current phase of the task. +func (t *Task) SetDescription(ctx context.Context, description types.LocalizableMessage) error { + req := types.SetTaskDescription{ + This: t.Reference(), + Description: description, + } + _, err := methods.SetTaskDescription(ctx, t.Common.Client(), &req) + return err +} + +// UpdateProgress Sets percentage done for this task and recalculates overall percentage done. +// If a percentDone value of less than zero or greater than 100 is specified, +// a value of zero or 100 respectively is used. +func (t *Task) UpdateProgress(ctx context.Context, percentDone int) error { + req := types.UpdateProgress{ + This: t.Reference(), + PercentDone: int32(percentDone), + } + _, err := methods.UpdateProgress(ctx, t.Common.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/tenant_manager.go b/vendor/github.com/vmware/govmomi/object/tenant_manager.go new file mode 100644 index 0000000000..4dda196e35 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/tenant_manager.go @@ -0,0 +1,78 @@ +/* +Copyright (c) 2021 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type TenantManager struct { + Common +} + +func NewTenantManager(c *vim25.Client) *TenantManager { + t := TenantManager{ + Common: NewCommon(c, *c.ServiceContent.TenantManager), + } + + return &t +} + +func (t TenantManager) MarkServiceProviderEntities(ctx context.Context, entities []types.ManagedObjectReference) error { + req := types.MarkServiceProviderEntities{ + This: t.Reference(), + Entity: entities, + } + + _, err := methods.MarkServiceProviderEntities(ctx, t.Client(), &req) + if err != nil { + return err + } + + return nil +} + +func (t TenantManager) UnmarkServiceProviderEntities(ctx context.Context, entities []types.ManagedObjectReference) error { + req := types.UnmarkServiceProviderEntities{ + This: t.Reference(), + Entity: entities, + } + + _, err := methods.UnmarkServiceProviderEntities(ctx, t.Client(), &req) + if err != nil { + return err + } + + return nil +} + +func (t TenantManager) RetrieveServiceProviderEntities(ctx context.Context) ([]types.ManagedObjectReference, error) { + req := types.RetrieveServiceProviderEntities{ + This: t.Reference(), + } + + res, err := methods.RetrieveServiceProviderEntities(ctx, t.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/types.go b/vendor/github.com/vmware/govmomi/object/types.go new file mode 100644 index 0000000000..4eb8d1b8bb --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/types.go @@ -0,0 +1,67 @@ +/* +Copyright (c) 2015 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 object + +import ( + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/types" +) + +type Reference interface { + Reference() types.ManagedObjectReference +} + +func NewReference(c *vim25.Client, e types.ManagedObjectReference) Reference { + switch e.Type { + case "Folder": + return NewFolder(c, e) + case "StoragePod": + return &StoragePod{ + NewFolder(c, e), + } + case "Datacenter": + return NewDatacenter(c, e) + case "VirtualMachine": + return NewVirtualMachine(c, e) + case "VirtualApp": + return &VirtualApp{ + NewResourcePool(c, e), + } + case "ComputeResource": + return NewComputeResource(c, e) + case "ClusterComputeResource": + return NewClusterComputeResource(c, e) + case "HostSystem": + return NewHostSystem(c, e) + case "Network": + return NewNetwork(c, e) + case "OpaqueNetwork": + return NewOpaqueNetwork(c, e) + case "ResourcePool": + return NewResourcePool(c, e) + case "DistributedVirtualSwitch": + return NewDistributedVirtualSwitch(c, e) + case "VmwareDistributedVirtualSwitch": + return &VmwareDistributedVirtualSwitch{*NewDistributedVirtualSwitch(c, e)} + case "DistributedVirtualPortgroup": + return NewDistributedVirtualPortgroup(c, e) + case "Datastore": + return NewDatastore(c, e) + default: + panic("Unknown managed entity: " + e.Type) + } +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_app.go b/vendor/github.com/vmware/govmomi/object/virtual_app.go new file mode 100644 index 0000000000..b7311b3e39 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/virtual_app.go @@ -0,0 +1,121 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type VirtualApp struct { + *ResourcePool +} + +func NewVirtualApp(c *vim25.Client, ref types.ManagedObjectReference) *VirtualApp { + return &VirtualApp{ + ResourcePool: NewResourcePool(c, ref), + } +} + +func (p VirtualApp) CreateChildVM(ctx context.Context, config types.VirtualMachineConfigSpec, host *HostSystem) (*Task, error) { + req := types.CreateChildVM_Task{ + This: p.Reference(), + Config: config, + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.CreateChildVM_Task(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewTask(p.c, res.Returnval), nil +} + +func (p VirtualApp) UpdateConfig(ctx context.Context, spec types.VAppConfigSpec) error { + req := types.UpdateVAppConfig{ + This: p.Reference(), + Spec: spec, + } + + _, err := methods.UpdateVAppConfig(ctx, p.c, &req) + return err +} + +func (p VirtualApp) PowerOn(ctx context.Context) (*Task, error) { + req := types.PowerOnVApp_Task{ + This: p.Reference(), + } + + res, err := methods.PowerOnVApp_Task(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewTask(p.c, res.Returnval), nil +} + +func (p VirtualApp) PowerOff(ctx context.Context, force bool) (*Task, error) { + req := types.PowerOffVApp_Task{ + This: p.Reference(), + Force: force, + } + + res, err := methods.PowerOffVApp_Task(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewTask(p.c, res.Returnval), nil + +} + +func (p VirtualApp) Suspend(ctx context.Context) (*Task, error) { + req := types.SuspendVApp_Task{ + This: p.Reference(), + } + + res, err := methods.SuspendVApp_Task(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewTask(p.c, res.Returnval), nil +} + +func (p VirtualApp) Clone(ctx context.Context, name string, target types.ManagedObjectReference, spec types.VAppCloneSpec) (*Task, error) { + req := types.CloneVApp_Task{ + This: p.Reference(), + Name: name, + Target: target, + Spec: spec, + } + + res, err := methods.CloneVApp_Task(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewTask(p.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_device_list.go b/vendor/github.com/vmware/govmomi/object/virtual_device_list.go new file mode 100644 index 0000000000..92797dcdab --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/virtual_device_list.go @@ -0,0 +1,976 @@ +/* +Copyright (c) 2015-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 object + +import ( + "errors" + "fmt" + "math/rand" + "path/filepath" + "reflect" + "regexp" + "sort" + "strings" + + "github.com/vmware/govmomi/vim25/types" +) + +// Type values for use in BootOrder +const ( + DeviceTypeNone = "-" + DeviceTypeCdrom = "cdrom" + DeviceTypeDisk = "disk" + DeviceTypeEthernet = "ethernet" + DeviceTypeFloppy = "floppy" +) + +// VirtualDeviceList provides helper methods for working with a list of virtual devices. +type VirtualDeviceList []types.BaseVirtualDevice + +// SCSIControllerTypes are used for adding a new SCSI controller to a VM. +func SCSIControllerTypes() VirtualDeviceList { + // Return a mutable list of SCSI controller types, initialized with defaults. + return VirtualDeviceList([]types.BaseVirtualDevice{ + &types.VirtualLsiLogicController{}, + &types.VirtualBusLogicController{}, + &types.ParaVirtualSCSIController{}, + &types.VirtualLsiLogicSASController{}, + }).Select(func(device types.BaseVirtualDevice) bool { + c := device.(types.BaseVirtualSCSIController).GetVirtualSCSIController() + c.SharedBus = types.VirtualSCSISharingNoSharing + c.BusNumber = -1 + return true + }) +} + +// EthernetCardTypes are used for adding a new ethernet card to a VM. +func EthernetCardTypes() VirtualDeviceList { + return VirtualDeviceList([]types.BaseVirtualDevice{ + &types.VirtualE1000{}, + &types.VirtualE1000e{}, + &types.VirtualVmxnet2{}, + &types.VirtualVmxnet3{}, + &types.VirtualVmxnet3Vrdma{}, + &types.VirtualPCNet32{}, + &types.VirtualSriovEthernetCard{}, + }).Select(func(device types.BaseVirtualDevice) bool { + c := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + c.GetVirtualDevice().Key = VirtualDeviceList{}.newRandomKey() + return true + }) +} + +// Select returns a new list containing all elements of the list for which the given func returns true. +func (l VirtualDeviceList) Select(f func(device types.BaseVirtualDevice) bool) VirtualDeviceList { + var found VirtualDeviceList + + for _, device := range l { + if f(device) { + found = append(found, device) + } + } + + return found +} + +// SelectByType returns a new list with devices that are equal to or extend the given type. +func (l VirtualDeviceList) SelectByType(deviceType types.BaseVirtualDevice) VirtualDeviceList { + dtype := reflect.TypeOf(deviceType) + if dtype == nil { + return nil + } + dname := dtype.Elem().Name() + + return l.Select(func(device types.BaseVirtualDevice) bool { + t := reflect.TypeOf(device) + + if t == dtype { + return true + } + + _, ok := t.Elem().FieldByName(dname) + + return ok + }) +} + +// SelectByBackingInfo returns a new list with devices matching the given backing info. +// If the value of backing is nil, any device with a backing of the same type will be returned. +func (l VirtualDeviceList) SelectByBackingInfo(backing types.BaseVirtualDeviceBackingInfo) VirtualDeviceList { + t := reflect.TypeOf(backing) + + return l.Select(func(device types.BaseVirtualDevice) bool { + db := device.GetVirtualDevice().Backing + if db == nil { + return false + } + + if reflect.TypeOf(db) != t { + return false + } + + if reflect.ValueOf(backing).IsNil() { + // selecting by backing type + return true + } + + switch a := db.(type) { + case *types.VirtualEthernetCardNetworkBackingInfo: + b := backing.(*types.VirtualEthernetCardNetworkBackingInfo) + return a.DeviceName == b.DeviceName + case *types.VirtualEthernetCardDistributedVirtualPortBackingInfo: + b := backing.(*types.VirtualEthernetCardDistributedVirtualPortBackingInfo) + return a.Port.SwitchUuid == b.Port.SwitchUuid && + a.Port.PortgroupKey == b.Port.PortgroupKey + case *types.VirtualEthernetCardOpaqueNetworkBackingInfo: + b := backing.(*types.VirtualEthernetCardOpaqueNetworkBackingInfo) + return a.OpaqueNetworkId == b.OpaqueNetworkId + case *types.VirtualDiskFlatVer2BackingInfo: + b := backing.(*types.VirtualDiskFlatVer2BackingInfo) + if a.Parent != nil && b.Parent != nil { + return a.Parent.FileName == b.Parent.FileName + } + return a.FileName == b.FileName + case *types.VirtualSerialPortURIBackingInfo: + b := backing.(*types.VirtualSerialPortURIBackingInfo) + return a.ServiceURI == b.ServiceURI + case types.BaseVirtualDeviceFileBackingInfo: + b := backing.(types.BaseVirtualDeviceFileBackingInfo) + return a.GetVirtualDeviceFileBackingInfo().FileName == b.GetVirtualDeviceFileBackingInfo().FileName + case *types.VirtualPCIPassthroughVmiopBackingInfo: + b := backing.(*types.VirtualPCIPassthroughVmiopBackingInfo) + return a.Vgpu == b.Vgpu + case *types.VirtualPCIPassthroughDynamicBackingInfo: + b := backing.(*types.VirtualPCIPassthroughDynamicBackingInfo) + if b.CustomLabel != "" && b.CustomLabel != a.CustomLabel { + return false + } + if len(b.AllowedDevice) == 0 { + return true + } + for _, x := range a.AllowedDevice { + for _, y := range b.AllowedDevice { + if x.DeviceId == y.DeviceId && x.VendorId == y.VendorId { + return true + } + } + } + return false + default: + return false + } + }) +} + +// Find returns the device matching the given name. +func (l VirtualDeviceList) Find(name string) types.BaseVirtualDevice { + for _, device := range l { + if l.Name(device) == name { + return device + } + } + return nil +} + +// FindByKey returns the device matching the given key. +func (l VirtualDeviceList) FindByKey(key int32) types.BaseVirtualDevice { + for _, device := range l { + if device.GetVirtualDevice().Key == key { + return device + } + } + return nil +} + +// FindIDEController will find the named IDE controller if given, otherwise will pick an available controller. +// An error is returned if the named controller is not found or not an IDE controller. Or, if name is not +// given and no available controller can be found. +func (l VirtualDeviceList) FindIDEController(name string) (*types.VirtualIDEController, error) { + if name != "" { + d := l.Find(name) + if d == nil { + return nil, fmt.Errorf("device '%s' not found", name) + } + if c, ok := d.(*types.VirtualIDEController); ok { + return c, nil + } + return nil, fmt.Errorf("%s is not an IDE controller", name) + } + + c := l.PickController((*types.VirtualIDEController)(nil)) + if c == nil { + return nil, errors.New("no available IDE controller") + } + + return c.(*types.VirtualIDEController), nil +} + +// CreateIDEController creates a new IDE controller. +func (l VirtualDeviceList) CreateIDEController() (types.BaseVirtualDevice, error) { + ide := &types.VirtualIDEController{} + ide.Key = l.NewKey() + return ide, nil +} + +// FindSCSIController will find the named SCSI controller if given, otherwise will pick an available controller. +// An error is returned if the named controller is not found or not an SCSI controller. Or, if name is not +// given and no available controller can be found. +func (l VirtualDeviceList) FindSCSIController(name string) (*types.VirtualSCSIController, error) { + if name != "" { + d := l.Find(name) + if d == nil { + return nil, fmt.Errorf("device '%s' not found", name) + } + if c, ok := d.(types.BaseVirtualSCSIController); ok { + return c.GetVirtualSCSIController(), nil + } + return nil, fmt.Errorf("%s is not an SCSI controller", name) + } + + c := l.PickController((*types.VirtualSCSIController)(nil)) + if c == nil { + return nil, errors.New("no available SCSI controller") + } + + return c.(types.BaseVirtualSCSIController).GetVirtualSCSIController(), nil +} + +// CreateSCSIController creates a new SCSI controller of type name if given, otherwise defaults to lsilogic. +func (l VirtualDeviceList) CreateSCSIController(name string) (types.BaseVirtualDevice, error) { + ctypes := SCSIControllerTypes() + + if name == "" || name == "scsi" { + name = ctypes.Type(ctypes[0]) + } else if name == "virtualscsi" { + name = "pvscsi" // ovf VirtualSCSI mapping + } + + found := ctypes.Select(func(device types.BaseVirtualDevice) bool { + return l.Type(device) == name + }) + + if len(found) == 0 { + return nil, fmt.Errorf("unknown SCSI controller type '%s'", name) + } + + c, ok := found[0].(types.BaseVirtualSCSIController) + if !ok { + return nil, fmt.Errorf("invalid SCSI controller type '%s'", name) + } + + scsi := c.GetVirtualSCSIController() + scsi.BusNumber = l.newSCSIBusNumber() + scsi.Key = l.NewKey() + scsi.ScsiCtlrUnitNumber = 7 + return c.(types.BaseVirtualDevice), nil +} + +var scsiBusNumbers = []int{0, 1, 2, 3} + +// newSCSIBusNumber returns the bus number to use for adding a new SCSI bus device. +// -1 is returned if there are no bus numbers available. +func (l VirtualDeviceList) newSCSIBusNumber() int32 { + var used []int + + for _, d := range l.SelectByType((*types.VirtualSCSIController)(nil)) { + num := d.(types.BaseVirtualSCSIController).GetVirtualSCSIController().BusNumber + if num >= 0 { + used = append(used, int(num)) + } // else caller is creating a new vm using SCSIControllerTypes + } + + sort.Ints(used) + + for i, n := range scsiBusNumbers { + if i == len(used) || n != used[i] { + return int32(n) + } + } + + return -1 +} + +// FindNVMEController will find the named NVME controller if given, otherwise will pick an available controller. +// An error is returned if the named controller is not found or not an NVME controller. Or, if name is not +// given and no available controller can be found. +func (l VirtualDeviceList) FindNVMEController(name string) (*types.VirtualNVMEController, error) { + if name != "" { + d := l.Find(name) + if d == nil { + return nil, fmt.Errorf("device '%s' not found", name) + } + if c, ok := d.(*types.VirtualNVMEController); ok { + return c, nil + } + return nil, fmt.Errorf("%s is not an NVME controller", name) + } + + c := l.PickController((*types.VirtualNVMEController)(nil)) + if c == nil { + return nil, errors.New("no available NVME controller") + } + + return c.(*types.VirtualNVMEController), nil +} + +// CreateNVMEController creates a new NVMWE controller. +func (l VirtualDeviceList) CreateNVMEController() (types.BaseVirtualDevice, error) { + nvme := &types.VirtualNVMEController{} + nvme.BusNumber = l.newNVMEBusNumber() + nvme.Key = l.NewKey() + + return nvme, nil +} + +var nvmeBusNumbers = []int{0, 1, 2, 3} + +// newNVMEBusNumber returns the bus number to use for adding a new NVME bus device. +// -1 is returned if there are no bus numbers available. +func (l VirtualDeviceList) newNVMEBusNumber() int32 { + var used []int + + for _, d := range l.SelectByType((*types.VirtualNVMEController)(nil)) { + num := d.(types.BaseVirtualController).GetVirtualController().BusNumber + if num >= 0 { + used = append(used, int(num)) + } // else caller is creating a new vm using NVMEControllerTypes + } + + sort.Ints(used) + + for i, n := range nvmeBusNumbers { + if i == len(used) || n != used[i] { + return int32(n) + } + } + + return -1 +} + +// FindDiskController will find an existing ide or scsi disk controller. +func (l VirtualDeviceList) FindDiskController(name string) (types.BaseVirtualController, error) { + switch { + case name == "ide": + return l.FindIDEController("") + case name == "scsi" || name == "": + return l.FindSCSIController("") + case name == "nvme": + return l.FindNVMEController("") + default: + if c, ok := l.Find(name).(types.BaseVirtualController); ok { + return c, nil + } + return nil, fmt.Errorf("%s is not a valid controller", name) + } +} + +// PickController returns a controller of the given type(s). +// If no controllers are found or have no available slots, then nil is returned. +func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) types.BaseVirtualController { + l = l.SelectByType(kind.(types.BaseVirtualDevice)).Select(func(device types.BaseVirtualDevice) bool { + num := len(device.(types.BaseVirtualController).GetVirtualController().Device) + + switch device.(type) { + case types.BaseVirtualSCSIController: + return num < 15 + case *types.VirtualIDEController: + return num < 2 + case *types.VirtualNVMEController: + return num < 8 + default: + return true + } + }) + + if len(l) == 0 { + return nil + } + + return l[0].(types.BaseVirtualController) +} + +// newUnitNumber returns the unit number to use for attaching a new device to the given controller. +func (l VirtualDeviceList) newUnitNumber(c types.BaseVirtualController, offset int) int32 { + units := make([]bool, 30) + + for i := 0; i < offset; i++ { + units[i] = true + } + + switch sc := c.(type) { + case types.BaseVirtualSCSIController: + // The SCSI controller sits on its own bus + units[sc.GetVirtualSCSIController().ScsiCtlrUnitNumber] = true + } + + key := c.GetVirtualController().Key + + for _, device := range l { + d := device.GetVirtualDevice() + + if d.ControllerKey == key && d.UnitNumber != nil { + units[int(*d.UnitNumber)] = true + } + } + + for unit, used := range units { + if !used { + return int32(unit) + } + } + + return -1 +} + +// NewKey returns the key to use for adding a new device to the device list. +// The device list we're working with here may not be complete (e.g. when +// we're only adding new devices), so any positive keys could conflict with device keys +// that are already in use. To avoid this type of conflict, we can use negative keys +// here, which will be resolved to positive keys by vSphere as the reconfiguration is done. +func (l VirtualDeviceList) NewKey() int32 { + var key int32 = -200 + + for _, device := range l { + d := device.GetVirtualDevice() + if d.Key < key { + key = d.Key + } + } + + return key - 1 +} + +// AssignController assigns a device to a controller. +func (l VirtualDeviceList) AssignController(device types.BaseVirtualDevice, c types.BaseVirtualController) { + d := device.GetVirtualDevice() + d.ControllerKey = c.GetVirtualController().Key + d.UnitNumber = new(int32) + + offset := 0 + switch device.(type) { + case types.BaseVirtualEthernetCard: + offset = 7 + } + *d.UnitNumber = l.newUnitNumber(c, offset) + + if d.Key == 0 { + d.Key = l.newRandomKey() + } +} + +// newRandomKey returns a random negative device key. +// The generated key can be used for devices you want to add so that it does not collide with existing ones. +func (l VirtualDeviceList) newRandomKey() int32 { + // NOTE: rand.Uint32 cannot be used here because conversion from uint32 to int32 may change the sign + key := rand.Int31() * -1 + if key == 0 { + return -1 + } + + return key +} + +// CreateDisk creates a new VirtualDisk device which can be added to a VM. +func (l VirtualDeviceList) CreateDisk(c types.BaseVirtualController, ds types.ManagedObjectReference, name string) *types.VirtualDisk { + // If name is not specified, one will be chosen for you. + // But if when given, make sure it ends in .vmdk, otherwise it will be treated as a directory. + if len(name) > 0 && filepath.Ext(name) != ".vmdk" { + name += ".vmdk" + } + + device := &types.VirtualDisk{ + VirtualDevice: types.VirtualDevice{ + Backing: &types.VirtualDiskFlatVer2BackingInfo{ + DiskMode: string(types.VirtualDiskModePersistent), + ThinProvisioned: types.NewBool(true), + VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ + FileName: name, + Datastore: &ds, + }, + }, + }, + } + + l.AssignController(device, c) + return device +} + +// ChildDisk creates a new VirtualDisk device, linked to the given parent disk, which can be added to a VM. +func (l VirtualDeviceList) ChildDisk(parent *types.VirtualDisk) *types.VirtualDisk { + disk := *parent + backing := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo) + p := new(DatastorePath) + p.FromString(backing.FileName) + p.Path = "" + + // Use specified disk as parent backing to a new disk. + disk.Backing = &types.VirtualDiskFlatVer2BackingInfo{ + VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ + FileName: p.String(), + Datastore: backing.Datastore, + }, + Parent: backing, + DiskMode: backing.DiskMode, + ThinProvisioned: backing.ThinProvisioned, + } + + return &disk +} + +func (l VirtualDeviceList) connectivity(device types.BaseVirtualDevice, v bool) error { + c := device.GetVirtualDevice().Connectable + if c == nil { + return fmt.Errorf("%s is not connectable", l.Name(device)) + } + + c.Connected = v + c.StartConnected = v + + return nil +} + +// Connect changes the device to connected, returns an error if the device is not connectable. +func (l VirtualDeviceList) Connect(device types.BaseVirtualDevice) error { + return l.connectivity(device, true) +} + +// Disconnect changes the device to disconnected, returns an error if the device is not connectable. +func (l VirtualDeviceList) Disconnect(device types.BaseVirtualDevice) error { + return l.connectivity(device, false) +} + +// FindCdrom finds a cdrom device with the given name, defaulting to the first cdrom device if any. +func (l VirtualDeviceList) FindCdrom(name string) (*types.VirtualCdrom, error) { + if name != "" { + d := l.Find(name) + if d == nil { + return nil, fmt.Errorf("device '%s' not found", name) + } + if c, ok := d.(*types.VirtualCdrom); ok { + return c, nil + } + return nil, fmt.Errorf("%s is not a cdrom device", name) + } + + c := l.SelectByType((*types.VirtualCdrom)(nil)) + if len(c) == 0 { + return nil, errors.New("no cdrom device found") + } + + return c[0].(*types.VirtualCdrom), nil +} + +// CreateCdrom creates a new VirtualCdrom device which can be added to a VM. +func (l VirtualDeviceList) CreateCdrom(c *types.VirtualIDEController) (*types.VirtualCdrom, error) { + device := &types.VirtualCdrom{} + + l.AssignController(device, c) + + l.setDefaultCdromBacking(device) + + device.Connectable = &types.VirtualDeviceConnectInfo{ + AllowGuestControl: true, + Connected: true, + StartConnected: true, + } + + return device, nil +} + +// InsertIso changes the cdrom device backing to use the given iso file. +func (l VirtualDeviceList) InsertIso(device *types.VirtualCdrom, iso string) *types.VirtualCdrom { + device.Backing = &types.VirtualCdromIsoBackingInfo{ + VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ + FileName: iso, + }, + } + + return device +} + +// EjectIso removes the iso file based backing and replaces with the default cdrom backing. +func (l VirtualDeviceList) EjectIso(device *types.VirtualCdrom) *types.VirtualCdrom { + l.setDefaultCdromBacking(device) + return device +} + +func (l VirtualDeviceList) setDefaultCdromBacking(device *types.VirtualCdrom) { + device.Backing = &types.VirtualCdromAtapiBackingInfo{ + VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{ + DeviceName: fmt.Sprintf("%s-%d-%d", DeviceTypeCdrom, device.ControllerKey, device.UnitNumber), + UseAutoDetect: types.NewBool(false), + }, + } +} + +// FindFloppy finds a floppy device with the given name, defaulting to the first floppy device if any. +func (l VirtualDeviceList) FindFloppy(name string) (*types.VirtualFloppy, error) { + if name != "" { + d := l.Find(name) + if d == nil { + return nil, fmt.Errorf("device '%s' not found", name) + } + if c, ok := d.(*types.VirtualFloppy); ok { + return c, nil + } + return nil, fmt.Errorf("%s is not a floppy device", name) + } + + c := l.SelectByType((*types.VirtualFloppy)(nil)) + if len(c) == 0 { + return nil, errors.New("no floppy device found") + } + + return c[0].(*types.VirtualFloppy), nil +} + +// CreateFloppy creates a new VirtualFloppy device which can be added to a VM. +func (l VirtualDeviceList) CreateFloppy() (*types.VirtualFloppy, error) { + device := &types.VirtualFloppy{} + + c := l.PickController((*types.VirtualSIOController)(nil)) + if c == nil { + return nil, errors.New("no available SIO controller") + } + + l.AssignController(device, c) + + l.setDefaultFloppyBacking(device) + + device.Connectable = &types.VirtualDeviceConnectInfo{ + AllowGuestControl: true, + Connected: true, + StartConnected: true, + } + + return device, nil +} + +// InsertImg changes the floppy device backing to use the given img file. +func (l VirtualDeviceList) InsertImg(device *types.VirtualFloppy, img string) *types.VirtualFloppy { + device.Backing = &types.VirtualFloppyImageBackingInfo{ + VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ + FileName: img, + }, + } + + return device +} + +// EjectImg removes the img file based backing and replaces with the default floppy backing. +func (l VirtualDeviceList) EjectImg(device *types.VirtualFloppy) *types.VirtualFloppy { + l.setDefaultFloppyBacking(device) + return device +} + +func (l VirtualDeviceList) setDefaultFloppyBacking(device *types.VirtualFloppy) { + device.Backing = &types.VirtualFloppyDeviceBackingInfo{ + VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{ + DeviceName: fmt.Sprintf("%s-%d", DeviceTypeFloppy, device.UnitNumber), + UseAutoDetect: types.NewBool(false), + }, + } +} + +// FindSerialPort finds a serial port device with the given name, defaulting to the first serial port device if any. +func (l VirtualDeviceList) FindSerialPort(name string) (*types.VirtualSerialPort, error) { + if name != "" { + d := l.Find(name) + if d == nil { + return nil, fmt.Errorf("device '%s' not found", name) + } + if c, ok := d.(*types.VirtualSerialPort); ok { + return c, nil + } + return nil, fmt.Errorf("%s is not a serial port device", name) + } + + c := l.SelectByType((*types.VirtualSerialPort)(nil)) + if len(c) == 0 { + return nil, errors.New("no serial port device found") + } + + return c[0].(*types.VirtualSerialPort), nil +} + +// CreateSerialPort creates a new VirtualSerialPort device which can be added to a VM. +func (l VirtualDeviceList) CreateSerialPort() (*types.VirtualSerialPort, error) { + device := &types.VirtualSerialPort{ + YieldOnPoll: true, + } + + c := l.PickController((*types.VirtualSIOController)(nil)) + if c == nil { + return nil, errors.New("no available SIO controller") + } + + l.AssignController(device, c) + + l.setDefaultSerialPortBacking(device) + + return device, nil +} + +// ConnectSerialPort connects a serial port to a server or client uri. +func (l VirtualDeviceList) ConnectSerialPort(device *types.VirtualSerialPort, uri string, client bool, proxyuri string) *types.VirtualSerialPort { + if strings.HasPrefix(uri, "[") { + device.Backing = &types.VirtualSerialPortFileBackingInfo{ + VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ + FileName: uri, + }, + } + + return device + } + + direction := types.VirtualDeviceURIBackingOptionDirectionServer + if client { + direction = types.VirtualDeviceURIBackingOptionDirectionClient + } + + device.Backing = &types.VirtualSerialPortURIBackingInfo{ + VirtualDeviceURIBackingInfo: types.VirtualDeviceURIBackingInfo{ + Direction: string(direction), + ServiceURI: uri, + ProxyURI: proxyuri, + }, + } + + return device +} + +// DisconnectSerialPort disconnects the serial port backing. +func (l VirtualDeviceList) DisconnectSerialPort(device *types.VirtualSerialPort) *types.VirtualSerialPort { + l.setDefaultSerialPortBacking(device) + return device +} + +func (l VirtualDeviceList) setDefaultSerialPortBacking(device *types.VirtualSerialPort) { + device.Backing = &types.VirtualSerialPortURIBackingInfo{ + VirtualDeviceURIBackingInfo: types.VirtualDeviceURIBackingInfo{ + Direction: "client", + ServiceURI: "localhost:0", + }, + } +} + +// CreateEthernetCard creates a new VirtualEthernetCard of the given name name and initialized with the given backing. +func (l VirtualDeviceList) CreateEthernetCard(name string, backing types.BaseVirtualDeviceBackingInfo) (types.BaseVirtualDevice, error) { + ctypes := EthernetCardTypes() + + if name == "" { + name = ctypes.deviceName(ctypes[0]) + } + + found := ctypes.Select(func(device types.BaseVirtualDevice) bool { + return l.deviceName(device) == name + }) + + if len(found) == 0 { + return nil, fmt.Errorf("unknown ethernet card type '%s'", name) + } + + c, ok := found[0].(types.BaseVirtualEthernetCard) + if !ok { + return nil, fmt.Errorf("invalid ethernet card type '%s'", name) + } + + c.GetVirtualEthernetCard().Backing = backing + + return c.(types.BaseVirtualDevice), nil +} + +// PrimaryMacAddress returns the MacAddress field of the primary VirtualEthernetCard +func (l VirtualDeviceList) PrimaryMacAddress() string { + eth0 := l.Find("ethernet-0") + + if eth0 == nil { + return "" + } + + return eth0.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard().MacAddress +} + +// convert a BaseVirtualDevice to a BaseVirtualMachineBootOptionsBootableDevice +var bootableDevices = map[string]func(device types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice{ + DeviceTypeNone: func(types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice { + return &types.VirtualMachineBootOptionsBootableDevice{} + }, + DeviceTypeCdrom: func(types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice { + return &types.VirtualMachineBootOptionsBootableCdromDevice{} + }, + DeviceTypeDisk: func(d types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice { + return &types.VirtualMachineBootOptionsBootableDiskDevice{ + DeviceKey: d.GetVirtualDevice().Key, + } + }, + DeviceTypeEthernet: func(d types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice { + return &types.VirtualMachineBootOptionsBootableEthernetDevice{ + DeviceKey: d.GetVirtualDevice().Key, + } + }, + DeviceTypeFloppy: func(types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice { + return &types.VirtualMachineBootOptionsBootableFloppyDevice{} + }, +} + +// BootOrder returns a list of devices which can be used to set boot order via VirtualMachine.SetBootOptions. +// The order can be any of "ethernet", "cdrom", "floppy" or "disk" or by specific device name. +// A value of "-" will clear the existing boot order on the VC/ESX side. +func (l VirtualDeviceList) BootOrder(order []string) []types.BaseVirtualMachineBootOptionsBootableDevice { + var devices []types.BaseVirtualMachineBootOptionsBootableDevice + + for _, name := range order { + if kind, ok := bootableDevices[name]; ok { + if name == DeviceTypeNone { + // Not covered in the API docs, nor obvious, but this clears the boot order on the VC/ESX side. + devices = append(devices, new(types.VirtualMachineBootOptionsBootableDevice)) + continue + } + + for _, device := range l { + if l.Type(device) == name { + devices = append(devices, kind(device)) + } + } + continue + } + + if d := l.Find(name); d != nil { + if kind, ok := bootableDevices[l.Type(d)]; ok { + devices = append(devices, kind(d)) + } + } + } + + return devices +} + +// SelectBootOrder returns an ordered list of devices matching the given bootable device order +func (l VirtualDeviceList) SelectBootOrder(order []types.BaseVirtualMachineBootOptionsBootableDevice) VirtualDeviceList { + var devices VirtualDeviceList + + for _, bd := range order { + for _, device := range l { + if kind, ok := bootableDevices[l.Type(device)]; ok { + if reflect.DeepEqual(kind(device), bd) { + devices = append(devices, device) + } + } + } + } + + return devices +} + +// TypeName returns the vmodl type name of the device +func (l VirtualDeviceList) TypeName(device types.BaseVirtualDevice) string { + dtype := reflect.TypeOf(device) + if dtype == nil { + return "" + } + return dtype.Elem().Name() +} + +var deviceNameRegexp = regexp.MustCompile(`(?:Virtual)?(?:Machine)?(\w+?)(?:Card|EthernetCard|Device|Controller)?$`) + +func (l VirtualDeviceList) deviceName(device types.BaseVirtualDevice) string { + name := "device" + typeName := l.TypeName(device) + + m := deviceNameRegexp.FindStringSubmatch(typeName) + if len(m) == 2 { + name = strings.ToLower(m[1]) + } + + return name +} + +// Type returns a human-readable name for the given device +func (l VirtualDeviceList) Type(device types.BaseVirtualDevice) string { + switch device.(type) { + case types.BaseVirtualEthernetCard: + return DeviceTypeEthernet + case *types.ParaVirtualSCSIController: + return "pvscsi" + case *types.VirtualLsiLogicSASController: + return "lsilogic-sas" + case *types.VirtualNVMEController: + return "nvme" + case *types.VirtualPrecisionClock: + return "clock" + default: + return l.deviceName(device) + } +} + +// Name returns a stable, human-readable name for the given device +func (l VirtualDeviceList) Name(device types.BaseVirtualDevice) string { + var key string + var UnitNumber int32 + d := device.GetVirtualDevice() + if d.UnitNumber != nil { + UnitNumber = *d.UnitNumber + } + + dtype := l.Type(device) + switch dtype { + case DeviceTypeEthernet: + // Ethernet devices of UnitNumber 7-19 are non-SRIOV. Ethernet devices of + // UnitNumber 45-36 descending are SRIOV + if UnitNumber <= 45 && UnitNumber >= 36 { + key = fmt.Sprintf("sriov-%d", 45-UnitNumber) + } else { + key = fmt.Sprintf("%d", UnitNumber-7) + } + case DeviceTypeDisk: + key = fmt.Sprintf("%d-%d", d.ControllerKey, UnitNumber) + default: + key = fmt.Sprintf("%d", d.Key) + } + + return fmt.Sprintf("%s-%s", dtype, key) +} + +// ConfigSpec creates a virtual machine configuration spec for +// the specified operation, for the list of devices in the device list. +func (l VirtualDeviceList) ConfigSpec(op types.VirtualDeviceConfigSpecOperation) ([]types.BaseVirtualDeviceConfigSpec, error) { + var fop types.VirtualDeviceConfigSpecFileOperation + switch op { + case types.VirtualDeviceConfigSpecOperationAdd: + fop = types.VirtualDeviceConfigSpecFileOperationCreate + case types.VirtualDeviceConfigSpecOperationEdit: + fop = types.VirtualDeviceConfigSpecFileOperationReplace + case types.VirtualDeviceConfigSpecOperationRemove: + fop = types.VirtualDeviceConfigSpecFileOperationDestroy + default: + panic("unknown op") + } + + var res []types.BaseVirtualDeviceConfigSpec + for _, device := range l { + config := &types.VirtualDeviceConfigSpec{ + Device: device, + Operation: op, + FileOperation: diskFileOperation(op, fop, device), + } + + res = append(res, config) + } + + return res, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go new file mode 100644 index 0000000000..72439caf9c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go @@ -0,0 +1,227 @@ +/* +Copyright (c) 2015 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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type VirtualDiskManager struct { + Common +} + +func NewVirtualDiskManager(c *vim25.Client) *VirtualDiskManager { + m := VirtualDiskManager{ + Common: NewCommon(c, *c.ServiceContent.VirtualDiskManager), + } + + return &m +} + +// CopyVirtualDisk copies a virtual disk, performing conversions as specified in the spec. +func (m VirtualDiskManager) CopyVirtualDisk( + ctx context.Context, + sourceName string, sourceDatacenter *Datacenter, + destName string, destDatacenter *Datacenter, + destSpec *types.VirtualDiskSpec, force bool) (*Task, error) { + + req := types.CopyVirtualDisk_Task{ + This: m.Reference(), + SourceName: sourceName, + DestName: destName, + DestSpec: destSpec, + Force: types.NewBool(force), + } + + if sourceDatacenter != nil { + ref := sourceDatacenter.Reference() + req.SourceDatacenter = &ref + } + + if destDatacenter != nil { + ref := destDatacenter.Reference() + req.DestDatacenter = &ref + } + + res, err := methods.CopyVirtualDisk_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return NewTask(m.c, res.Returnval), nil +} + +// CreateVirtualDisk creates a new virtual disk. +func (m VirtualDiskManager) CreateVirtualDisk( + ctx context.Context, + name string, datacenter *Datacenter, + spec types.BaseVirtualDiskSpec) (*Task, error) { + + req := types.CreateVirtualDisk_Task{ + This: m.Reference(), + Name: name, + Spec: spec, + } + + if datacenter != nil { + ref := datacenter.Reference() + req.Datacenter = &ref + } + + res, err := methods.CreateVirtualDisk_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return NewTask(m.c, res.Returnval), nil +} + +// MoveVirtualDisk moves a virtual disk. +func (m VirtualDiskManager) MoveVirtualDisk( + ctx context.Context, + sourceName string, sourceDatacenter *Datacenter, + destName string, destDatacenter *Datacenter, + force bool) (*Task, error) { + req := types.MoveVirtualDisk_Task{ + This: m.Reference(), + SourceName: sourceName, + DestName: destName, + Force: types.NewBool(force), + } + + if sourceDatacenter != nil { + ref := sourceDatacenter.Reference() + req.SourceDatacenter = &ref + } + + if destDatacenter != nil { + ref := destDatacenter.Reference() + req.DestDatacenter = &ref + } + + res, err := methods.MoveVirtualDisk_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return NewTask(m.c, res.Returnval), nil +} + +// DeleteVirtualDisk deletes a virtual disk. +func (m VirtualDiskManager) DeleteVirtualDisk(ctx context.Context, name string, dc *Datacenter) (*Task, error) { + req := types.DeleteVirtualDisk_Task{ + This: m.Reference(), + Name: name, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.DeleteVirtualDisk_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return NewTask(m.c, res.Returnval), nil +} + +// InflateVirtualDisk inflates a virtual disk. +func (m VirtualDiskManager) InflateVirtualDisk(ctx context.Context, name string, dc *Datacenter) (*Task, error) { + req := types.InflateVirtualDisk_Task{ + This: m.Reference(), + Name: name, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.InflateVirtualDisk_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return NewTask(m.c, res.Returnval), nil +} + +// ShrinkVirtualDisk shrinks a virtual disk. +func (m VirtualDiskManager) ShrinkVirtualDisk(ctx context.Context, name string, dc *Datacenter, copy *bool) (*Task, error) { + req := types.ShrinkVirtualDisk_Task{ + This: m.Reference(), + Name: name, + Copy: copy, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.ShrinkVirtualDisk_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return NewTask(m.c, res.Returnval), nil +} + +// Queries virtual disk uuid +func (m VirtualDiskManager) QueryVirtualDiskUuid(ctx context.Context, name string, dc *Datacenter) (string, error) { + req := types.QueryVirtualDiskUuid{ + This: m.Reference(), + Name: name, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.QueryVirtualDiskUuid(ctx, m.c, &req) + if err != nil { + return "", err + } + + if res == nil { + return "", nil + } + + 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 +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_disk_manager_internal.go b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager_internal.go new file mode 100644 index 0000000000..faa9ecad5c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager_internal.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 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 object + +import ( + "context" + "reflect" + + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +func init() { + types.Add("ArrayOfVirtualDiskInfo", reflect.TypeOf((*arrayOfVirtualDiskInfo)(nil)).Elem()) + + types.Add("VirtualDiskInfo", reflect.TypeOf((*VirtualDiskInfo)(nil)).Elem()) +} + +type arrayOfVirtualDiskInfo struct { + VirtualDiskInfo []VirtualDiskInfo `xml:"VirtualDiskInfo,omitempty"` +} + +type queryVirtualDiskInfoTaskRequest struct { + This types.ManagedObjectReference `xml:"_this"` + Name string `xml:"name"` + Datacenter *types.ManagedObjectReference `xml:"datacenter,omitempty"` + IncludeParents bool `xml:"includeParents"` +} + +type queryVirtualDiskInfoTaskResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type queryVirtualDiskInfoTaskBody struct { + Req *queryVirtualDiskInfoTaskRequest `xml:"urn:internalvim25 QueryVirtualDiskInfo_Task,omitempty"` + Res *queryVirtualDiskInfoTaskResponse `xml:"urn:vim25 QueryVirtualDiskInfo_TaskResponse,omitempty"` + InternalRes *queryVirtualDiskInfoTaskResponse `xml:"urn:internalvim25 QueryVirtualDiskInfo_TaskResponse,omitempty"` + Err *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *queryVirtualDiskInfoTaskBody) Fault() *soap.Fault { return b.Err } + +func queryVirtualDiskInfoTask(ctx context.Context, r soap.RoundTripper, req *queryVirtualDiskInfoTaskRequest) (*queryVirtualDiskInfoTaskResponse, error) { + var reqBody, resBody queryVirtualDiskInfoTaskBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + if resBody.Res != nil { + return resBody.Res, nil + } + + return resBody.InternalRes, nil +} + +type VirtualDiskInfo struct { + Name string `xml:"unit>name"` + DiskType string `xml:"diskType"` + Parent string `xml:"parent,omitempty"` +} + +func (m VirtualDiskManager) QueryVirtualDiskInfo(ctx context.Context, name string, dc *Datacenter, includeParents bool) ([]VirtualDiskInfo, error) { + req := queryVirtualDiskInfoTaskRequest{ + This: m.Reference(), + Name: name, + IncludeParents: includeParents, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := queryVirtualDiskInfoTask(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + info, err := NewTask(m.Client(), res.Returnval).WaitForResult(ctx, nil) + if err != nil { + return nil, err + } + + return info.Result.(arrayOfVirtualDiskInfo).VirtualDiskInfo, nil +} + +type createChildDiskTaskRequest struct { + This types.ManagedObjectReference `xml:"_this"` + ChildName string `xml:"childName"` + ChildDatacenter *types.ManagedObjectReference `xml:"childDatacenter,omitempty"` + ParentName string `xml:"parentName"` + ParentDatacenter *types.ManagedObjectReference `xml:"parentDatacenter,omitempty"` + IsLinkedClone bool `xml:"isLinkedClone"` +} + +type createChildDiskTaskResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type createChildDiskTaskBody struct { + Req *createChildDiskTaskRequest `xml:"urn:internalvim25 CreateChildDisk_Task,omitempty"` + Res *createChildDiskTaskResponse `xml:"urn:vim25 CreateChildDisk_TaskResponse,omitempty"` + InternalRes *createChildDiskTaskResponse `xml:"urn:internalvim25 CreateChildDisk_TaskResponse,omitempty"` + Err *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *createChildDiskTaskBody) Fault() *soap.Fault { return b.Err } + +func createChildDiskTask(ctx context.Context, r soap.RoundTripper, req *createChildDiskTaskRequest) (*createChildDiskTaskResponse, error) { + var reqBody, resBody createChildDiskTaskBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + if resBody.Res != nil { + return resBody.Res, nil // vim-version <= 6.5 + } + + return resBody.InternalRes, nil // vim-version >= 6.7 +} + +func (m VirtualDiskManager) CreateChildDisk(ctx context.Context, parent string, pdc *Datacenter, name string, dc *Datacenter, linked bool) (*Task, error) { + req := createChildDiskTaskRequest{ + This: m.Reference(), + ChildName: name, + ParentName: parent, + IsLinkedClone: linked, + } + + if dc != nil { + ref := dc.Reference() + req.ChildDatacenter = &ref + } + + if pdc != nil { + ref := pdc.Reference() + req.ParentDatacenter = &ref + } + + res, err := createChildDiskTask(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(m.Client(), res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_machine.go b/vendor/github.com/vmware/govmomi/object/virtual_machine.go new file mode 100644 index 0000000000..4665fcb744 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/virtual_machine.go @@ -0,0 +1,1081 @@ +/* +Copyright (c) 2015-2023 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 object + +import ( + "context" + "errors" + "fmt" + "net" + "path" + "strings" + + "github.com/vmware/govmomi/nfc" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +const ( + PropRuntimePowerState = "summary.runtime.powerState" + PropConfigTemplate = "summary.config.template" +) + +type VirtualMachine struct { + Common +} + +// extractDiskLayoutFiles is a helper function used to extract file keys for +// all disk files attached to the virtual machine at the current point of +// running. +func extractDiskLayoutFiles(diskLayoutList []types.VirtualMachineFileLayoutExDiskLayout) []int { + var result []int + + for _, layoutExDisk := range diskLayoutList { + for _, link := range layoutExDisk.Chain { + for i := range link.FileKey { // diskDescriptor, diskExtent pairs + result = append(result, int(link.FileKey[i])) + } + } + } + + return result +} + +// removeKey is a helper function for removing a specific file key from a list +// of keys associated with disks attached to a virtual machine. +func removeKey(l *[]int, key int) { + for i, k := range *l { + if k == key { + *l = append((*l)[:i], (*l)[i+1:]...) + break + } + } +} + +func NewVirtualMachine(c *vim25.Client, ref types.ManagedObjectReference) *VirtualMachine { + return &VirtualMachine{ + Common: NewCommon(c, ref), + } +} + +func (v VirtualMachine) PowerState(ctx context.Context) (types.VirtualMachinePowerState, error) { + var o mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{PropRuntimePowerState}, &o) + if err != nil { + return "", err + } + + return o.Summary.Runtime.PowerState, nil +} + +func (v VirtualMachine) IsTemplate(ctx context.Context) (bool, error) { + var o mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{PropConfigTemplate}, &o) + if err != nil { + return false, err + } + + return o.Summary.Config.Template, nil +} + +func (v VirtualMachine) PowerOn(ctx context.Context) (*Task, error) { + req := types.PowerOnVM_Task{ + This: v.Reference(), + } + + res, err := methods.PowerOnVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) PowerOff(ctx context.Context) (*Task, error) { + req := types.PowerOffVM_Task{ + This: v.Reference(), + } + + res, err := methods.PowerOffVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) PutUsbScanCodes(ctx context.Context, spec types.UsbScanCodeSpec) (int32, error) { + req := types.PutUsbScanCodes{ + This: v.Reference(), + Spec: spec, + } + + res, err := methods.PutUsbScanCodes(ctx, v.c, &req) + if err != nil { + return 0, err + } + + return res.Returnval, nil +} + +func (v VirtualMachine) Reset(ctx context.Context) (*Task, error) { + req := types.ResetVM_Task{ + This: v.Reference(), + } + + res, err := methods.ResetVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) Suspend(ctx context.Context) (*Task, error) { + req := types.SuspendVM_Task{ + This: v.Reference(), + } + + res, err := methods.SuspendVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) ShutdownGuest(ctx context.Context) error { + req := types.ShutdownGuest{ + This: v.Reference(), + } + + _, err := methods.ShutdownGuest(ctx, v.c, &req) + return err +} + +func (v VirtualMachine) StandbyGuest(ctx context.Context) error { + req := types.StandbyGuest{ + This: v.Reference(), + } + + _, err := methods.StandbyGuest(ctx, v.c, &req) + return err +} + +func (v VirtualMachine) RebootGuest(ctx context.Context) error { + req := types.RebootGuest{ + This: v.Reference(), + } + + _, err := methods.RebootGuest(ctx, v.c, &req) + return err +} + +func (v VirtualMachine) Destroy(ctx context.Context) (*Task, error) { + req := types.Destroy_Task{ + This: v.Reference(), + } + + res, err := methods.Destroy_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) Clone(ctx context.Context, folder *Folder, name string, config types.VirtualMachineCloneSpec) (*Task, error) { + req := types.CloneVM_Task{ + This: v.Reference(), + Folder: folder.Reference(), + Name: name, + Spec: config, + } + + res, err := methods.CloneVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) InstantClone(ctx context.Context, config types.VirtualMachineInstantCloneSpec) (*Task, error) { + req := types.InstantClone_Task{ + This: v.Reference(), + Spec: config, + } + + res, err := methods.InstantClone_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) Customize(ctx context.Context, spec types.CustomizationSpec) (*Task, error) { + req := types.CustomizeVM_Task{ + This: v.Reference(), + Spec: spec, + } + + res, err := methods.CustomizeVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) Relocate(ctx context.Context, config types.VirtualMachineRelocateSpec, priority types.VirtualMachineMovePriority) (*Task, error) { + req := types.RelocateVM_Task{ + This: v.Reference(), + Spec: config, + Priority: priority, + } + + res, err := methods.RelocateVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) Reconfigure(ctx context.Context, config types.VirtualMachineConfigSpec) (*Task, error) { + req := types.ReconfigVM_Task{ + This: v.Reference(), + Spec: config, + } + + res, err := methods.ReconfigVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) RefreshStorageInfo(ctx context.Context) error { + req := types.RefreshStorageInfo{ + This: v.Reference(), + } + + _, err := methods.RefreshStorageInfo(ctx, v.c, &req) + return err +} + +// WaitForIP waits for the VM guest.ipAddress property to report an IP address. +// Waits for an IPv4 address if the v4 param is true. +func (v VirtualMachine) WaitForIP(ctx context.Context, v4 ...bool) (string, error) { + var ip string + + p := property.DefaultCollector(v.c) + err := property.Wait(ctx, p, v.Reference(), []string{"guest.ipAddress"}, func(pc []types.PropertyChange) bool { + for _, c := range pc { + if c.Name != "guest.ipAddress" { + continue + } + if c.Op != types.PropertyChangeOpAssign { + continue + } + if c.Val == nil { + continue + } + + ip = c.Val.(string) + if len(v4) == 1 && v4[0] { + if net.ParseIP(ip).To4() == nil { + return false + } + } + return true + } + + return false + }) + + if err != nil { + return "", err + } + + return ip, nil +} + +// WaitForNetIP waits for the VM guest.net property to report an IP address for all VM NICs. +// Only consider IPv4 addresses if the v4 param is true. +// By default, wait for all NICs to get an IP address, unless 1 or more device is given. +// A device can be specified by the MAC address or the device name, e.g. "ethernet-0". +// Returns a map with MAC address as the key and IP address list as the value. +func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool, device ...string) (map[string][]string, error) { + macs := make(map[string][]string) + eths := make(map[string]string) + + p := property.DefaultCollector(v.c) + + // Wait for all NICs to have a MacAddress, which may not be generated yet. + err := property.Wait(ctx, p, v.Reference(), []string{"config.hardware.device"}, func(pc []types.PropertyChange) bool { + for _, c := range pc { + if c.Op != types.PropertyChangeOpAssign { + continue + } + + devices := VirtualDeviceList(c.Val.(types.ArrayOfVirtualDevice).VirtualDevice) + for _, d := range devices { + if nic, ok := d.(types.BaseVirtualEthernetCard); ok { + // Convert to lower so that e.g. 00:50:56:83:3A:5D is treated the + // same as 00:50:56:83:3a:5d + mac := strings.ToLower(nic.GetVirtualEthernetCard().MacAddress) + if mac == "" { + return false + } + macs[mac] = nil + eths[devices.Name(d)] = mac + } + } + } + + return true + }) + + if err != nil { + return nil, err + } + + if len(device) != 0 { + // Only wait for specific NIC(s) + macs = make(map[string][]string) + for _, mac := range device { + if eth, ok := eths[mac]; ok { + mac = eth // device name, e.g. "ethernet-0" + } + macs[mac] = nil + } + } + + err = property.Wait(ctx, p, v.Reference(), []string{"guest.net"}, func(pc []types.PropertyChange) bool { + for _, c := range pc { + if c.Op != types.PropertyChangeOpAssign { + continue + } + + nics := c.Val.(types.ArrayOfGuestNicInfo).GuestNicInfo + for _, nic := range nics { + // Convert to lower so that e.g. 00:50:56:83:3A:5D is treated the + // same as 00:50:56:83:3a:5d + mac := strings.ToLower(nic.MacAddress) + if mac == "" || nic.IpConfig == nil { + continue + } + + for _, ip := range nic.IpConfig.IpAddress { + if _, ok := macs[mac]; !ok { + continue // Ignore any that don't correspond to a VM device + } + if v4 && net.ParseIP(ip.IpAddress).To4() == nil { + continue // Ignore non IPv4 address + } + macs[mac] = append(macs[mac], ip.IpAddress) + } + } + } + + for _, ips := range macs { + if len(ips) == 0 { + return false + } + } + + return true + }) + + if err != nil { + return nil, err + } + + return macs, nil +} + +// Device returns the VirtualMachine's config.hardware.device property. +func (v VirtualMachine) Device(ctx context.Context) (VirtualDeviceList, error) { + var o mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"config.hardware.device", "summary.runtime.connectionState"}, &o) + if err != nil { + return nil, err + } + + // Quoting the SDK doc: + // The virtual machine configuration is not guaranteed to be available. + // For example, the configuration information would be unavailable if the server + // is unable to access the virtual machine files on disk, and is often also unavailable + // during the initial phases of virtual machine creation. + if o.Config == nil { + return nil, fmt.Errorf("%s Config is not available, connectionState=%s", + v.Reference(), o.Summary.Runtime.ConnectionState) + } + + return VirtualDeviceList(o.Config.Hardware.Device), nil +} + +func (v VirtualMachine) EnvironmentBrowser(ctx context.Context) (*EnvironmentBrowser, error) { + var vm mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"environmentBrowser"}, &vm) + if err != nil { + return nil, err + } + + return NewEnvironmentBrowser(v.c, vm.EnvironmentBrowser), nil +} + +func (v VirtualMachine) HostSystem(ctx context.Context) (*HostSystem, error) { + var o mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"summary.runtime.host"}, &o) + if err != nil { + return nil, err + } + + host := o.Summary.Runtime.Host + if host == nil { + return nil, errors.New("VM doesn't have a HostSystem") + } + + return NewHostSystem(v.c, *host), nil +} + +func (v VirtualMachine) ResourcePool(ctx context.Context) (*ResourcePool, error) { + var o mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"resourcePool"}, &o) + if err != nil { + return nil, err + } + + rp := o.ResourcePool + if rp == nil { + return nil, errors.New("VM doesn't have a resourcePool") + } + + return NewResourcePool(v.c, *rp), nil +} + +func diskFileOperation(op types.VirtualDeviceConfigSpecOperation, fop types.VirtualDeviceConfigSpecFileOperation, device types.BaseVirtualDevice) types.VirtualDeviceConfigSpecFileOperation { + if disk, ok := device.(*types.VirtualDisk); ok { + // Special case to attach an existing disk + if op == types.VirtualDeviceConfigSpecOperationAdd && disk.CapacityInKB == 0 && disk.CapacityInBytes == 0 { + childDisk := false + if b, ok := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo); ok { + childDisk = b.Parent != nil + } + + if !childDisk { + fop = "" // existing disk + } + } + return fop + } + + return "" +} + +func (v VirtualMachine) configureDevice(ctx context.Context, op types.VirtualDeviceConfigSpecOperation, fop types.VirtualDeviceConfigSpecFileOperation, devices ...types.BaseVirtualDevice) error { + spec := types.VirtualMachineConfigSpec{} + + for _, device := range devices { + config := &types.VirtualDeviceConfigSpec{ + Device: device, + Operation: op, + FileOperation: diskFileOperation(op, fop, device), + } + + spec.DeviceChange = append(spec.DeviceChange, config) + } + + task, err := v.Reconfigure(ctx, spec) + if err != nil { + return err + } + + return task.Wait(ctx) +} + +// AddDevice adds the given devices to the VirtualMachine +func (v VirtualMachine) AddDevice(ctx context.Context, device ...types.BaseVirtualDevice) error { + return v.configureDevice(ctx, types.VirtualDeviceConfigSpecOperationAdd, types.VirtualDeviceConfigSpecFileOperationCreate, device...) +} + +// EditDevice edits the given (existing) devices on the VirtualMachine +func (v VirtualMachine) EditDevice(ctx context.Context, device ...types.BaseVirtualDevice) error { + return v.configureDevice(ctx, types.VirtualDeviceConfigSpecOperationEdit, types.VirtualDeviceConfigSpecFileOperationReplace, device...) +} + +// RemoveDevice removes the given devices on the VirtualMachine +func (v VirtualMachine) RemoveDevice(ctx context.Context, keepFiles bool, device ...types.BaseVirtualDevice) error { + fop := types.VirtualDeviceConfigSpecFileOperationDestroy + if keepFiles { + fop = "" + } + return v.configureDevice(ctx, types.VirtualDeviceConfigSpecOperationRemove, fop, device...) +} + +// AttachDisk attaches the given disk to the VirtualMachine +func (v VirtualMachine) AttachDisk(ctx context.Context, id string, datastore *Datastore, controllerKey int32, unitNumber int32) error { + req := types.AttachDisk_Task{ + This: v.Reference(), + DiskId: types.ID{Id: id}, + Datastore: datastore.Reference(), + ControllerKey: controllerKey, + UnitNumber: &unitNumber, + } + + res, err := methods.AttachDisk_Task(ctx, v.c, &req) + if err != nil { + return err + } + + task := NewTask(v.c, res.Returnval) + return task.Wait(ctx) +} + +// DetachDisk detaches the given disk from the VirtualMachine +func (v VirtualMachine) DetachDisk(ctx context.Context, id string) error { + req := types.DetachDisk_Task{ + This: v.Reference(), + DiskId: types.ID{Id: id}, + } + + res, err := methods.DetachDisk_Task(ctx, v.c, &req) + if err != nil { + return err + } + + task := NewTask(v.c, res.Returnval) + return task.Wait(ctx) +} + +// BootOptions returns the VirtualMachine's config.bootOptions property. +func (v VirtualMachine) BootOptions(ctx context.Context) (*types.VirtualMachineBootOptions, error) { + var o mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"config.bootOptions"}, &o) + if err != nil { + return nil, err + } + + return o.Config.BootOptions, nil +} + +// SetBootOptions reconfigures the VirtualMachine with the given options. +func (v VirtualMachine) SetBootOptions(ctx context.Context, options *types.VirtualMachineBootOptions) error { + spec := types.VirtualMachineConfigSpec{} + + spec.BootOptions = options + + task, err := v.Reconfigure(ctx, spec) + if err != nil { + return err + } + + return task.Wait(ctx) +} + +// Answer answers a pending question. +func (v VirtualMachine) Answer(ctx context.Context, id, answer string) error { + req := types.AnswerVM{ + This: v.Reference(), + QuestionId: id, + AnswerChoice: answer, + } + + _, err := methods.AnswerVM(ctx, v.c, &req) + if err != nil { + return err + } + + return nil +} + +func (v VirtualMachine) AcquireTicket(ctx context.Context, kind string) (*types.VirtualMachineTicket, error) { + req := types.AcquireTicket{ + This: v.Reference(), + TicketType: kind, + } + + res, err := methods.AcquireTicket(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +// CreateSnapshot creates a new snapshot of a virtual machine. +func (v VirtualMachine) CreateSnapshot(ctx context.Context, name string, description string, memory bool, quiesce bool) (*Task, error) { + req := types.CreateSnapshot_Task{ + This: v.Reference(), + Name: name, + Description: description, + Memory: memory, + Quiesce: quiesce, + } + + res, err := methods.CreateSnapshot_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +// RemoveAllSnapshot removes all snapshots of a virtual machine +func (v VirtualMachine) RemoveAllSnapshot(ctx context.Context, consolidate *bool) (*Task, error) { + req := types.RemoveAllSnapshots_Task{ + This: v.Reference(), + Consolidate: consolidate, + } + + res, err := methods.RemoveAllSnapshots_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +type snapshotMap map[string][]types.ManagedObjectReference + +func (m snapshotMap) add(parent string, tree []types.VirtualMachineSnapshotTree) { + for i, st := range tree { + sname := st.Name + names := []string{sname, st.Snapshot.Value} + + if parent != "" { + sname = path.Join(parent, sname) + // Add full path as an option to resolve duplicate names + names = append(names, sname) + } + + for _, name := range names { + m[name] = append(m[name], tree[i].Snapshot) + } + + m.add(sname, st.ChildSnapshotList) + } +} + +// SnapshotSize calculates the size of a given snapshot in bytes. If the +// snapshot is current, disk files not associated with any parent snapshot are +// included in size calculations. This allows for measuring and including the +// growth from the last fixed snapshot to the present state. +func SnapshotSize(info types.ManagedObjectReference, parent *types.ManagedObjectReference, vmlayout *types.VirtualMachineFileLayoutEx, isCurrent bool) int { + var fileKeyList []int + var parentFiles []int + var allSnapshotFiles []int + + diskFiles := extractDiskLayoutFiles(vmlayout.Disk) + + for _, layout := range vmlayout.Snapshot { + diskLayout := extractDiskLayoutFiles(layout.Disk) + allSnapshotFiles = append(allSnapshotFiles, diskLayout...) + + if layout.Key.Value == info.Value { + fileKeyList = append(fileKeyList, int(layout.DataKey)) // The .vmsn file + fileKeyList = append(fileKeyList, diskLayout...) // The .vmdk files + } else if parent != nil && layout.Key.Value == parent.Value { + parentFiles = append(parentFiles, diskLayout...) + } + } + + for _, parentFile := range parentFiles { + removeKey(&fileKeyList, parentFile) + } + + for _, file := range allSnapshotFiles { + removeKey(&diskFiles, file) + } + + fileKeyMap := make(map[int]types.VirtualMachineFileLayoutExFileInfo) + for _, file := range vmlayout.File { + fileKeyMap[int(file.Key)] = file + } + + size := 0 + + for _, fileKey := range fileKeyList { + file := fileKeyMap[fileKey] + if parent != nil || + (file.Type != string(types.VirtualMachineFileLayoutExFileTypeDiskDescriptor) && + file.Type != string(types.VirtualMachineFileLayoutExFileTypeDiskExtent)) { + size += int(file.Size) + } + } + + if isCurrent { + for _, diskFile := range diskFiles { + file := fileKeyMap[diskFile] + size += int(file.Size) + } + } + + return size +} + +// FindSnapshot supports snapshot lookup by name, where name can be: +// 1) snapshot ManagedObjectReference.Value (unique) +// 2) snapshot name (may not be unique) +// 3) snapshot tree path (may not be unique) +func (v VirtualMachine) FindSnapshot(ctx context.Context, name string) (*types.ManagedObjectReference, error) { + var o mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"snapshot"}, &o) + if err != nil { + return nil, err + } + + if o.Snapshot == nil || len(o.Snapshot.RootSnapshotList) == 0 { + return nil, errors.New("no snapshots for this VM") + } + + m := make(snapshotMap) + m.add("", o.Snapshot.RootSnapshotList) + + s := m[name] + switch len(s) { + case 0: + return nil, fmt.Errorf("snapshot %q not found", name) + case 1: + return &s[0], nil + default: + return nil, fmt.Errorf("%q resolves to %d snapshots", name, len(s)) + } +} + +// RemoveSnapshot removes a named snapshot +func (v VirtualMachine) RemoveSnapshot(ctx context.Context, name string, removeChildren bool, consolidate *bool) (*Task, error) { + snapshot, err := v.FindSnapshot(ctx, name) + if err != nil { + return nil, err + } + + req := types.RemoveSnapshot_Task{ + This: snapshot.Reference(), + RemoveChildren: removeChildren, + Consolidate: consolidate, + } + + res, err := methods.RemoveSnapshot_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +// RevertToCurrentSnapshot reverts to the current snapshot +func (v VirtualMachine) RevertToCurrentSnapshot(ctx context.Context, suppressPowerOn bool) (*Task, error) { + req := types.RevertToCurrentSnapshot_Task{ + This: v.Reference(), + SuppressPowerOn: types.NewBool(suppressPowerOn), + } + + res, err := methods.RevertToCurrentSnapshot_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +// RevertToSnapshot reverts to a named snapshot +func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppressPowerOn bool) (*Task, error) { + snapshot, err := v.FindSnapshot(ctx, name) + if err != nil { + return nil, err + } + + req := types.RevertToSnapshot_Task{ + This: snapshot.Reference(), + SuppressPowerOn: types.NewBool(suppressPowerOn), + } + + res, err := methods.RevertToSnapshot_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +// IsToolsRunning returns true if VMware Tools is currently running in the guest OS, and false otherwise. +func (v VirtualMachine) IsToolsRunning(ctx context.Context) (bool, error) { + var o mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"guest.toolsRunningStatus"}, &o) + if err != nil { + return false, err + } + + return o.Guest.ToolsRunningStatus == string(types.VirtualMachineToolsRunningStatusGuestToolsRunning), nil +} + +// Wait for the VirtualMachine to change to the desired power state. +func (v VirtualMachine) WaitForPowerState(ctx context.Context, state types.VirtualMachinePowerState) error { + p := property.DefaultCollector(v.c) + err := property.Wait(ctx, p, v.Reference(), []string{PropRuntimePowerState}, func(pc []types.PropertyChange) bool { + for _, c := range pc { + if c.Name != PropRuntimePowerState { + continue + } + if c.Val == nil { + continue + } + + ps := c.Val.(types.VirtualMachinePowerState) + if ps == state { + return true + } + } + return false + }) + + return err +} + +func (v VirtualMachine) MarkAsTemplate(ctx context.Context) error { + req := types.MarkAsTemplate{ + This: v.Reference(), + } + + _, err := methods.MarkAsTemplate(ctx, v.c, &req) + if err != nil { + return err + } + + return nil +} + +func (v VirtualMachine) MarkAsVirtualMachine(ctx context.Context, pool ResourcePool, host *HostSystem) error { + req := types.MarkAsVirtualMachine{ + This: v.Reference(), + Pool: pool.Reference(), + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + _, err := methods.MarkAsVirtualMachine(ctx, v.c, &req) + if err != nil { + return err + } + + return nil +} + +func (v VirtualMachine) Migrate(ctx context.Context, pool *ResourcePool, host *HostSystem, priority types.VirtualMachineMovePriority, state types.VirtualMachinePowerState) (*Task, error) { + req := types.MigrateVM_Task{ + This: v.Reference(), + Priority: priority, + State: state, + } + + if pool != nil { + ref := pool.Reference() + req.Pool = &ref + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.MigrateVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) Unregister(ctx context.Context) error { + req := types.UnregisterVM{ + This: v.Reference(), + } + + _, err := methods.UnregisterVM(ctx, v.Client(), &req) + return err +} + +func (v VirtualMachine) MountToolsInstaller(ctx context.Context) error { + req := types.MountToolsInstaller{ + This: v.Reference(), + } + + _, err := methods.MountToolsInstaller(ctx, v.Client(), &req) + return err +} + +func (v VirtualMachine) UnmountToolsInstaller(ctx context.Context) error { + req := types.UnmountToolsInstaller{ + This: v.Reference(), + } + + _, err := methods.UnmountToolsInstaller(ctx, v.Client(), &req) + return err +} + +func (v VirtualMachine) UpgradeTools(ctx context.Context, options string) (*Task, error) { + req := types.UpgradeTools_Task{ + This: v.Reference(), + InstallerOptions: options, + } + + res, err := methods.UpgradeTools_Task(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) Export(ctx context.Context) (*nfc.Lease, error) { + req := types.ExportVm{ + This: v.Reference(), + } + + res, err := methods.ExportVm(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return nfc.NewLease(v.c, res.Returnval), nil +} + +func (v VirtualMachine) UpgradeVM(ctx context.Context, version string) (*Task, error) { + req := types.UpgradeVM_Task{ + This: v.Reference(), + Version: version, + } + + res, err := methods.UpgradeVM_Task(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + 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 "" + } + if o.Config != nil { + return o.Config.Uuid + } + return "" +} + +func (v VirtualMachine) QueryChangedDiskAreas(ctx context.Context, baseSnapshot, curSnapshot *types.ManagedObjectReference, disk *types.VirtualDisk, offset int64) (types.DiskChangeInfo, error) { + var noChange types.DiskChangeInfo + var err error + + if offset > disk.CapacityInBytes { + return noChange, fmt.Errorf("offset is greater than the disk size (%#x and %#x)", offset, disk.CapacityInBytes) + } else if offset == disk.CapacityInBytes { + return types.DiskChangeInfo{StartOffset: offset, Length: 0}, nil + } + + var b mo.VirtualMachineSnapshot + err = v.Properties(ctx, baseSnapshot.Reference(), []string{"config.hardware"}, &b) + if err != nil { + return noChange, fmt.Errorf("failed to fetch config.hardware of snapshot %s: %s", baseSnapshot, err) + } + + var changeId *string + for _, vd := range b.Config.Hardware.Device { + d := vd.GetVirtualDevice() + if d.Key != disk.Key { + continue + } + + // As per VDDK programming guide, these are the four types of disks + // that support CBT, see "Gathering Changed Block Information". + if b, ok := d.Backing.(*types.VirtualDiskFlatVer2BackingInfo); ok { + changeId = &b.ChangeId + break + } + if b, ok := d.Backing.(*types.VirtualDiskSparseVer2BackingInfo); ok { + changeId = &b.ChangeId + break + } + if b, ok := d.Backing.(*types.VirtualDiskRawDiskMappingVer1BackingInfo); ok { + changeId = &b.ChangeId + break + } + if b, ok := d.Backing.(*types.VirtualDiskRawDiskVer2BackingInfo); ok { + changeId = &b.ChangeId + break + } + + return noChange, fmt.Errorf("disk %d has backing info without .ChangeId: %t", disk.Key, d.Backing) + } + if changeId == nil || *changeId == "" { + return noChange, fmt.Errorf("CBT is not enabled on disk %d", disk.Key) + } + + req := types.QueryChangedDiskAreas{ + This: v.Reference(), + Snapshot: curSnapshot, + DeviceKey: disk.Key, + StartOffset: offset, + ChangeId: *changeId, + } + + res, err := methods.QueryChangedDiskAreas(ctx, v.Client(), &req) + if err != nil { + return noChange, err + } + + return res.Returnval, nil +} + +// ExportSnapshot exports all VMDK-files up to (but not including) a specified snapshot. This +// is useful when exporting a running VM. +func (v *VirtualMachine) ExportSnapshot(ctx context.Context, snapshot *types.ManagedObjectReference) (*nfc.Lease, error) { + req := types.ExportSnapshot{ + This: *snapshot, + } + resp, err := methods.ExportSnapshot(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + return nfc.NewLease(v.c, resp.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/vmware_distributed_virtual_switch.go b/vendor/github.com/vmware/govmomi/object/vmware_distributed_virtual_switch.go new file mode 100644 index 0000000000..8eccba19b1 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/vmware_distributed_virtual_switch.go @@ -0,0 +1,25 @@ +/* +Copyright (c) 2015 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 object + +type VmwareDistributedVirtualSwitch struct { + DistributedVirtualSwitch +} + +func (s VmwareDistributedVirtualSwitch) GetInventoryPath() string { + return s.InventoryPath +} diff --git a/vendor/github.com/vmware/govmomi/performance/manager.go b/vendor/github.com/vmware/govmomi/performance/manager.go new file mode 100644 index 0000000000..94b9c79514 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/performance/manager.go @@ -0,0 +1,487 @@ +/* +Copyright (c) 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 performance + +import ( + "context" + "fmt" + "sort" + "strconv" + "strings" + "sync" + "time" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +var ( + // Intervals maps name to seconds for the built-in historical intervals + Intervals = map[string]int32{ + "real": 0, // 0 == default 20s interval + "day": 300, + "week": 1800, + "month": 7200, + "year": 86400, + } +) + +// Manager wraps mo.PerformanceManager. +type Manager struct { + object.Common + + Sort bool + + pm struct { + sync.Mutex + *mo.PerformanceManager + } + + infoByName struct { + sync.Mutex + m map[string]*types.PerfCounterInfo + } + + infoByKey struct { + sync.Mutex + m map[int32]*types.PerfCounterInfo + } +} + +// NewManager creates a new Manager instance. +func NewManager(client *vim25.Client) *Manager { + m := Manager{ + Common: object.NewCommon(client, *client.ServiceContent.PerfManager), + } + + m.pm.PerformanceManager = new(mo.PerformanceManager) + + return &m +} + +// IntervalList wraps []types.PerfInterval. +type IntervalList []types.PerfInterval + +// Enabled returns a map with Level as the key and enabled PerfInterval.Name(s) as the value. +func (l IntervalList) Enabled() map[int32][]string { + enabled := make(map[int32][]string) + + for level := int32(0); level <= 4; level++ { + var names []string + + for _, interval := range l { + if interval.Enabled && interval.Level >= level { + names = append(names, interval.Name) + } + } + + enabled[level] = names + } + + return enabled +} + +// HistoricalInterval gets the PerformanceManager.HistoricalInterval property and wraps as an IntervalList. +func (m *Manager) HistoricalInterval(ctx context.Context) (IntervalList, error) { + var pm mo.PerformanceManager + + err := m.Properties(ctx, m.Reference(), []string{"historicalInterval"}, &pm) + if err != nil { + return nil, err + } + + return IntervalList(pm.HistoricalInterval), nil +} + +// CounterInfo gets the PerformanceManager.PerfCounter property. +// The property value is only collected once, subsequent calls return the cached value. +func (m *Manager) CounterInfo(ctx context.Context) ([]types.PerfCounterInfo, error) { + m.pm.Lock() + defer m.pm.Unlock() + + if len(m.pm.PerfCounter) == 0 { + err := m.Properties(ctx, m.Reference(), []string{"perfCounter"}, m.pm.PerformanceManager) + if err != nil { + return nil, err + } + } + + return m.pm.PerfCounter, nil +} + +// CounterInfoByName converts the PerformanceManager.PerfCounter property to a map, +// where key is types.PerfCounterInfo.Name(). +func (m *Manager) CounterInfoByName(ctx context.Context) (map[string]*types.PerfCounterInfo, error) { + m.infoByName.Lock() + defer m.infoByName.Unlock() + + if m.infoByName.m != nil { + return m.infoByName.m, nil + } + + info, err := m.CounterInfo(ctx) + if err != nil { + return nil, err + } + + m.infoByName.m = make(map[string]*types.PerfCounterInfo) + + for i := range info { + c := &info[i] + + m.infoByName.m[c.Name()] = c + } + + return m.infoByName.m, nil +} + +// CounterInfoByKey converts the PerformanceManager.PerfCounter property to a map, +// where key is types.PerfCounterInfo.Key. +func (m *Manager) CounterInfoByKey(ctx context.Context) (map[int32]*types.PerfCounterInfo, error) { + m.infoByKey.Lock() + defer m.infoByKey.Unlock() + + if m.infoByKey.m != nil { + return m.infoByKey.m, nil + } + + info, err := m.CounterInfo(ctx) + if err != nil { + return nil, err + } + + m.infoByKey.m = make(map[int32]*types.PerfCounterInfo) + + for i := range info { + c := &info[i] + + m.infoByKey.m[c.Key] = c + } + + return m.infoByKey.m, nil +} + +// ProviderSummary wraps the QueryPerfProviderSummary method, caching the value based on entity.Type. +func (m *Manager) ProviderSummary(ctx context.Context, entity types.ManagedObjectReference) (*types.PerfProviderSummary, error) { + req := types.QueryPerfProviderSummary{ + This: m.Reference(), + Entity: entity, + } + + res, err := methods.QueryPerfProviderSummary(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +type groupPerfCounterInfo struct { + info map[int32]*types.PerfCounterInfo + ids []types.PerfMetricId +} + +func (d groupPerfCounterInfo) Len() int { + return len(d.ids) +} + +func (d groupPerfCounterInfo) Less(i, j int) bool { + ci := d.ids[i].CounterId + cj := d.ids[j].CounterId + + giKey := "-" + gjKey := "-" + + if gi, ok := d.info[ci]; ok { + giKey = gi.GroupInfo.GetElementDescription().Key + } + if gj, ok := d.info[cj]; ok { + gjKey = gj.GroupInfo.GetElementDescription().Key + } + + return giKey < gjKey +} + +func (d groupPerfCounterInfo) Swap(i, j int) { + d.ids[i], d.ids[j] = d.ids[j], d.ids[i] +} + +// MetricList wraps []types.PerfMetricId +type MetricList []types.PerfMetricId + +// ByKey converts MetricList to map, where key is types.PerfMetricId.CounterId / types.PerfCounterInfo.Key +func (l MetricList) ByKey() map[int32][]*types.PerfMetricId { + ids := make(map[int32][]*types.PerfMetricId, len(l)) + + for i := range l { + id := &l[i] + ids[id.CounterId] = append(ids[id.CounterId], id) + } + + return ids +} + +// AvailableMetric wraps the QueryAvailablePerfMetric method. +// The MetricList is sorted by PerfCounterInfo.GroupInfo.Key if Manager.Sort == true. +func (m *Manager) AvailableMetric(ctx context.Context, entity types.ManagedObjectReference, interval int32) (MetricList, error) { + req := types.QueryAvailablePerfMetric{ + This: m.Reference(), + Entity: entity.Reference(), + IntervalId: interval, + } + + res, err := methods.QueryAvailablePerfMetric(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + if m.Sort { + info, err := m.CounterInfoByKey(ctx) + if err != nil { + return nil, err + } + + sort.Sort(groupPerfCounterInfo{info, res.Returnval}) + } + + return MetricList(res.Returnval), nil +} + +// Query wraps the QueryPerf method. +func (m *Manager) Query(ctx context.Context, spec []types.PerfQuerySpec) ([]types.BasePerfEntityMetricBase, error) { + req := types.QueryPerf{ + This: m.Reference(), + QuerySpec: spec, + } + + res, err := methods.QueryPerf(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +// QueryCounter wraps the QueryPerfCounter method. +func (m *Manager) QueryCounter(ctx context.Context, ids []int32) ([]types.PerfCounterInfo, error) { + req := types.QueryPerfCounter{ + This: m.Reference(), + CounterId: ids, + } + + res, err := methods.QueryPerfCounter(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +// SampleByName uses the spec param as a template, constructing a []types.PerfQuerySpec for the given metrics and entities +// and invoking the Query method. +// The spec template can specify instances using the MetricId.Instance field, by default all instances are collected. +// The spec template MaxSample defaults to 1. +// If the spec template IntervalId is a historical interval and StartTime is not specified, +// the StartTime is set to the current time - (IntervalId * MaxSample). +func (m *Manager) SampleByName(ctx context.Context, spec types.PerfQuerySpec, metrics []string, entity []types.ManagedObjectReference) ([]types.BasePerfEntityMetricBase, error) { + info, err := m.CounterInfoByName(ctx) + if err != nil { + return nil, err + } + + var ids []types.PerfMetricId + + instances := spec.MetricId + if len(instances) == 0 { + // Default to all instances + instances = []types.PerfMetricId{{Instance: "*"}} + } + + for _, name := range metrics { + counter, ok := info[name] + if !ok { + return nil, fmt.Errorf("counter %q not found", name) + } + + for _, i := range instances { + ids = append(ids, types.PerfMetricId{CounterId: counter.Key, Instance: i.Instance}) + } + } + + spec.MetricId = ids + + if spec.MaxSample == 0 { + spec.MaxSample = 1 + } + + truncate := false + + if spec.IntervalId >= 60 && spec.StartTime == nil { + truncate = true + // Need a StartTime to make use of history + now, err := methods.GetCurrentTime(ctx, m.Client()) + if err != nil { + return nil, err + } + + // Go back in time + x := spec.IntervalId * -1 * (spec.MaxSample * 2) + t := now.Add(time.Duration(x) * time.Second) + spec.StartTime = &t + } + + var query []types.PerfQuerySpec + + for _, e := range entity { + spec.Entity = e.Reference() + query = append(query, spec) + } + + series, err := m.Query(ctx, query) + if err != nil { + return nil, err + } + + if truncate { + // Going back in time with IntervalId * MaxSample isn't always far enough, + // depending on when the historical data is saved in vCenter. + // So we go back twice as far and truncate here if needed. + for i := range series { + s, ok := series[i].(*types.PerfEntityMetric) + if !ok { + break + } + + n := len(s.SampleInfo) + diff := n - int(spec.MaxSample) + if diff > 0 { + s.SampleInfo = s.SampleInfo[diff:] + } + + for j := range s.Value { + v, ok := s.Value[j].(*types.PerfMetricIntSeries) + if !ok { + break + } + + n = len(v.Value) + diff = n - int(spec.MaxSample) + if diff > 0 { + v.Value = v.Value[diff:] + } + } + } + } + + return series, nil +} + +// MetricSeries contains the same data as types.PerfMetricIntSeries, but with the CounterId converted to Name. +type MetricSeries struct { + Name string `json:"name"` + unit string + Instance string `json:"instance"` + Value []int64 `json:"value"` +} + +func (s *MetricSeries) Format(val int64) string { + switch types.PerformanceManagerUnit(s.unit) { + case types.PerformanceManagerUnitPercent: + return strconv.FormatFloat(float64(val)/100.0, 'f', 2, 64) + default: + return strconv.FormatInt(val, 10) + } +} + +// ValueCSV converts the Value field to a CSV string +func (s *MetricSeries) ValueCSV() string { + vals := make([]string, len(s.Value)) + + for i := range s.Value { + vals[i] = s.Format(s.Value[i]) + } + + return strings.Join(vals, ",") +} + +// EntityMetric contains the same data as types.PerfEntityMetric, but with MetricSeries type for the Value field. +type EntityMetric struct { + Entity types.ManagedObjectReference `json:"entity"` + + SampleInfo []types.PerfSampleInfo `json:"sampleInfo"` + Value []MetricSeries `json:"value"` +} + +// SampleInfoCSV converts the SampleInfo field to a CSV string +func (m *EntityMetric) SampleInfoCSV() string { + vals := make([]string, len(m.SampleInfo)*2) + + i := 0 + + for _, s := range m.SampleInfo { + vals[i] = s.Timestamp.Format(time.RFC3339) + i++ + vals[i] = strconv.Itoa(int(s.Interval)) + i++ + } + + return strings.Join(vals, ",") +} + +// ToMetricSeries converts []BasePerfEntityMetricBase to []EntityMetric +func (m *Manager) ToMetricSeries(ctx context.Context, series []types.BasePerfEntityMetricBase) ([]EntityMetric, error) { + counters, err := m.CounterInfoByKey(ctx) + if err != nil { + return nil, err + } + + var result []EntityMetric + + for i := range series { + var values []MetricSeries + s, ok := series[i].(*types.PerfEntityMetric) + if !ok { + panic(fmt.Errorf("expected type %T, got: %T", s, series[i])) + } + + for j := range s.Value { + v := s.Value[j].(*types.PerfMetricIntSeries) + info, ok := counters[v.Id.CounterId] + if !ok { + continue + } + + values = append(values, MetricSeries{ + Name: info.Name(), + unit: info.UnitInfo.GetElementDescription().Key, + Instance: v.Id.Instance, + Value: v.Value, + }) + } + + result = append(result, EntityMetric{ + Entity: s.Entity, + SampleInfo: s.SampleInfo, + Value: values, + }) + } + + return result, nil +} diff --git a/vendor/github.com/vmware/govmomi/program.mk b/vendor/github.com/vmware/govmomi/program.mk new file mode 100644 index 0000000000..f24939934f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/program.mk @@ -0,0 +1,51 @@ +# Copyright (c) 2021 VMware, Inc. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +ifneq (,$(strip $(GOOS))) +ifeq (,$(strip $(GOARCH))) +GOARCH := $(shell go env | grep GOARCH | awk -F= '{print $$2}' | tr -d '"') +endif +endif + +ifneq (,$(strip $(GOARCH))) +ifeq (,$(strip $(GOOS))) +GOOS := $(shell go env | grep GOOS | awk -F= '{print $$2}' | tr -d '"') +endif +endif + +ifeq (2,$(words $(GOOS) $(GOARCH))) +PROGRAM := $(PROGRAM)_$(GOOS)_$(GOARCH) +endif + +ifeq (windows,$(GOOS)) +PROGRAM := $(PROGRAM).exe +endif + +all: $(PROGRAM) + +TAGS += netgo +ifeq (,$(strip $(findstring -w,$(LDFLAGS)))) +LDFLAGS += -w +endif +BUILD_ARGS := -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -v + +$(PROGRAM): + CGO_ENABLED=0 go build -a $(BUILD_ARGS) -o $@ + +install: + CGO_ENABLED=0 go install -v $(BUILD_ARGS) + +ifneq (,$(strip $(BUILD_OS))) +ifneq (,$(strip $(BUILD_ARCH))) +GOOS_GOARCH_TARGETS := $(foreach a,$(BUILD_ARCH),$(patsubst %,%_$a,$(BUILD_OS))) +XBUILD := $(addprefix $(PROGRAM)_,$(GOOS_GOARCH_TARGETS)) +$(XBUILD): + GOOS=$(word 2,$(subst _, ,$@)) GOARCH=$(word 3,$(subst _, ,$@)) $(MAKE) --output-sync=target +build-all: $(XBUILD) +endif +endif + +clean: + @rm -f $(PROGRAM) $(XBUILD) + +.PHONY: build-all install clean diff --git a/vendor/github.com/vmware/govmomi/property/collector.go b/vendor/github.com/vmware/govmomi/property/collector.go new file mode 100644 index 0000000000..263621a06a --- /dev/null +++ b/vendor/github.com/vmware/govmomi/property/collector.go @@ -0,0 +1,331 @@ +/* +Copyright (c) 2015-2024 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 property + +import ( + "context" + "errors" + "fmt" + "sync" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// ErrConcurrentCollector is returned from WaitForUpdates, WaitForUpdatesEx, +// or CheckForUpdates if any of those calls are unable to obtain an exclusive +// lock for the property collector. +var ErrConcurrentCollector = fmt.Errorf( + "only one goroutine may invoke WaitForUpdates, WaitForUpdatesEx, " + + "or CheckForUpdates on a given PropertyCollector") + +// Collector models the PropertyCollector managed object. +// +// For more information, see: +// http://pubs.vmware.com/vsphere-60/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvmodl.query.PropertyCollector.html +type Collector struct { + mu sync.Mutex + roundTripper soap.RoundTripper + reference types.ManagedObjectReference +} + +// DefaultCollector returns the session's default property collector. +func DefaultCollector(c *vim25.Client) *Collector { + p := Collector{ + roundTripper: c, + reference: c.ServiceContent.PropertyCollector, + } + + return &p +} + +func (p *Collector) Reference() types.ManagedObjectReference { + return p.reference +} + +// Create creates a new session-specific Collector that can be used to +// retrieve property updates independent of any other Collector. +func (p *Collector) Create(ctx context.Context) (*Collector, error) { + req := types.CreatePropertyCollector{ + This: p.Reference(), + } + + res, err := methods.CreatePropertyCollector(ctx, p.roundTripper, &req) + if err != nil { + return nil, err + } + + newp := Collector{ + roundTripper: p.roundTripper, + reference: res.Returnval, + } + + return &newp, nil +} + +// Destroy destroys this Collector. +func (p *Collector) Destroy(ctx context.Context) error { + req := types.DestroyPropertyCollector{ + This: p.Reference(), + } + + _, err := methods.DestroyPropertyCollector(ctx, p.roundTripper, &req) + if err != nil { + return err + } + + p.reference = types.ManagedObjectReference{} + return nil +} + +func (p *Collector) CreateFilter(ctx context.Context, req types.CreateFilter) (*Filter, error) { + req.This = p.Reference() + + resp, err := methods.CreateFilter(ctx, p.roundTripper, &req) + if err != nil { + return nil, err + } + + return &Filter{roundTripper: p.roundTripper, reference: resp.Returnval}, nil +} + +// Deprecated: Please use WaitForUpdatesEx instead. +func (p *Collector) WaitForUpdates( + ctx context.Context, + version string, + opts ...*types.WaitOptions) (*types.UpdateSet, error) { + + if !p.mu.TryLock() { + return nil, ErrConcurrentCollector + } + defer p.mu.Unlock() + + req := types.WaitForUpdatesEx{ + This: p.Reference(), + Version: version, + } + + if len(opts) == 1 { + req.Options = opts[0] + } else if len(opts) > 1 { + panic("only one option may be specified") + } + + res, err := methods.WaitForUpdatesEx(ctx, p.roundTripper, &req) + if err != nil { + return nil, err + } + + 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 +} + +// RetrieveProperties wraps RetrievePropertiesEx and ContinueRetrievePropertiesEx to collect properties in batches. +func (p *Collector) RetrieveProperties( + ctx context.Context, + req types.RetrieveProperties, + maxObjectsArgs ...int32) (*types.RetrievePropertiesResponse, error) { + + var opts types.RetrieveOptions + if l := len(maxObjectsArgs); l > 1 { + return nil, fmt.Errorf("maxObjectsArgs accepts a single value") + } else if l == 1 { + opts.MaxObjects = maxObjectsArgs[0] + } + + objects, err := mo.RetrievePropertiesEx(ctx, p.roundTripper, types.RetrievePropertiesEx{ + This: p.Reference(), + SpecSet: req.SpecSet, + Options: opts, + }) + if err != nil { + return nil, err + } + + return &types.RetrievePropertiesResponse{Returnval: objects}, nil +} + +// Retrieve loads properties for a slice of managed objects. The dst argument +// must be a pointer to a []interface{}, which is populated with the instances +// of the specified managed objects, with the relevant properties filled in. If +// the properties slice is nil, all properties are loaded. +// Note that pointer types are optional fields that may be left as a nil value. +// The caller should check such fields for a nil value before dereferencing. +func (p *Collector) Retrieve(ctx context.Context, objs []types.ManagedObjectReference, ps []string, dst interface{}) error { + if len(objs) == 0 { + return errors.New("object references is empty") + } + + kinds := make(map[string]bool) + + var propSet []types.PropertySpec + var objectSet []types.ObjectSpec + + for _, obj := range objs { + if _, ok := kinds[obj.Type]; !ok { + spec := types.PropertySpec{ + Type: obj.Type, + } + if len(ps) == 0 { + spec.All = types.NewBool(true) + } else { + spec.PathSet = ps + } + propSet = append(propSet, spec) + kinds[obj.Type] = true + } + + objectSpec := types.ObjectSpec{ + Obj: obj, + Skip: types.NewBool(false), + } + + objectSet = append(objectSet, objectSpec) + } + + req := types.RetrieveProperties{ + SpecSet: []types.PropertyFilterSpec{ + { + ObjectSet: objectSet, + PropSet: propSet, + }, + }, + } + + res, err := p.RetrieveProperties(ctx, req) + if err != nil { + return err + } + + if d, ok := dst.(*[]types.ObjectContent); ok { + *d = res.Returnval + return nil + } + + return mo.LoadObjectContent(res.Returnval, dst) +} + +// RetrieveWithFilter populates dst as Retrieve does, but only for entities +// that match the specified filter. +func (p *Collector) RetrieveWithFilter( + ctx context.Context, + objs []types.ManagedObjectReference, + ps []string, + dst interface{}, + filter Match) error { + + if len(filter) == 0 { + return p.Retrieve(ctx, objs, ps, dst) + } + + var content []types.ObjectContent + + err := p.Retrieve(ctx, objs, filter.Keys(), &content) + if err != nil { + return err + } + + objs = filter.ObjectContent(content) + + if len(objs) == 0 { + return nil + } + + return p.Retrieve(ctx, objs, ps, dst) +} + +// RetrieveOne calls Retrieve with a single managed object reference via Collector.Retrieve(). +func (p *Collector) RetrieveOne(ctx context.Context, obj types.ManagedObjectReference, ps []string, dst interface{}) error { + var objs = []types.ManagedObjectReference{obj} + return p.Retrieve(ctx, objs, ps, dst) +} + +// WaitForUpdatesEx waits for any of the specified properties of the specified +// managed object to change. It calls the specified function for every update it +// receives. If this function returns false, it continues waiting for +// subsequent updates. If this function returns true, it stops waiting and +// returns. +// +// If the Context is canceled, a call to CancelWaitForUpdates() is made and its +// error value is returned. +// +// By default, ObjectUpdate.MissingSet faults are not propagated to the returned +// error, set WaitFilter.PropagateMissing=true to enable MissingSet fault +// propagation. +func (p *Collector) WaitForUpdatesEx( + ctx context.Context, + opts WaitOptions, + onUpdatesFn func([]types.ObjectUpdate) bool) error { + + if !p.mu.TryLock() { + return ErrConcurrentCollector + } + defer p.mu.Unlock() + + req := types.WaitForUpdatesEx{ + This: p.Reference(), + Options: opts.Options, + } + + for { + res, err := methods.WaitForUpdatesEx(ctx, p.roundTripper, &req) + if err != nil { + if ctx.Err() == context.Canceled { + return p.CancelWaitForUpdates(context.Background()) + } + return err + } + + 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 + } + + req.Version = set.Version + opts.Truncated = false + if set.Truncated != nil { + opts.Truncated = *set.Truncated + } + + for _, fs := range set.FilterSet { + if opts.PropagateMissing { + for i := range fs.ObjectSet { + for _, p := range fs.ObjectSet[i].MissingSet { + // Same behavior as mo.ObjectContentToType() + return soap.WrapVimFault(p.Fault.Fault) + } + } + } + + if onUpdatesFn(fs.ObjectSet) { + return nil + } + } + } +} diff --git a/vendor/github.com/vmware/govmomi/property/filter.go b/vendor/github.com/vmware/govmomi/property/filter.go new file mode 100644 index 0000000000..40cd718fad --- /dev/null +++ b/vendor/github.com/vmware/govmomi/property/filter.go @@ -0,0 +1,54 @@ +/* +Copyright (c) 2017-2024 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 property + +import ( + "context" + + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// Filter models the Filter managed object. +// +// For more information, see: +// https://vdc-download.vmware.com/vmwb-repository/dcr-public/184bb3ba-6fa8-4574-a767-d0c96e2a38f4/ba9422ef-405c-47dd-8553-e11b619185b2/SDK/vsphere-ws/docs/ReferenceGuide/vmodl.query.PropertyCollector.Filter.html. +type Filter struct { + roundTripper soap.RoundTripper + reference types.ManagedObjectReference +} + +func (f Filter) Reference() types.ManagedObjectReference { + return f.reference +} + +// Destroy destroys this filter. +// +// This operation can be called explicitly, or it can take place implicitly when +// the session that created the filter is closed. +func (f *Filter) Destroy(ctx context.Context) error { + if _, err := methods.DestroyPropertyFilter( + ctx, + f.roundTripper, + &types.DestroyPropertyFilter{This: f.Reference()}); err != nil { + + return err + } + f.reference = types.ManagedObjectReference{} + return nil +} diff --git a/vendor/github.com/vmware/govmomi/property/match.go b/vendor/github.com/vmware/govmomi/property/match.go new file mode 100644 index 0000000000..f3922296b9 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/property/match.go @@ -0,0 +1,170 @@ +/* +Copyright (c) 2017-2024 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 property + +import ( + "fmt" + "path" + "reflect" + "strconv" + "strings" + + "github.com/vmware/govmomi/vim25/types" +) + +// Match provides methods for matching against types.DynamicProperty +type Match map[string]types.AnyType + +// Keys returns the Match map keys as a []string +func (m Match) Keys() []string { + keys := make([]string, 0, len(m)) + + for key := range m { + keys = append(keys, key) + } + + return keys +} + +// Property returns true if an entry matches the given prop. +func (m Match) Property(prop types.DynamicProperty) bool { + if prop.Val == nil { + return false + } + match, ok := m[prop.Name] + if !ok { + return false + } + + if match == prop.Val { + return true + } + + ptype := reflect.TypeOf(prop.Val) + + if strings.HasPrefix(ptype.Name(), "ArrayOf") { + pval := reflect.ValueOf(prop.Val).Field(0) + + for i := 0; i < pval.Len(); i++ { + prop.Val = pval.Index(i).Interface() + + if m.Property(prop) { + return true + } + } + + return false + } + + if reflect.TypeOf(match) != ptype { + s, ok := match.(string) + if !ok { + return false + } + + // convert if we can + switch val := prop.Val.(type) { + case bool: + match, _ = strconv.ParseBool(s) + case int16: + x, _ := strconv.ParseInt(s, 10, 16) + match = int16(x) + case int32: + x, _ := strconv.ParseInt(s, 10, 32) + match = int32(x) + case int64: + match, _ = strconv.ParseInt(s, 10, 64) + case float32: + x, _ := strconv.ParseFloat(s, 32) + match = float32(x) + case float64: + match, _ = strconv.ParseFloat(s, 64) + case fmt.Stringer: + prop.Val = val.String() + case *types.CustomFieldStringValue: + prop.Val = fmt.Sprintf("%d:%s", val.Key, val.Value) + default: + if ptype.Kind() != reflect.String { + return false + } + // An enum type we can convert to a string type + prop.Val = reflect.ValueOf(prop.Val).String() + } + } + + switch pval := prop.Val.(type) { + case string: + s := match.(string) + if s == "*" { + return true // TODO: path.Match fails if s contains a '/' + } + m, _ := path.Match(s, pval) + return m + default: + return reflect.DeepEqual(match, pval) + } +} + +// List returns true if all given props match. +func (m Match) List(props []types.DynamicProperty) bool { + for _, p := range props { + if !m.Property(p) { + return false + } + } + + return len(m) == len(props) // false if a property such as VM "guest" is unset +} + +// ObjectContent returns a list of ObjectContent.Obj where the +// ObjectContent.PropSet matches all properties the Filter. +func (m Match) ObjectContent(objects []types.ObjectContent) []types.ManagedObjectReference { + var refs []types.ManagedObjectReference + + for _, o := range objects { + if m.List(o.PropSet) { + refs = append(refs, o.Obj) + } + } + + return refs +} + +// AnyList returns true if any given props match. +func (m Match) AnyList(props []types.DynamicProperty) bool { + for _, p := range props { + if m.Property(p) { + return true + } + } + + return false +} + +// AnyObjectContent returns a list of ObjectContent.Obj where the +// ObjectContent.PropSet matches any property. +func (m Match) AnyObjectContent(objects []types.ObjectContent) []types.ManagedObjectReference { + var refs []types.ManagedObjectReference + + for _, o := range objects { + if m.AnyList(o.PropSet) { + refs = append(refs, o.Obj) + } + } + + return refs +} diff --git a/vendor/github.com/vmware/govmomi/property/wait.go b/vendor/github.com/vmware/govmomi/property/wait.go new file mode 100644 index 0000000000..07ea3cb5dc --- /dev/null +++ b/vendor/github.com/vmware/govmomi/property/wait.go @@ -0,0 +1,170 @@ +/* +Copyright (c) 2015-2024 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 property + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/vim25/types" +) + +// WaitOptions defines options for a property collector's WaitForUpdatesEx +// method. +type WaitOptions struct { + Options *types.WaitOptions + PropagateMissing bool + Truncated bool +} + +// WaitFilter provides helpers to construct a types.CreateFilter for use with property.Wait +type WaitFilter struct { + types.CreateFilter + WaitOptions +} + +// Add a new ObjectSpec and PropertySpec to the WaitFilter +func (f *WaitFilter) Add(obj types.ManagedObjectReference, kind string, ps []string, set ...types.BaseSelectionSpec) *WaitFilter { + spec := types.ObjectSpec{ + Obj: obj, + SelectSet: set, + } + + pset := types.PropertySpec{ + Type: kind, + PathSet: ps, + } + + if len(ps) == 0 { + pset.All = types.NewBool(true) + } + + f.Spec.ObjectSet = append(f.Spec.ObjectSet, spec) + + f.Spec.PropSet = append(f.Spec.PropSet, pset) + + return f +} + +// Wait creates a new WaitFilter and calls the specified function for each ObjectUpdate via WaitForUpdates +func Wait(ctx context.Context, c *Collector, obj types.ManagedObjectReference, ps []string, f func([]types.PropertyChange) bool) error { + filter := new(WaitFilter).Add(obj, obj.Type, ps) + + return WaitForUpdates(ctx, c, filter, func(updates []types.ObjectUpdate) bool { + for _, update := range updates { + if f(update.ChangeSet) { + return true + } + } + + return false + }) +} + +// WaitForUpdates waits for any of the specified properties of the specified +// managed object to change. It calls the specified function for every update it +// receives. If this function returns false, it continues waiting for +// subsequent updates. If this function returns true, it stops waiting and +// returns. +// +// To only receive updates for the specified managed object, the function +// 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). +// +// By default, ObjectUpdate.MissingSet faults are not propagated to the returned +// error, set WaitFilter.PropagateMissing=true to enable MissingSet fault +// propagation. +func WaitForUpdates( + ctx context.Context, + c *Collector, + filter *WaitFilter, + onUpdatesFn func([]types.ObjectUpdate) bool) (result error) { + + pc, err := c.Create(ctx) + if err != nil { + return err + } + + // Attempt to destroy the collector using the background context, as the + // specified context may have timed out or have been canceled. + defer func() { + if err := pc.Destroy(context.Background()); err != nil { + if result == nil { + result = err + } else { + result = fmt.Errorf( + "destroy property collector failed with %s after failing to wait for updates: %w", + err, + result) + } + } + }() + + // Create a property filter for the property collector. + if _, err := pc.CreateFilter(ctx, filter.CreateFilter); err != nil { + return err + } + + return pc.WaitForUpdatesEx(ctx, filter.WaitOptions, onUpdatesFn) +} + +// WaitForUpdates waits for any of the specified properties of the specified +// managed object to change. It calls the specified function for every update it +// receives. If this function returns false, it continues waiting for +// subsequent updates. If this function returns true, it stops waiting and +// returns. +// +// If the Context is canceled, a call to CancelWaitForUpdates() is made and its +// error value is returned. +// +// By default, ObjectUpdate.MissingSet faults are not propagated to the returned +// error, set WaitFilter.PropagateMissing=true to enable MissingSet fault +// propagation. +func WaitForUpdatesEx( + ctx context.Context, + pc *Collector, + filter *WaitFilter, + onUpdatesFn func([]types.ObjectUpdate) bool) (result error) { + + // Create a property filter for the property collector. + pf, err := pc.CreateFilter(ctx, filter.CreateFilter) + if err != nil { + return err + } + + // Destroy the filter using the background context, as the specified context + // may have timed out or have been canceled. + defer func() { + if err := pf.Destroy(context.Background()); err != nil { + if result == nil { + result = err + } else { + result = fmt.Errorf( + "destroy property filter failed with %s after failing to wait for updates: %w", + err, + result) + } + } + + }() + + return pc.WaitForUpdatesEx(ctx, filter.WaitOptions, onUpdatesFn) +} diff --git a/vendor/github.com/vmware/govmomi/session/keep_alive.go b/vendor/github.com/vmware/govmomi/session/keep_alive.go new file mode 100644 index 0000000000..7c1bebf913 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/session/keep_alive.go @@ -0,0 +1,40 @@ +/* +Copyright (c) 2015-2020 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 session + +import ( + "time" + + "github.com/vmware/govmomi/session/keepalive" + "github.com/vmware/govmomi/vim25/soap" +) + +// KeepAlive is a backward compatible wrapper around KeepAliveHandler. +func KeepAlive(roundTripper soap.RoundTripper, idleTime time.Duration) soap.RoundTripper { + return KeepAliveHandler(roundTripper, idleTime, nil) +} + +// KeepAliveHandler is a backward compatible wrapper around keepalive.NewHandlerSOAP. +func KeepAliveHandler(roundTripper soap.RoundTripper, idleTime time.Duration, handler func(soap.RoundTripper) error) soap.RoundTripper { + var f func() error + if handler != nil { + f = func() error { + return handler(roundTripper) + } + } + return keepalive.NewHandlerSOAP(roundTripper, idleTime, f) +} diff --git a/vendor/github.com/vmware/govmomi/session/keepalive/handler.go b/vendor/github.com/vmware/govmomi/session/keepalive/handler.go new file mode 100644 index 0000000000..3ebf046a53 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/session/keepalive/handler.go @@ -0,0 +1,204 @@ +/* +Copyright (c) 2020 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 keepalive + +import ( + "context" + "errors" + "net/http" + "sync" + "time" + + "github.com/vmware/govmomi/vapi/rest" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/soap" +) + +// handler contains the generic keep alive settings and logic +type handler struct { + mu sync.Mutex + notifyStop chan struct{} + notifyWaitGroup sync.WaitGroup + + idle time.Duration + send func() error +} + +// NewHandlerSOAP returns a soap.RoundTripper for use with a vim25.Client +// The idle time specifies the interval in between send() requests. Defaults to 10 minutes. +// The send func is used to keep a session alive. Defaults to calling vim25 GetCurrentTime(). +// The keep alive goroutine starts when a Login method is called and runs until Logout is called or send returns an error. +func NewHandlerSOAP(c soap.RoundTripper, idle time.Duration, send func() error) *HandlerSOAP { + h := &handler{ + idle: idle, + send: send, + } + + if send == nil { + h.send = func() error { + return h.keepAliveSOAP(c) + } + } + + return &HandlerSOAP{h, c} +} + +// NewHandlerREST returns an http.RoundTripper for use with a rest.Client +// The idle time specifies the interval in between send() requests. Defaults to 10 minutes. +// The send func is used to keep a session alive. Defaults to calling the rest.Client.Session() method +// The keep alive goroutine starts when a Login method is called and runs until Logout is called or send returns an error. +func NewHandlerREST(c *rest.Client, idle time.Duration, send func() error) *HandlerREST { + h := &handler{ + idle: idle, + send: send, + } + + if send == nil { + h.send = func() error { + return h.keepAliveREST(c) + } + } + + return &HandlerREST{h, c.Transport} +} + +func (h *handler) keepAliveSOAP(rt soap.RoundTripper) error { + ctx := context.Background() + _, err := methods.GetCurrentTime(ctx, rt) + return err +} + +func (h *handler) keepAliveREST(c *rest.Client) error { + ctx := context.Background() + + s, err := c.Session(ctx) + if err != nil { + return err + } + if s != nil { + return nil + } + return errors.New(http.StatusText(http.StatusUnauthorized)) +} + +// Start explicitly starts the keep alive go routine. +// For use with session cache.Client, as cached sessions may not involve Login/Logout via RoundTripper. +func (h *handler) Start() { + h.mu.Lock() + defer h.mu.Unlock() + + if h.notifyStop != nil { + return + } + + if h.idle == 0 { + h.idle = time.Minute * 10 + } + + // This channel must be closed to terminate idle timer. + h.notifyStop = make(chan struct{}) + h.notifyWaitGroup.Add(1) + + go func() { + for t := time.NewTimer(h.idle); ; { + select { + case <-h.notifyStop: + h.notifyWaitGroup.Done() + t.Stop() + return + case <-t.C: + if err := h.send(); err != nil { + h.notifyWaitGroup.Done() + h.Stop() + return + } + t.Reset(h.idle) + } + } + }() +} + +// Stop explicitly stops the keep alive go routine. +// For use with session cache.Client, as cached sessions may not involve Login/Logout via RoundTripper. +func (h *handler) Stop() { + h.mu.Lock() + defer h.mu.Unlock() + + if h.notifyStop != nil { + close(h.notifyStop) + h.notifyWaitGroup.Wait() + h.notifyStop = nil + } +} + +// HandlerSOAP is a keep alive implementation for use with vim25.Client +type HandlerSOAP struct { + *handler + + roundTripper soap.RoundTripper +} + +// RoundTrip implements soap.RoundTripper +func (h *HandlerSOAP) RoundTrip(ctx context.Context, req, res soap.HasFault) error { + // Stop ticker on logout. + switch req.(type) { + case *methods.LogoutBody: + h.Stop() + } + + err := h.roundTripper.RoundTrip(ctx, req, res) + if err != nil { + return err + } + + // Start ticker on login. + switch req.(type) { + case *methods.LoginBody, *methods.LoginExtensionByCertificateBody, *methods.LoginByTokenBody: + h.Start() + } + + return nil +} + +// HandlerREST is a keep alive implementation for use with rest.Client +type HandlerREST struct { + *handler + + roundTripper http.RoundTripper +} + +// RoundTrip implements http.RoundTripper +func (h *HandlerREST) RoundTrip(req *http.Request) (*http.Response, error) { + if req.URL.Path != "/rest/com/vmware/cis/session" { + return h.roundTripper.RoundTrip(req) + } + + if req.Method == http.MethodDelete { // Logout + h.Stop() + } + + res, err := h.roundTripper.RoundTrip(req) + if err != nil { + return res, err + } + + if req.Method == http.MethodPost { // Login + h.Start() + } + + return res, err +} diff --git a/vendor/github.com/vmware/govmomi/session/manager.go b/vendor/github.com/vmware/govmomi/session/manager.go new file mode 100644 index 0000000000..e2d70a2f60 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/session/manager.go @@ -0,0 +1,293 @@ +/* +Copyright (c) 2015 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 session + +import ( + "context" + "net/url" + "os" + "strings" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +// Locale defaults to "en_US" and can be overridden via this var or the GOVMOMI_LOCALE env var. +// A value of "_" uses the server locale setting. +var Locale = os.Getenv("GOVMOMI_LOCALE") + +func init() { + if Locale == "_" { + Locale = "" + } else if Locale == "" { + Locale = "en_US" + } +} + +// Secret returns the contents if a file path value is given, otherwise returns value itself. +func Secret(value string) (string, error) { + if len(value) == 0 { + return value, nil + } + contents, err := os.ReadFile(value) + if err != nil { + if os.IsPermission(err) { + return "", err + } + return value, nil + } + return strings.TrimSpace(string(contents)), nil +} + +type Manager struct { + client *vim25.Client + userSession *types.UserSession +} + +func NewManager(client *vim25.Client) *Manager { + m := Manager{ + client: client, + } + + return &m +} + +func (sm Manager) Reference() types.ManagedObjectReference { + return *sm.client.ServiceContent.SessionManager +} + +func (sm *Manager) SetLocale(ctx context.Context, locale string) error { + req := types.SetLocale{ + This: sm.Reference(), + Locale: locale, + } + + _, err := methods.SetLocale(ctx, sm.client, &req) + return err +} + +func (sm *Manager) Login(ctx context.Context, u *url.Userinfo) error { + req := types.Login{ + This: sm.Reference(), + Locale: Locale, + } + + if u != nil { + req.UserName = u.Username() + if pw, ok := u.Password(); ok { + req.Password = pw + } + } + + login, err := methods.Login(ctx, sm.client, &req) + if err != nil { + return err + } + + sm.userSession = &login.Returnval + return nil +} + +// LoginExtensionByCertificate uses the vCenter SDK tunnel to login using a client certificate. +// The client certificate can be set using the soap.Client.SetCertificate method. +// See: https://kb.vmware.com/s/article/2004305 +func (sm *Manager) LoginExtensionByCertificate(ctx context.Context, key string) error { + c := sm.client + u := c.URL() + if u.Hostname() != "sdkTunnel" { + sc := c.Tunnel() + c = &vim25.Client{ + Client: sc, + RoundTripper: sc, + ServiceContent: c.ServiceContent, + } + // When http.Transport.Proxy is used, our thumbprint checker is bypassed, resulting in: + // "Post https://sdkTunnel:8089/sdk: x509: certificate is valid for $vcenter_hostname, not sdkTunnel" + // The only easy way around this is to disable verification for the call to LoginExtensionByCertificate(). + // TODO: find a way to avoid disabling InsecureSkipVerify. + c.DefaultTransport().TLSClientConfig.InsecureSkipVerify = true + } + + req := types.LoginExtensionByCertificate{ + This: sm.Reference(), + ExtensionKey: key, + Locale: Locale, + } + + login, err := methods.LoginExtensionByCertificate(ctx, c, &req) + if err != nil { + return err + } + + // Copy the session cookie + sm.client.Jar.SetCookies(u, c.Jar.Cookies(c.URL())) + + sm.userSession = &login.Returnval + return nil +} + +func (sm *Manager) LoginByToken(ctx context.Context) error { + req := types.LoginByToken{ + This: sm.Reference(), + Locale: Locale, + } + + login, err := methods.LoginByToken(ctx, sm.client, &req) + if err != nil { + return err + } + + sm.userSession = &login.Returnval + return nil +} + +func (sm *Manager) Logout(ctx context.Context) error { + req := types.Logout{ + This: sm.Reference(), + } + + _, err := methods.Logout(ctx, sm.client, &req) + if err != nil { + return err + } + + sm.userSession = nil + return nil +} + +// UserSession retrieves and returns the SessionManager's CurrentSession field. +// Nil is returned if the session is not authenticated. +func (sm *Manager) UserSession(ctx context.Context) (*types.UserSession, error) { + var mgr mo.SessionManager + + pc := property.DefaultCollector(sm.client) + err := pc.RetrieveOne(ctx, sm.Reference(), []string{"currentSession"}, &mgr) + if err != nil { + // It's OK if we can't retrieve properties because we're not authenticated + if f, ok := err.(types.HasFault); ok { + switch f.Fault().(type) { + case *types.NotAuthenticated: + return nil, nil + } + } + + return nil, err + } + + return mgr.CurrentSession, nil +} + +func (sm *Manager) TerminateSession(ctx context.Context, sessionId []string) error { + req := types.TerminateSession{ + This: sm.Reference(), + SessionId: sessionId, + } + + _, err := methods.TerminateSession(ctx, sm.client, &req) + return err +} + +// SessionIsActive checks whether the session that was created at login is +// still valid. This function only works against vCenter. +func (sm *Manager) SessionIsActive(ctx context.Context) (bool, error) { + if sm.userSession == nil { + return false, nil + } + + req := types.SessionIsActive{ + This: sm.Reference(), + SessionID: sm.userSession.Key, + UserName: sm.userSession.UserName, + } + + active, err := methods.SessionIsActive(ctx, sm.client, &req) + if err != nil { + return false, err + } + + return active.Returnval, err +} + +func (sm *Manager) AcquireGenericServiceTicket(ctx context.Context, spec types.BaseSessionManagerServiceRequestSpec) (*types.SessionManagerGenericServiceTicket, error) { + req := types.AcquireGenericServiceTicket{ + This: sm.Reference(), + Spec: spec, + } + + res, err := methods.AcquireGenericServiceTicket(ctx, sm.client, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +func (sm *Manager) AcquireLocalTicket(ctx context.Context, userName string) (*types.SessionManagerLocalTicket, error) { + req := types.AcquireLocalTicket{ + This: sm.Reference(), + UserName: userName, + } + + res, err := methods.AcquireLocalTicket(ctx, sm.client, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +func (sm *Manager) AcquireCloneTicket(ctx context.Context) (string, error) { + req := types.AcquireCloneTicket{ + This: sm.Reference(), + } + + res, err := methods.AcquireCloneTicket(ctx, sm.client, &req) + if err != nil { + return "", err + } + + return res.Returnval, nil +} + +func (sm *Manager) CloneSession(ctx context.Context, ticket string) error { + req := types.CloneSession{ + This: sm.Reference(), + CloneTicket: ticket, + } + + res, err := methods.CloneSession(ctx, sm.client, &req) + if err != nil { + return err + } + + sm.userSession = &res.Returnval + return nil +} + +func (sm *Manager) UpdateServiceMessage(ctx context.Context, message string) error { + req := types.UpdateServiceMessage{ + This: sm.Reference(), + Message: message, + } + + _, err := methods.UpdateServiceMessage(ctx, sm.client, &req) + + return err +} diff --git a/vendor/github.com/vmware/govmomi/task/error.go b/vendor/github.com/vmware/govmomi/task/error.go new file mode 100644 index 0000000000..3fff5aa265 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/task/error.go @@ -0,0 +1,33 @@ +/* +Copyright (c) 2015 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 task + +import "github.com/vmware/govmomi/vim25/types" + +type Error struct { + *types.LocalizedMethodFault + Description *types.LocalizableMessage +} + +// Error returns the task's localized fault message. +func (e Error) Error() string { + return e.LocalizedMethodFault.LocalizedMessage +} + +func (e Error) Fault() types.BaseMethodFault { + return e.LocalizedMethodFault.Fault +} diff --git a/vendor/github.com/vmware/govmomi/task/history_collector.go b/vendor/github.com/vmware/govmomi/task/history_collector.go new file mode 100644 index 0000000000..7d8a6cf04a --- /dev/null +++ b/vendor/github.com/vmware/govmomi/task/history_collector.go @@ -0,0 +1,89 @@ +/* +Copyright (c) 2015-2022 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 task + +import ( + "context" + + "github.com/vmware/govmomi/history" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +// HistoryCollector provides a mechanism for retrieving historical data and +// updates when the server appends new tasks. +type HistoryCollector struct { + *history.Collector +} + +func newHistoryCollector(c *vim25.Client, ref types.ManagedObjectReference) *HistoryCollector { + return &HistoryCollector{ + Collector: history.NewCollector(c, ref), + } +} + +// LatestPage returns items in the 'viewable latest page' of the task history collector. +// As new tasks that match the collector's TaskFilterSpec are created, +// they are added to this page, and the oldest tasks are removed from the collector to keep +// the size of the page to that allowed by SetCollectorPageSize. +// The "oldest task" is the one with the oldest creation time. The tasks in the returned page are unordered. +func (h HistoryCollector) LatestPage(ctx context.Context) ([]types.TaskInfo, error) { + var o mo.TaskHistoryCollector + + err := h.Properties(ctx, h.Reference(), []string{"latestPage"}, &o) + if err != nil { + return nil, err + } + + return o.LatestPage, nil +} + +// ReadNextTasks reads the scrollable view from the current position. The +// scrollable position is moved to the next newer page after the read. No item +// is returned when the end of the collector is reached. +func (h HistoryCollector) ReadNextTasks(ctx context.Context, maxCount int32) ([]types.TaskInfo, error) { + req := types.ReadNextTasks{ + This: h.Reference(), + MaxCount: maxCount, + } + + res, err := methods.ReadNextTasks(ctx, h.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +// ReadPreviousTasks reads the scrollable view from the current position. The +// scrollable position is then moved to the next older page after the read. No +// item is returned when the head of the collector is reached. +func (h HistoryCollector) ReadPreviousTasks(ctx context.Context, maxCount int32) ([]types.TaskInfo, error) { + req := types.ReadPreviousTasks{ + This: h.Reference(), + MaxCount: maxCount, + } + + res, err := methods.ReadPreviousTasks(ctx, h.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/task/manager.go b/vendor/github.com/vmware/govmomi/task/manager.go new file mode 100644 index 0000000000..8279089d7d --- /dev/null +++ b/vendor/github.com/vmware/govmomi/task/manager.go @@ -0,0 +1,61 @@ +/* +Copyright (c) 2014-2022 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 task + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type Manager struct { + r types.ManagedObjectReference + c *vim25.Client +} + +// NewManager creates a new task manager +func NewManager(c *vim25.Client) *Manager { + m := Manager{ + r: *c.ServiceContent.TaskManager, + c: c, + } + + return &m +} + +// Reference returns the task.Manager MOID +func (m Manager) Reference() types.ManagedObjectReference { + return m.r +} + +// CreateCollectorForTasks returns a task history collector, a specialized +// history collector that gathers TaskInfo data objects. +func (m Manager) CreateCollectorForTasks(ctx context.Context, filter types.TaskFilterSpec) (*HistoryCollector, error) { + req := types.CreateCollectorForTasks{ + This: m.r, + Filter: filter, + } + + res, err := methods.CreateCollectorForTasks(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return newHistoryCollector(m.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/task/wait.go b/vendor/github.com/vmware/govmomi/task/wait.go new file mode 100644 index 0000000000..8f3a2fe6b0 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/task/wait.go @@ -0,0 +1,157 @@ +/* +Copyright (c) 2015-2024 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 task + +import ( + "context" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25/progress" + "github.com/vmware/govmomi/vim25/types" +) + +type taskProgress struct { + info *types.TaskInfo +} + +func (t taskProgress) Percentage() float32 { + return float32(t.info.Progress) +} + +func (t taskProgress) Detail() string { + return "" +} + +func (t taskProgress) Error() error { + if t.info.Error != nil { + return Error{t.info.Error, t.info.Description} + } + + return nil +} + +type taskCallback struct { + ch chan<- progress.Report + info *types.TaskInfo + err error +} + +func (t *taskCallback) fn(pc []types.PropertyChange) bool { + for _, c := range pc { + if c.Name != "info" { + continue + } + + if c.Op != types.PropertyChangeOpAssign { + continue + } + + if c.Val == nil { + continue + } + + ti := c.Val.(types.TaskInfo) + t.info = &ti + } + + // t.info could be nil if pc can't satisfy the rules above + if t.info == nil { + return false + } + + pr := taskProgress{t.info} + + // Store copy of error, so Wait() can return it as well. + t.err = pr.Error() + + switch t.info.State { + case types.TaskInfoStateQueued, types.TaskInfoStateRunning: + if t.ch != nil { + // Don't care if this is dropped + select { + case t.ch <- pr: + default: + } + } + return false + case types.TaskInfoStateSuccess, types.TaskInfoStateError: + if t.ch != nil { + // Last one must always be delivered + t.ch <- pr + } + return true + default: + panic("unknown state: " + t.info.State) + } +} + +// WaitEx waits for a task to finish with either success or failure. It does so +// by waiting for the "info" property of task managed object to change. The +// function returns when it finds the task in the "success" or "error" state. +// In the former case, the return value is nil. In the latter case the return +// value is an instance of this package's Error struct. +// +// Any error returned while waiting for property changes causes the function to +// return immediately and propagate the error. +// +// If the progress.Sinker argument is specified, any progress updates for the +// task are sent here. The completion percentage is passed through directly. +// The detail for the progress update is set to an empty string. If the task +// finishes in the error state, the error instance is passed through as well. +// Note that this error is the same error that is returned by this function. +func WaitEx( + ctx context.Context, + ref types.ManagedObjectReference, + pc *property.Collector, + s progress.Sinker) (*types.TaskInfo, error) { + + cb := &taskCallback{} + + // Include progress sink if specified + if s != nil { + cb.ch = s.Sink() + defer close(cb.ch) + } + + filter := &property.WaitFilter{ + WaitOptions: property.WaitOptions{ + PropagateMissing: true, + }, + } + filter.Add(ref, ref.Type, []string{"info"}) + + if err := property.WaitForUpdatesEx( + ctx, + pc, + filter, + func(updates []types.ObjectUpdate) bool { + for _, update := range updates { + // Only look at updates for the expected task object. + if update.Obj.Value == ref.Value && update.Obj.Type == ref.Type { + if cb.fn(update.ChangeSet) { + return true + } + } + } + return false + }); err != nil { + + return nil, err + } + + return cb.info, cb.err +} diff --git a/vendor/github.com/vmware/govmomi/vapi/internal/internal.go b/vendor/github.com/vmware/govmomi/vapi/internal/internal.go new file mode 100644 index 0000000000..5931fd4abd --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/internal/internal.go @@ -0,0 +1,94 @@ +/* +Copyright (c) 2018-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +// VAPI REST Paths +const ( + SessionPath = "/com/vmware/cis/session" + CategoryPath = "/com/vmware/cis/tagging/category" + TagPath = "/com/vmware/cis/tagging/tag" + AssociationPath = "/com/vmware/cis/tagging/tag-association" + LibraryPath = "/com/vmware/content/library" + LibraryItemFileData = "/com/vmware/cis/data" + LibraryItemPath = "/com/vmware/content/library/item" + LibraryItemFilePath = "/com/vmware/content/library/item/file" + LibraryItemStoragePath = "/com/vmware/content/library/item/storage" + LibraryItemUpdateSession = "/com/vmware/content/library/item/update-session" + LibraryItemUpdateSessionFile = "/com/vmware/content/library/item/updatesession/file" + LibraryItemDownloadSession = "/com/vmware/content/library/item/download-session" + LibraryItemDownloadSessionFile = "/com/vmware/content/library/item/downloadsession/file" + LocalLibraryPath = "/com/vmware/content/local-library" + SubscribedLibraryPath = "/com/vmware/content/subscribed-library" + SecurityPoliciesPath = "/api/content/security-policies" + SubscribedLibraryItem = "/com/vmware/content/library/subscribed-item" + Subscriptions = "/com/vmware/content/library/subscriptions" + TrustedCertificatesPath = "/api/content/trusted-certificates" + VCenterOVFLibraryItem = "/com/vmware/vcenter/ovf/library-item" + VCenterVMTXLibraryItem = "/vcenter/vm-template/library-items" + SessionCookieName = "vmware-api-session-id" + UseHeaderAuthn = "vmware-use-header-authn" + DebugEcho = "/vc-sim/debug/echo" +) + +// AssociatedObject is the same structure as types.ManagedObjectReference, +// just with a different field name (ID instead of Value). +// In the API we use mo.Reference, this type is only used for wire transfer. +type AssociatedObject struct { + Type string `json:"type"` + Value string `json:"id"` +} + +// Reference implements mo.Reference +func (o AssociatedObject) Reference() types.ManagedObjectReference { + return types.ManagedObjectReference{ + Type: o.Type, + Value: o.Value, + } +} + +// Association for tag-association requests. +type Association struct { + ObjectID *AssociatedObject `json:"object_id,omitempty"` +} + +// NewAssociation returns an Association, converting ref to an AssociatedObject. +func NewAssociation(ref mo.Reference) Association { + return Association{ + ObjectID: &AssociatedObject{ + Type: ref.Reference().Type, + Value: ref.Reference().Value, + }, + } +} + +type SubscriptionDestination struct { + ID string `json:"subscription"` +} + +type SubscriptionDestinationSpec struct { + Subscriptions []SubscriptionDestination `json:"subscriptions,omitempty"` +} + +type SubscriptionItemDestinationSpec struct { + Force bool `json:"force_sync_content"` + Subscriptions []SubscriptionDestination `json:"subscriptions,omitempty"` +} diff --git a/vendor/github.com/vmware/govmomi/vapi/rest/client.go b/vendor/github.com/vmware/govmomi/vapi/rest/client.go new file mode 100644 index 0000000000..52552bf00f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/rest/client.go @@ -0,0 +1,350 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rest + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "sync" + "time" + + "github.com/vmware/govmomi/vapi/internal" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// Client extends soap.Client to support JSON encoding, while inheriting security features, debug tracing and session persistence. +type Client struct { + mu sync.Mutex + + *soap.Client + sessionID string +} + +// Session information +type Session struct { + User string `json:"user"` + Created time.Time `json:"created_time"` + LastAccessed time.Time `json:"last_accessed_time"` +} + +// LocalizableMessage represents a localizable error +type LocalizableMessage struct { + Args []string `json:"args,omitempty"` + DefaultMessage string `json:"default_message,omitempty"` + ID string `json:"id,omitempty"` +} + +func (m *LocalizableMessage) Error() string { + return m.DefaultMessage +} + +// NewClient creates a new Client instance. +func NewClient(c *vim25.Client) *Client { + sc := c.Client.NewServiceClient(Path, "") + + return &Client{Client: sc} +} + +// SessionID is set by calling Login() or optionally with the given id param +func (c *Client) SessionID(id ...string) string { + c.mu.Lock() + defer c.mu.Unlock() + if len(id) != 0 { + c.sessionID = id[0] + } + return c.sessionID +} + +type marshaledClient struct { + SoapClient *soap.Client + SessionID string +} + +func (c *Client) MarshalJSON() ([]byte, error) { + m := marshaledClient{ + SoapClient: c.Client, + SessionID: c.sessionID, + } + + return json.Marshal(m) +} + +func (c *Client) UnmarshalJSON(b []byte) error { + var m marshaledClient + + err := json.Unmarshal(b, &m) + if err != nil { + return err + } + + *c = Client{ + Client: m.SoapClient, + sessionID: m.SessionID, + } + + return nil +} + +// isAPI returns true if path starts with "/api" +// This hack allows helpers to support both endpoints: +// "/rest" - value wrapped responses and structured error responses +// "/api" - raw responses and no structured error responses +func isAPI(path string) bool { + return strings.HasPrefix(path, "/api") +} + +// Resource helper for the given path. +func (c *Client) Resource(path string) *Resource { + r := &Resource{u: c.URL()} + if !isAPI(path) { + path = Path + path + } + r.u.Path = path + return r +} + +type Signer interface { + SignRequest(*http.Request) error +} + +type signerContext struct{} + +func (c *Client) WithSigner(ctx context.Context, s Signer) context.Context { + return context.WithValue(ctx, signerContext{}, s) +} + +type headersContext struct{} + +// WithHeader returns a new Context populated with the provided headers map. +// Calls to a VAPI REST client with this context will populate the HTTP headers +// map using the provided headers. +func (c *Client) WithHeader( + ctx context.Context, + headers http.Header) context.Context { + + return context.WithValue(ctx, headersContext{}, headers) +} + +type statusError struct { + res *http.Response +} + +func (e *statusError) Error() string { + return fmt.Sprintf("%s %s: %s", e.res.Request.Method, e.res.Request.URL, e.res.Status) +} + +func IsStatusError(err error, code int) bool { + statusErr, ok := err.(*statusError) + if !ok || statusErr == nil || statusErr.res == nil { + return false + } + return statusErr.res.StatusCode == code +} + +// RawResponse may be used with the Do method as the resBody argument in order +// to capture the raw response data. +type RawResponse struct { + bytes.Buffer +} + +// Do sends the http.Request, decoding resBody if provided. +func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{}) error { + switch req.Method { + case http.MethodPost, http.MethodPatch, http.MethodPut: + req.Header.Set("Content-Type", "application/json") + } + + req.Header.Set("Accept", "application/json") + + if id := c.SessionID(); id != "" { + req.Header.Set(internal.SessionCookieName, id) + } + + if s, ok := ctx.Value(signerContext{}).(Signer); ok { + if err := s.SignRequest(req); err != nil { + return err + } + } + + // OperationID (see soap.Client.soapRoundTrip) + if id, ok := ctx.Value(types.ID{}).(string); ok { + req.Header.Add("X-Request-ID", id) + } + + if headers, ok := ctx.Value(headersContext{}).(http.Header); ok { + for k, v := range headers { + for _, v := range v { + req.Header.Add(k, v) + } + } + } + + return c.Client.Do(ctx, req, func(res *http.Response) error { + switch res.StatusCode { + case http.StatusOK: + case http.StatusCreated: + case http.StatusAccepted: + case http.StatusNoContent: + case http.StatusBadRequest: + // TODO: structured error types + detail, err := io.ReadAll(res.Body) + if err != nil { + return err + } + return fmt.Errorf("%s: %s", res.Status, bytes.TrimSpace(detail)) + default: + return &statusError{res} + } + + if resBody == nil { + return nil + } + + switch b := resBody.(type) { + case *RawResponse: + return res.Write(b) + case io.Writer: + _, err := io.Copy(b, res.Body) + return err + default: + d := json.NewDecoder(res.Body) + if isAPI(req.URL.Path) { + // Responses from the /api endpoint are not wrapped + return d.Decode(resBody) + } + // Responses from the /rest endpoint are wrapped in this structure + val := struct { + Value interface{} `json:"value,omitempty"` + }{ + resBody, + } + return d.Decode(&val) + } + }) +} + +// authHeaders ensures the given map contains a REST auth header +func (c *Client) authHeaders(h map[string]string) map[string]string { + if _, exists := h[internal.SessionCookieName]; exists { + return h + } + if h == nil { + h = make(map[string]string) + } + + h[internal.SessionCookieName] = c.SessionID() + + return h +} + +// Download wraps soap.Client.Download, adding the REST authentication header +func (c *Client) Download(ctx context.Context, u *url.URL, param *soap.Download) (io.ReadCloser, int64, error) { + p := *param + p.Headers = c.authHeaders(p.Headers) + return c.Client.Download(ctx, u, &p) +} + +// DownloadFile wraps soap.Client.DownloadFile, adding the REST authentication header +func (c *Client) DownloadFile(ctx context.Context, file string, u *url.URL, param *soap.Download) error { + p := *param + p.Headers = c.authHeaders(p.Headers) + return c.Client.DownloadFile(ctx, file, u, &p) +} + +// Upload wraps soap.Client.Upload, adding the REST authentication header +func (c *Client) Upload(ctx context.Context, f io.Reader, u *url.URL, param *soap.Upload) error { + p := *param + p.Headers = c.authHeaders(p.Headers) + return c.Client.Upload(ctx, f, u, &p) +} + +// Login creates a new session via Basic Authentication with the given url.Userinfo. +func (c *Client) Login(ctx context.Context, user *url.Userinfo) error { + req := c.Resource(internal.SessionPath).Request(http.MethodPost) + + req.Header.Set(internal.UseHeaderAuthn, "true") + + if user != nil { + if password, ok := user.Password(); ok { + req.SetBasicAuth(user.Username(), password) + } + } + + var id string + err := c.Do(ctx, req, &id) + if err != nil { + return err + } + + c.SessionID(id) + + return nil +} + +func (c *Client) LoginByToken(ctx context.Context) error { + return c.Login(ctx, nil) +} + +// Session returns the user's current session. +// Nil is returned if the session is not authenticated. +func (c *Client) Session(ctx context.Context) (*Session, error) { + var s Session + req := c.Resource(internal.SessionPath).WithAction("get").Request(http.MethodPost) + err := c.Do(ctx, req, &s) + if err != nil { + if e, ok := err.(*statusError); ok { + if e.res.StatusCode == http.StatusUnauthorized { + return nil, nil + } + } + return nil, err + } + return &s, nil +} + +// Logout deletes the current session. +func (c *Client) Logout(ctx context.Context) error { + req := c.Resource(internal.SessionPath).Request(http.MethodDelete) + return c.Do(ctx, req, nil) +} + +// Valid returns whether or not the client is valid and ready for use. +// This should be called after unmarshalling the client. +func (c *Client) Valid() bool { + if c == nil { + return false + } + + if c.Client == nil { + return false + } + + return true +} + +// Path returns rest.Path (see cache.Client) +func (c *Client) Path() string { + return Path +} diff --git a/vendor/github.com/vmware/govmomi/vapi/rest/resource.go b/vendor/github.com/vmware/govmomi/vapi/rest/resource.go new file mode 100644 index 0000000000..f89e07e3b9 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/rest/resource.go @@ -0,0 +1,120 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rest + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/url" +) + +const ( + Path = "/rest" +) + +// Resource wraps url.URL with helpers +type Resource struct { + u *url.URL +} + +func (r *Resource) String() string { + return r.u.String() +} + +// WithSubpath appends the provided subpath to the URL.Path +func (r *Resource) WithSubpath(subpath string) *Resource { + r.u.Path += "/" + subpath + return r +} + +// WithID appends id to the URL.Path +func (r *Resource) WithID(id string) *Resource { + r.u.Path += "/id:" + id + return r +} + +// WithAction sets adds action to the URL.RawQuery +func (r *Resource) WithAction(action string) *Resource { + return r.WithParam("~action", action) +} + +// WithParam adds one parameter on the URL.RawQuery +func (r *Resource) WithParam(name string, value string) *Resource { + // ParseQuery handles empty case, and we control access to query string so shouldn't encounter an error case + params, err := url.ParseQuery(r.u.RawQuery) + if err != nil { + panic(err) + } + params[name] = append(params[name], value) + r.u.RawQuery = params.Encode() + return r +} + +// WithPathEncodedParam appends a parameter on the URL.RawQuery, +// For special cases where URL Path-style encoding is needed +func (r *Resource) WithPathEncodedParam(name string, value string) *Resource { + t := &url.URL{Path: value} + encodedValue := t.String() + t = &url.URL{Path: name} + encodedName := t.String() + // ParseQuery handles empty case, and we control access to query string so shouldn't encounter an error case + params, err := url.ParseQuery(r.u.RawQuery) + if err != nil { + panic(err) + } + // Values.Encode() doesn't escape exactly how we want, so we need to build the query string ourselves + if len(params) >= 1 { + r.u.RawQuery = r.u.RawQuery + "&" + encodedName + "=" + encodedValue + } else { + r.u.RawQuery = r.u.RawQuery + encodedName + "=" + encodedValue + } + return r +} + +// Request returns a new http.Request for the given method. +// An optional body can be provided for POST and PATCH methods. +func (r *Resource) Request(method string, body ...interface{}) *http.Request { + rdr := io.MultiReader() // empty body by default + if len(body) != 0 { + rdr = encode(body[0]) + } + req, err := http.NewRequest(method, r.u.String(), rdr) + if err != nil { + panic(err) + } + return req +} + +type errorReader struct { + e error +} + +func (e errorReader) Read([]byte) (int, error) { + return -1, e.e +} + +// encode body as JSON, deferring any errors until io.Reader is used. +func encode(body interface{}) io.Reader { + var b bytes.Buffer + err := json.NewEncoder(&b).Encode(body) + if err != nil { + return errorReader{err} + } + return &b +} diff --git a/vendor/github.com/vmware/govmomi/view/container_view.go b/vendor/github.com/vmware/govmomi/view/container_view.go new file mode 100644 index 0000000000..356994035f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/view/container_view.go @@ -0,0 +1,145 @@ +/* +Copyright (c) 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 view + +import ( + "context" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type ContainerView struct { + ManagedObjectView +} + +func NewContainerView(c *vim25.Client, ref types.ManagedObjectReference) *ContainerView { + return &ContainerView{ + ManagedObjectView: *NewManagedObjectView(c, ref), + } +} + +// Retrieve populates dst as property.Collector.Retrieve does, for all entities in the view of types specified by kind. +func (v ContainerView) Retrieve(ctx context.Context, kind []string, ps []string, dst interface{}, pspec ...types.PropertySpec) error { + pc := property.DefaultCollector(v.Client()) + + ospec := types.ObjectSpec{ + Obj: v.Reference(), + Skip: types.NewBool(true), + SelectSet: []types.BaseSelectionSpec{ + &types.TraversalSpec{ + Type: v.Reference().Type, + Path: "view", + }, + }, + } + + if len(kind) == 0 { + kind = []string{"ManagedEntity"} + } + + for _, t := range kind { + spec := types.PropertySpec{ + Type: t, + } + + if len(ps) == 0 { + spec.All = types.NewBool(true) + } else { + spec.PathSet = ps + } + + pspec = append(pspec, spec) + } + + req := types.RetrieveProperties{ + SpecSet: []types.PropertyFilterSpec{ + { + ObjectSet: []types.ObjectSpec{ospec}, + PropSet: pspec, + }, + }, + } + + res, err := pc.RetrieveProperties(ctx, req) + if err != nil { + return err + } + + if d, ok := dst.(*[]types.ObjectContent); ok { + *d = res.Returnval + return nil + } + + return mo.LoadObjectContent(res.Returnval, dst) +} + +// RetrieveWithFilter populates dst as Retrieve does, but only for entities matching the given filter. +func (v ContainerView) RetrieveWithFilter(ctx context.Context, kind []string, ps []string, dst interface{}, filter property.Match) error { + if len(filter) == 0 { + return v.Retrieve(ctx, kind, ps, dst) + } + + var content []types.ObjectContent + + err := v.Retrieve(ctx, kind, filter.Keys(), &content) + if err != nil { + return err + } + + objs := filter.ObjectContent(content) + + pc := property.DefaultCollector(v.Client()) + + return pc.Retrieve(ctx, objs, ps, dst) +} + +// Find returns object references for entities of type kind, matching the given filter. +func (v ContainerView) Find(ctx context.Context, kind []string, filter property.Match) ([]types.ManagedObjectReference, error) { + if len(filter) == 0 { + // Ensure we have at least 1 filter to avoid retrieving all properties. + filter = property.Match{"name": "*"} + } + + var content []types.ObjectContent + + err := v.Retrieve(ctx, kind, filter.Keys(), &content) + if err != nil { + return nil, err + } + + return filter.ObjectContent(content), nil +} + +// FindAny returns object references for entities of type kind, matching any property the given filter. +func (v ContainerView) FindAny(ctx context.Context, kind []string, filter property.Match) ([]types.ManagedObjectReference, error) { + if len(filter) == 0 { + // Ensure we have at least 1 filter to avoid retrieving all properties. + filter = property.Match{"name": "*"} + } + + var content []types.ObjectContent + + err := v.Retrieve(ctx, kind, filter.Keys(), &content) + if err != nil { + return nil, err + } + + return filter.AnyObjectContent(content), nil +} diff --git a/vendor/github.com/vmware/govmomi/view/list_view.go b/vendor/github.com/vmware/govmomi/view/list_view.go new file mode 100644 index 0000000000..4958941cc6 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/view/list_view.go @@ -0,0 +1,74 @@ +/* +Copyright (c) 2015-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 view + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type ListView struct { + ManagedObjectView +} + +func NewListView(c *vim25.Client, ref types.ManagedObjectReference) *ListView { + return &ListView{ + ManagedObjectView: *NewManagedObjectView(c, ref), + } +} + +func (v ListView) Add(ctx context.Context, refs []types.ManagedObjectReference) ([]types.ManagedObjectReference, error) { + req := types.ModifyListView{ + This: v.Reference(), + Add: refs, + } + res, err := methods.ModifyListView(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (v ListView) Remove(ctx context.Context, refs []types.ManagedObjectReference) ([]types.ManagedObjectReference, error) { + req := types.ModifyListView{ + This: v.Reference(), + Remove: refs, + } + res, err := methods.ModifyListView(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (v ListView) Reset(ctx context.Context, refs []types.ManagedObjectReference) ([]types.ManagedObjectReference, error) { + req := types.ResetListView{ + This: v.Reference(), + Obj: refs, + } + res, err := methods.ResetListView(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/view/managed_object_view.go b/vendor/github.com/vmware/govmomi/view/managed_object_view.go new file mode 100644 index 0000000000..805c864310 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/view/managed_object_view.go @@ -0,0 +1,52 @@ +/* +Copyright (c) 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 view + +import ( + "context" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type ManagedObjectView struct { + object.Common +} + +func NewManagedObjectView(c *vim25.Client, ref types.ManagedObjectReference) *ManagedObjectView { + return &ManagedObjectView{ + Common: object.NewCommon(c, ref), + } +} + +func (v *ManagedObjectView) TraversalSpec() *types.TraversalSpec { + return &types.TraversalSpec{ + Path: "view", + Type: v.Reference().Type, + } +} + +func (v *ManagedObjectView) Destroy(ctx context.Context) error { + req := types.DestroyView{ + This: v.Reference(), + } + + _, err := methods.DestroyView(ctx, v.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/view/manager.go b/vendor/github.com/vmware/govmomi/view/manager.go new file mode 100644 index 0000000000..d44def0cd9 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/view/manager.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2015 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 view + +import ( + "context" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type Manager struct { + object.Common +} + +func NewManager(c *vim25.Client) *Manager { + m := Manager{ + object.NewCommon(c, *c.ServiceContent.ViewManager), + } + + return &m +} + +func (m Manager) CreateListView(ctx context.Context, objects []types.ManagedObjectReference) (*ListView, error) { + req := types.CreateListView{ + This: m.Common.Reference(), + Obj: objects, + } + + res, err := methods.CreateListView(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return NewListView(m.Client(), res.Returnval), nil +} + +func (m Manager) CreateContainerView(ctx context.Context, container types.ManagedObjectReference, managedObjectTypes []string, recursive bool) (*ContainerView, error) { + + req := types.CreateContainerView{ + This: m.Common.Reference(), + Container: container, + Recursive: recursive, + Type: managedObjectTypes, + } + + res, err := methods.CreateContainerView(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return NewContainerView(m.Client(), res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/view/task_view.go b/vendor/github.com/vmware/govmomi/view/task_view.go new file mode 100644 index 0000000000..4e1beef38c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/view/task_view.go @@ -0,0 +1,125 @@ +/* +Copyright (c) 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 view + +import ( + "context" + + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25/types" +) + +// TaskView extends ListView such that it can follow a ManagedEntity's recentTask updates. +type TaskView struct { + *ListView + + Follow bool + + Watch *types.ManagedObjectReference +} + +// CreateTaskView creates a new ListView that optionally watches for a ManagedEntity's recentTask updates. +func (m Manager) CreateTaskView(ctx context.Context, watch *types.ManagedObjectReference) (*TaskView, error) { + l, err := m.CreateListView(ctx, nil) + if err != nil { + return nil, err + } + + tv := &TaskView{ + ListView: l, + Watch: watch, + } + + return tv, nil +} + +// Collect calls function f for each Task update. +func (v TaskView) Collect(ctx context.Context, f func([]types.TaskInfo)) error { + // Using TaskHistoryCollector would be less clunky, but it isn't supported on ESX at all. + ref := v.Reference() + filter := new(property.WaitFilter).Add(ref, "Task", []string{"info"}, v.TraversalSpec()) + + if v.Watch != nil { + filter.Add(*v.Watch, v.Watch.Type, []string{"recentTask"}) + } + + pc := property.DefaultCollector(v.Client()) + + completed := make(map[string]bool) + + return property.WaitForUpdates(ctx, pc, filter, func(updates []types.ObjectUpdate) bool { + var infos []types.TaskInfo + var prune []types.ManagedObjectReference + var tasks []types.ManagedObjectReference + var reset func() + + for _, update := range updates { + for _, change := range update.ChangeSet { + if change.Name == "recentTask" { + tasks = change.Val.(types.ArrayOfManagedObjectReference).ManagedObjectReference + if len(tasks) != 0 { + reset = func() { + _, _ = v.Reset(ctx, tasks) + + // Remember any tasks we've reported as complete already, + // to avoid reporting multiple times when Reset is triggered. + rtasks := make(map[string]bool) + for i := range tasks { + if _, ok := completed[tasks[i].Value]; ok { + rtasks[tasks[i].Value] = true + } + } + completed = rtasks + } + } + + continue + } + + info, ok := change.Val.(types.TaskInfo) + if !ok { + continue + } + + if !completed[info.Task.Value] { + infos = append(infos, info) + } + + if v.Follow && info.CompleteTime != nil { + prune = append(prune, info.Task) + completed[info.Task.Value] = true + } + } + } + + if len(infos) != 0 { + f(infos) + } + + if reset != nil { + reset() + } else if len(prune) != 0 { + _, _ = v.Remove(ctx, prune) + } + + if len(tasks) != 0 && len(infos) == 0 { + return false + } + + return !v.Follow + }) +} diff --git a/vendor/github.com/vmware/govmomi/vim25/client.go b/vendor/github.com/vmware/govmomi/vim25/client.go new file mode 100644 index 0000000000..3daaf131a1 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/client.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2015-2023 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 vim25 + +import ( + "context" + "encoding/json" + "strings" + + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +const ( + Namespace = "vim25" + Version = "8.0.3.0" + Path = "/sdk" +) + +var ( + ServiceInstance = types.ManagedObjectReference{ + Type: "ServiceInstance", + Value: "ServiceInstance", + } +) + +// Client is a tiny wrapper around the vim25/soap Client that stores session +// specific state (i.e. state that only needs to be retrieved once after the +// client has been created). This means the client can be reused after +// serialization without performing additional requests for initialization. +type Client struct { + *soap.Client + + ServiceContent types.ServiceContent + + // RoundTripper is a separate field such that the client's implementation of + // the RoundTripper interface can be wrapped by separate implementations for + // extra functionality (for example, reauthentication on session timeout). + RoundTripper soap.RoundTripper +} + +// NewClient creates and returns a new client with the ServiceContent field +// filled in. +func NewClient(ctx context.Context, rt soap.RoundTripper) (*Client, error) { + c := Client{ + RoundTripper: rt, + } + + // Set client if it happens to be a soap.Client + if sc, ok := rt.(*soap.Client); ok { + c.Client = sc + + if c.Namespace == "" { + c.Namespace = "urn:" + Namespace + } else if !strings.Contains(c.Namespace, ":") { + c.Namespace = "urn:" + c.Namespace // ensure valid URI format + } + if c.Version == "" { + c.Version = Version + } + } + + var err error + c.ServiceContent, err = methods.GetServiceContent(ctx, rt) + if err != nil { + return nil, err + } + + return &c, nil +} + +// RoundTrip dispatches to the RoundTripper field. +func (c *Client) RoundTrip(ctx context.Context, req, res soap.HasFault) error { + return c.RoundTripper.RoundTrip(ctx, req, res) +} + +type marshaledClient struct { + SoapClient *soap.Client + ServiceContent types.ServiceContent +} + +func (c *Client) MarshalJSON() ([]byte, error) { + m := marshaledClient{ + SoapClient: c.Client, + ServiceContent: c.ServiceContent, + } + + return json.Marshal(m) +} + +func (c *Client) UnmarshalJSON(b []byte) error { + var m marshaledClient + + err := json.Unmarshal(b, &m) + if err != nil { + return err + } + + *c = Client{ + Client: m.SoapClient, + ServiceContent: m.ServiceContent, + RoundTripper: m.SoapClient, + } + + return nil +} + +// Valid returns whether or not the client is valid and ready for use. +// This should be called after unmarshalling the client. +func (c *Client) Valid() bool { + if c == nil { + return false + } + + if c.Client == nil { + return false + } + + // Use arbitrary pointer field in the service content. + // Doesn't matter which one, as long as it is populated by default. + if c.ServiceContent.SessionManager == nil { + return false + } + + return true +} + +// Path returns vim25.Path (see cache.Client) +func (c *Client) Path() string { + return Path +} + +// IsVC returns true if we are connected to a vCenter +func (c *Client) IsVC() bool { + return c.ServiceContent.About.ApiType == "VirtualCenter" +} diff --git a/vendor/github.com/vmware/govmomi/vim25/debug/debug.go b/vendor/github.com/vmware/govmomi/vim25/debug/debug.go new file mode 100644 index 0000000000..048062825d --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/debug/debug.go @@ -0,0 +1,73 @@ +/* +Copyright (c) 2014 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 debug + +import ( + "io" + "regexp" +) + +// Provider specified the interface types must implement to be used as a +// debugging sink. Having multiple such sink implementations allows it to be +// changed externally (for example when running tests). +type Provider interface { + NewFile(s string) io.WriteCloser + Flush() +} + +// ReadCloser is a struct that satisfies the io.ReadCloser interface +type ReadCloser struct { + io.Reader + io.Closer +} + +// NewTeeReader wraps io.TeeReader and patches through the Close() function. +func NewTeeReader(rc io.ReadCloser, w io.Writer) io.ReadCloser { + return ReadCloser{ + Reader: io.TeeReader(rc, w), + Closer: rc, + } +} + +var currentProvider Provider = nil +var scrubPassword = regexp.MustCompile(`(.*)`) + +func SetProvider(p Provider) { + if currentProvider != nil { + currentProvider.Flush() + } + currentProvider = p +} + +// Enabled returns whether debugging is enabled or not. +func Enabled() bool { + return currentProvider != nil +} + +// NewFile dispatches to the current provider's NewFile function. +func NewFile(s string) io.WriteCloser { + return currentProvider.NewFile(s) +} + +// Flush dispatches to the current provider's Flush function. +func Flush() { + currentProvider.Flush() +} + +func Scrub(in []byte) []byte { + return scrubPassword.ReplaceAll(in, []byte(`********`)) +} diff --git a/vendor/github.com/vmware/govmomi/vim25/debug/file.go b/vendor/github.com/vmware/govmomi/vim25/debug/file.go new file mode 100644 index 0000000000..4290a29167 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/debug/file.go @@ -0,0 +1,75 @@ +/* +Copyright (c) 2014 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 debug + +import ( + "io" + "os" + "path" + "sync" +) + +// FileProvider implements a debugging provider that creates a real file for +// every call to NewFile. It maintains a list of all files that it creates, +// such that it can close them when its Flush function is called. +type FileProvider struct { + Path string + + mu sync.Mutex + files []*os.File +} + +func (fp *FileProvider) NewFile(p string) io.WriteCloser { + f, err := os.Create(path.Join(fp.Path, p)) + if err != nil { + panic(err) + } + + fp.mu.Lock() + defer fp.mu.Unlock() + fp.files = append(fp.files, f) + + return NewFileWriterCloser(f, p) +} + +func (fp *FileProvider) Flush() { + fp.mu.Lock() + defer fp.mu.Unlock() + for _, f := range fp.files { + f.Close() + } +} + +type FileWriterCloser struct { + f *os.File + p string +} + +func NewFileWriterCloser(f *os.File, p string) *FileWriterCloser { + return &FileWriterCloser{ + f, + p, + } +} + +func (fwc *FileWriterCloser) Write(p []byte) (n int, err error) { + return fwc.f.Write(Scrub(p)) +} + +func (fwc *FileWriterCloser) Close() error { + return fwc.f.Close() +} diff --git a/vendor/github.com/vmware/govmomi/vim25/debug/log.go b/vendor/github.com/vmware/govmomi/vim25/debug/log.go new file mode 100644 index 0000000000..183c606a3c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/debug/log.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2014 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 debug + +import ( + "fmt" + "io" + "os" +) + +type LogWriterCloser struct { +} + +func NewLogWriterCloser() *LogWriterCloser { + return &LogWriterCloser{} +} + +func (lwc *LogWriterCloser) Write(p []byte) (n int, err error) { + fmt.Fprint(os.Stderr, string(Scrub(p))) + return len(p), nil +} + +func (lwc *LogWriterCloser) Close() error { + return nil +} + +type LogProvider struct { +} + +func (s *LogProvider) NewFile(p string) io.WriteCloser { + return NewLogWriterCloser() +} + +func (s *LogProvider) Flush() { +} diff --git a/vendor/github.com/vmware/govmomi/vim25/doc.go b/vendor/github.com/vmware/govmomi/vim25/doc.go new file mode 100644 index 0000000000..acb2c9f64d --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/doc.go @@ -0,0 +1,29 @@ +/* +Copyright (c) 2015 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 vim25 provides a minimal client implementation to use with other +packages in the vim25 tree. The code in this package intentionally does not +take any dependendies outside the vim25 tree. + +The client implementation in this package embeds the soap.Client structure. +Additionally, it stores the value of the session's ServiceContent object. This +object stores references to a variety of subsystems, such as the root property +collector, the session manager, and the search index. The client is fully +functional after serialization and deserialization, without the need for +additional requests for initialization. +*/ +package vim25 diff --git a/vendor/github.com/vmware/govmomi/vim25/json/LICENSE b/vendor/github.com/vmware/govmomi/vim25/json/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/vmware/govmomi/vim25/json/README.md b/vendor/github.com/vmware/govmomi/vim25/json/README.md new file mode 100644 index 0000000000..6cbe80349a --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/README.md @@ -0,0 +1,9 @@ +# JSON with Discriminators + +The source code in this directory was copied from Go 1.17.13's `encoding/json` package in order to add support for JSON discriminators. Please use the following command to review the diff: + +```shell +C1="$(git log --pretty=format:'%h' --no-patch --grep='Vendor Go 1.17.13 encoding/json')" && \ +C2="$(git log --pretty=format:'%h' --no-patch --grep='JSON Encoding w Discriminator Support')" && \ +git diff "${C1}".."${C2}" +``` diff --git a/vendor/github.com/vmware/govmomi/vim25/json/decode.go b/vendor/github.com/vmware/govmomi/vim25/json/decode.go new file mode 100644 index 0000000000..6a92a2410b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/decode.go @@ -0,0 +1,1319 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "encoding" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. If v is nil or not a pointer, +// Unmarshal returns an InvalidUnmarshalError. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a value implementing the Unmarshaler interface, +// Unmarshal calls that value's UnmarshalJSON method, including +// when the input is a JSON null. +// Otherwise, if the value implements encoding.TextUnmarshaler +// and the input is a JSON quoted string, Unmarshal calls that value's +// UnmarshalText method with the unquoted form of the string. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. By +// default, object keys which don't have a corresponding struct field are +// ignored (see Decoder.DisallowUnknownFields for an alternative). +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores +// key-value pairs from the JSON object into the map. The map's key type must +// either be any string type, an integer, implement json.Unmarshaler, or +// implement encoding.TextUnmarshaler. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. In any +// case, it's not guaranteed that all the remaining fields following +// the problematic one will be unmarshaled into the target object. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +// +func Unmarshal(data []byte, v interface{}) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + var d decodeState + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +// +// By convention, to approximate the behavior of Unmarshal itself, +// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes + Struct string // name of the struct type containing the field + Field string // the full path from root node to the field +} + +func (e *UnmarshalTypeError) Error() string { + if e.Struct != "" || e.Field != "" { + return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() + } + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// +// Deprecated: No longer used; kept for compatibility. +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Ptr { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v interface{}) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + d.scanWhile(scanSkipSpace) + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + err := d.value(rv) + if err != nil { + return d.addErrorContext(err) + } + return d.savedError +} + +// A Number represents a JSON number literal. +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext + savedError error + useNumber bool + disallowUnknownFields bool + + discriminatorTypeFieldName string + discriminatorValueFieldName string + discriminatorToTypeFn DiscriminatorToTypeFunc +} + +// readIndex returns the position of the last byte read. +func (d *decodeState) readIndex() int { + return d.off - 1 +} + +// phasePanicMsg is used as a panic message when we end up with something that +// shouldn't happen. It can indicate a bug in the JSON decoder, or that +// something is editing the data slice while the decoder executes. +const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } + return d +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = d.addErrorContext(err) + } +} + +// addErrorContext returns a new error enhanced with information from d.errorContext +func (d *decodeState) addErrorContext(err error) error { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { + switch err := err.(type) { + case *UnmarshalTypeError: + err.Struct = d.errorContext.Struct.Name() + err.Field = strings.Join(d.errorContext.FieldStack, ".") + } + } + return err +} + +// skip scans to the end of what was started. +func (d *decodeState) skip() { + s, data, i := &d.scan, d.data, d.off + depth := len(s.parseState) + for { + op := s.step(s, data[i]) + i++ + if len(s.parseState) < depth { + d.off = i + d.opcode = op + return + } + } +} + +// scanNext processes the byte at d.data[d.off]. +func (d *decodeState) scanNext() { + if d.off < len(d.data) { + d.opcode = d.scan.step(&d.scan, d.data[d.off]) + d.off++ + } else { + d.opcode = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +func (d *decodeState) scanWhile(op int) { + s, data, i := &d.scan, d.data, d.off + for i < len(data) { + newOp := s.step(s, data[i]) + i++ + if newOp != op { + d.opcode = newOp + d.off = i + return + } + } + + d.off = len(data) + 1 // mark processed EOF with len+1 + d.opcode = d.scan.eof() +} + +// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the +// common case where we're decoding a literal. The decoder scans the input +// twice, once for syntax errors and to check the length of the value, and the +// second to perform the decoding. +// +// Only in the second step do we use decodeState to tokenize literals, so we +// know there aren't any syntax errors. We can take advantage of that knowledge, +// and scan a literal's bytes much more quickly. +func (d *decodeState) rescanLiteral() { + data, i := d.data, d.off +Switch: + switch data[i-1] { + case '"': // string + for ; i < len(data); i++ { + switch data[i] { + case '\\': + i++ // escaped char + case '"': + i++ // tokenize the closing quote too + break Switch + } + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number + for ; i < len(data); i++ { + switch data[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '.', 'e', 'E', '+', '-': + default: + break Switch + } + } + case 't': // true + i += len("rue") + case 'f': // false + i += len("alse") + case 'n': // null + i += len("ull") + } + if i < len(data) { + d.opcode = stateEndValue(&d.scan, data[i]) + } else { + d.opcode = scanEnd + } + d.off = i + 1 +} + +// value consumes a JSON value from d.data[d.off-1:], decoding into v, and +// reads the following byte ahead. If v is invalid, the value is discarded. +// The first byte of the value has been read already. +func (d *decodeState) value(v reflect.Value) error { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray: + if v.IsValid() { + if err := d.array(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginObject: + if v.IsValid() { + if err := d.object(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginLiteral: + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + if v.IsValid() { + if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { + return err + } + } + } + return nil +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() interface{} { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray, scanBeginObject: + d.skip() + d.scanNext() + + case scanBeginLiteral: + v := d.literalInterface() + switch v.(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// If it encounters an Unmarshaler, indirect stops and returns that. +// If decodingNull is true, indirect stops at the first settable pointer so it +// can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // Issue #24153 indicates that it is generally not a guaranteed property + // that you may round-trip a reflect.Value by calling Value.Addr().Elem() + // and expect the value to still be settable for values derived from + // unexported embedded struct fields. + // + // The logic below effectively does this when it first addresses the value + // (to satisfy possible pointer methods) and continues to dereference + // subsequent pointers as necessary. + // + // After the first round-trip, we set v back to the original value to + // preserve the original RW flags contained in reflect.Value. + v0 := v + haveAddr := false + + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { + haveAddr = false + v = e + continue + } + } + + if v.Kind() != reflect.Ptr { + break + } + + if decodingNull && v.CanSet() { + break + } + + // Prevent infinite loop if v is an interface pointing to its own address: + // var v interface{} + // v = &v + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { + v = v.Elem() + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if !decodingNull { + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + } + + if haveAddr { + v = v0 // restore original value after round-trip Value.Addr().Elem() + haveAddr = false + } else { + v = v.Elem() + } + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into v. +// The first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + ai := d.arrayInterface() + v.Set(reflect.ValueOf(ai)) + return nil + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + case reflect.Array, reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + // Get element of array, growing if necessary. + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + if err := d.value(v.Index(i)); err != nil { + return err + } + } else { + // Ran out of fixed array: skip. + if err := d.value(reflect.Value{}); err != nil { + return err + } + } + i++ + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + // Array. Zero the rest. + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) + } + } else { + v.SetLen(i) + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } + return nil +} + +var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + +// object consumes an object from d.data[d.off-1:], decoding into v. +// The first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + t := v.Type() + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 && !d.isDiscriminatorSet() { + oi := d.objectInterface() + v.Set(reflect.ValueOf(oi)) + return nil + } + + var fields structFields + + // Check type of target: + // struct or + // map[T1]T2 where T1 is string, an integer type, + // or an encoding.TextUnmarshaler + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind, have an integer kind, + // or be an encoding.TextUnmarshaler. + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + fields = cachedTypeFields(t) + // ok + default: + if d.isDiscriminatorSet() { + return d.discriminatorInterfaceDecode(t, v) + } + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + + var mapElem reflect.Value + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } + + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquoteBytes(item) + if !ok { + panic(phasePanicMsg) + } + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := t.Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + if i, ok := fields.nameIndex[string(key)]; ok { + // Found an exact name match. + f = &fields.list[i] + } else { + // Fall back to the expensive case-insensitive + // linear search. + for i := range fields.list { + ff := &fields.list[i] + if ff.equalFold(ff.nameBytes, key) { + f = ff + break + } + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Ptr { + if subv.IsNil() { + // If a struct embeds a pointer to an unexported type, + // it is not possible to set a newly allocated value + // since the field is unexported. + // + // See https://golang.org/issue/21357 + if !subv.CanSet() { + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) + // Invalidate subv to ensure d.value(subv) skips over + // the JSON value without assigning it to subv. + subv = reflect.Value{} + destring = false + break + } + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } + d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) + d.errorContext.Struct = t + } else if d.disallowUnknownFields { + d.saveError(fmt.Errorf("json: unknown field %q", key)) + } + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + if err := d.literalStore(nullLiteral, subv, false); err != nil { + return err + } + case string: + if err := d.literalStore([]byte(qv), subv, true); err != nil { + return err + } + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + if err := d.value(subv); err != nil { + return err + } + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := t.Key() + var kv reflect.Value + switch { + case reflect.PtrTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(kt) + if err := d.literalStore(item, kv, true); err != nil { + return err + } + kv = kv.Elem() + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(kt) + default: + switch kt.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := string(key) + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s := string(key) + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + default: + panic("json: Unexpected key type") // should never occur + } + } + if kv.IsValid() { + if !d.isDiscriminatorSet() || kv.String() != d.discriminatorTypeFieldName { + v.SetMapIndex(kv, subv) + } + } + } + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return nil +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (interface{}, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeOf(Number("")) + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { + // Check for unmarshaler. + if len(item) == 0 { + //Empty string given + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + isNull := item[0] == 'n' // null + u, ut, pv := indirect(v, isNull) + if u != nil { + return u.UnmarshalJSON(item) + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + val := "number" + switch item[0] { + case 'n': + val = "null" + case 't', 'f': + val = "bool" + } + d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) + return nil + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + return ut.UnmarshalText(s) + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "null" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := item[0] == 't' + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "true" && string(item) != "false" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + if v.Type() == numberType && !isValidNumber(string(s)) { + return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) + } + v.SetString(string(s)) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + s := string(item) + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + // s must be a valid number, because it's + // already been tokenized. + v.SetString(s) + break + } + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Interface: + n, err := d.convertNumber(s) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(s, v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetFloat(n) + } + } + return nil +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() (val interface{}) { + switch d.opcode { + default: + panic(phasePanicMsg) + case scanBeginArray: + val = d.arrayInterface() + d.scanNext() + case scanBeginObject: + val = d.objectInterface() + d.scanNext() + case scanBeginLiteral: + val = d.literalInterface() + } + return +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []interface{} { + var v = make([]interface{}, 0) + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() map[string]interface{} { + m := make(map[string]interface{}) + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read string key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return m +} + +// literalInterface consumes and returns a literal from d.data[d.off-1:] and +// it reads the following byte ahead. The first byte of the literal has been +// read already (that's how the caller knows it's a literal). +func (d *decodeState) literalInterface() interface{} { + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + item := d.data[start:d.readIndex()] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + panic(phasePanicMsg) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) + } + return r +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/github.com/vmware/govmomi/vim25/json/discriminator.go b/vendor/github.com/vmware/govmomi/vim25/json/discriminator.go new file mode 100644 index 0000000000..ce315dd527 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/discriminator.go @@ -0,0 +1,568 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "fmt" + "reflect" + "regexp" + "strconv" + "sync" +) + +// DiscriminatorToTypeFunc is used to get a reflect.Type from its +// discriminator. +type DiscriminatorToTypeFunc func(discriminator string) (reflect.Type, bool) + +// TypeToDiscriminatorFunc is used to get a discriminator string from a +// reflect.Type. Empty return value suppresses discriminator rendering. +type TypeToDiscriminatorFunc func(reflect.Type) (discriminator string) + +// DefaultDiscriminatorFunc is shorthand for the ShortName func and is used when +// no other discriminator func is set explicitly +var DefaultDiscriminatorFunc = ShortName + +// ShortName returns the type name in golang without the package name +func ShortName(t reflect.Type) (discriminator string) { + tn := t.Name() + if tn == "" { + return t.String() + } + return tn +} + +// FullName return the name of the type prefixed with the package name as +// appropriate +func FullName(t reflect.Type) (discriminator string) { + tn := t.Name() + if tn == "" { + return t.String() + } + if pp := t.PkgPath(); pp != "" { + return fmt.Sprintf("%s.%s", pp, tn) + } + return tn +} + +// DiscriminatorEncodeMode is a mask that describes the different encode +// options. +type DiscriminatorEncodeMode uint8 + +const ( + // DiscriminatorEncodeTypeNameRootValue causes the type name to be encoded + // for the root value. + DiscriminatorEncodeTypeNameRootValue DiscriminatorEncodeMode = 1 << iota + + // DiscriminatorEncodeTypeNameAllObjects causes the type name to be encoded + // for all struct and map values. Please note this specifically does not + // apply to the root value. + DiscriminatorEncodeTypeNameAllObjects + + // DiscriminatorEncodeTypeNameIfRequired is the default behavior when + // the discriminator is set, and the type name is only encoded if required. + DiscriminatorEncodeTypeNameIfRequired DiscriminatorEncodeMode = 0 +) + +func (m DiscriminatorEncodeMode) root() bool { + return m&DiscriminatorEncodeTypeNameRootValue > 0 +} + +func (m DiscriminatorEncodeMode) all() bool { + return m&DiscriminatorEncodeTypeNameAllObjects > 0 +} + +func (d *decodeState) isDiscriminatorSet() bool { + return d.discriminatorTypeFieldName != "" && + d.discriminatorValueFieldName != "" +} + +// discriminatorOpType describes the current operation related to +// discriminators when reading a JSON object's fields. +type discriminatorOpType uint8 + +const ( + // discriminatorOpTypeNameField indicates the discriminator type name + // field was discovered. + discriminatorOpTypeNameField = iota + 1 + + // discriminatorOpValueField indicates the discriminator value field + // was discovered. + discriminatorOpValueField +) + +func (d *decodeState) discriminatorGetValue() (reflect.Value, error) { + // Record the current offset so we know where the data starts. + offset := d.readIndex() + + // Create a temporary decodeState used to inspect the current object + // and determine its discriminator type and decode its value. + dd := &decodeState{ + disallowUnknownFields: d.disallowUnknownFields, + useNumber: d.useNumber, + discriminatorToTypeFn: d.discriminatorToTypeFn, + discriminatorTypeFieldName: d.discriminatorTypeFieldName, + discriminatorValueFieldName: d.discriminatorValueFieldName, + } + dd.init(append([]byte{}, d.data[offset:]...)) + defer freeScanner(&dd.scan) + dd.scan.reset() + + var ( + t reflect.Type // the instance of the type + valueOff = -1 // the offset of a possible discriminator value + ) + + dd.scanWhile(scanSkipSpace) + if dd.opcode != scanBeginObject { + panic(phasePanicMsg) + } + + for { + dd.scanWhile(scanSkipSpace) + if dd.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if dd.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read key. + start := dd.readIndex() + dd.rescanLiteral() + item := dd.data[start:dd.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Check to see if the key is related to the discriminator. + var discriminatorOp discriminatorOpType + switch key { + case d.discriminatorTypeFieldName: + discriminatorOp = discriminatorOpTypeNameField + case d.discriminatorValueFieldName: + discriminatorOp = discriminatorOpValueField + } + + // Read : before value. + if dd.opcode == scanSkipSpace { + dd.scanWhile(scanSkipSpace) + } + + if dd.opcode != scanObjectKey { + panic(phasePanicMsg) + } + dd.scanWhile(scanSkipSpace) + + // Read value. + valOff := dd.readIndex() + val := dd.valueInterface() + + switch discriminatorOp { + case discriminatorOpTypeNameField: + tn, ok := val.(string) + if !ok { + return reflect.Value{}, fmt.Errorf( + "json: discriminator type at offset %d is not string", + offset+valOff) + } + if tn == "" { + return reflect.Value{}, fmt.Errorf( + "json: discriminator type at offset %d is empty", + offset+valOff) + } + + // Parse the type name into a type instance. + ti, err := discriminatorParseTypeName(tn, d.discriminatorToTypeFn) + if err != nil { + return reflect.Value{}, err + } + + // Assign the type instance to the outer variable, t. + t = ti + + // Primitive types and types with Unmarshaler are wrapped in a + // structure with type and value fields. Structures and Maps not + // implementing Unmarshaler use discriminator embedded within their + // content. + if useNestedDiscriminator(t) { + // If the type is a map or a struct not implementing Unmarshaler + // then it is not necessary to continue walking over the current + // JSON object since it will be completely re-scanned to decode + // its value into the discovered type. + dd.opcode = scanEndObject + } else { + // Otherwise if the value offset has been discovered then it is + // safe to stop walking over the current JSON object as well. + if valueOff > -1 { + dd.opcode = scanEndObject + } + } + case discriminatorOpValueField: + valueOff = valOff + + // If the type has been discovered then it is safe to stop walking + // over the current JSON object. + if t != nil { + dd.opcode = scanEndObject + } + } + + // Next token must be , or }. + if dd.opcode == scanSkipSpace { + dd.scanWhile(scanSkipSpace) + } + if dd.opcode == scanEndObject { + break + } + if dd.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + + // If there is not a type discriminator then return early. + if t == nil { + return reflect.Value{}, fmt.Errorf("json: missing discriminator") + } + + // Instantiate a new instance of the discriminated type. + var v reflect.Value + switch t.Kind() { + case reflect.Slice: + // MakeSlice returns a value that is not addressable. + // Instead, use MakeSlice to get the type, then use + // reflect.New to create an addressable value. + v = reflect.New(reflect.MakeSlice(t, 0, 0).Type()).Elem() + case reflect.Map: + // MakeMap returns a value that is not addressable. + // Instead, use MakeMap to get the type, then use + // reflect.New to create an addressable value. + v = reflect.New(reflect.MakeMap(t).Type()).Elem() + case reflect.Complex64, reflect.Complex128: + return reflect.Value{}, fmt.Errorf("json: unsupported discriminator type: %s", t.Kind()) + default: + v = reflect.New(t) + } + + // Reset the decode state to prepare for decoding the data. + dd.scan.reset() + + if useNestedDiscriminator(t) { + // Set the offset to zero since the entire object will be decoded + // into v. + dd.off = 0 + } else { + // Set the offset to what it was before the discriminator value was + // read so only the value field is decoded into v. + dd.off = valueOff + } + // This will initialize the correct scan step and op code. + dd.scanWhile(scanSkipSpace) + + // Decode the data into the value. + if err := dd.value(v); err != nil { + return reflect.Value{}, err + } + + // Check the saved error as well since the decoder.value function does not + // always return an error. If the reflected value is still zero, then it is + // likely the decoder was unable to decode the value. + if err := dd.savedError; err != nil { + switch v.Kind() { + case reflect.Ptr, reflect.Interface: + v = v.Elem() + } + if v.IsZero() { + return reflect.Value{}, err + } + } + + return v, nil +} + +func (d *decodeState) discriminatorInterfaceDecode(t reflect.Type, v reflect.Value) error { + + defer func() { + // Advance the decode state, throwing away the value. + _ = d.objectInterface() + }() + + dv, err := d.discriminatorGetValue() + if err != nil { + return err + } + + switch dv.Kind() { + case reflect.Map, reflect.Slice: + if dv.Type().AssignableTo(t) { + v.Set(dv) + return nil + } + if pdv := dv.Addr(); pdv.Type().AssignableTo(t) { + v.Set(pdv) + return nil + } + case reflect.Ptr: + if dve := dv.Elem(); dve.Type().AssignableTo(t) { + v.Set(dve) + return nil + } + if dv.Type().AssignableTo(t) { + v.Set(dv) + return nil + } + } + + return fmt.Errorf("json: unsupported discriminator kind: %s", dv.Kind()) +} + +func (o encOpts) isDiscriminatorSet() bool { + return o.discriminatorTypeFieldName != "" && + o.discriminatorValueFieldName != "" +} + +func discriminatorInterfaceEncode(e *encodeState, v reflect.Value, opts encOpts) { + v = v.Elem() + + if v.Type().Implements(marshalerType) { + discriminatorValue := opts.discriminatorValueFn(v.Type()) + if discriminatorValue == "" { + marshalerEncoder(e, v, opts) + } + e.WriteString(`{"`) + e.WriteString(opts.discriminatorTypeFieldName) + e.WriteString(`":"`) + e.WriteString(discriminatorValue) + e.WriteString(`","`) + e.WriteString(opts.discriminatorValueFieldName) + e.WriteString(`":`) + marshalerEncoder(e, v, opts) + e.WriteByte('}') + return + } + + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Invalid: + e.error(&UnsupportedValueError{v, fmt.Sprintf("invalid kind: %s", v.Kind())}) + case reflect.Map: + e.discriminatorEncodeTypeName = true + newMapEncoder(v.Type())(e, v, opts) + case reflect.Struct: + e.discriminatorEncodeTypeName = true + newStructEncoder(v.Type())(e, v, opts) + case reflect.Ptr: + discriminatorInterfaceEncode(e, v, opts) + default: + discriminatorValue := opts.discriminatorValueFn(v.Type()) + if discriminatorValue == "" { + e.reflectValue(v, opts) + return + } + e.WriteString(`{"`) + e.WriteString(opts.discriminatorTypeFieldName) + e.WriteString(`":"`) + e.WriteString(discriminatorValue) + e.WriteString(`","`) + e.WriteString(opts.discriminatorValueFieldName) + e.WriteString(`":`) + e.reflectValue(v, opts) + e.WriteByte('}') + } +} + +func discriminatorMapEncode(e *encodeState, v reflect.Value, opts encOpts) { + if !e.discriminatorEncodeTypeName && !opts.discriminatorEncodeMode.all() { + return + } + discriminatorValue := opts.discriminatorValueFn(v.Type()) + if discriminatorValue == "" { + return + } + e.WriteByte('"') + e.WriteString(opts.discriminatorTypeFieldName) + e.WriteString(`":"`) + e.WriteString(discriminatorValue) + e.WriteByte('"') + if v.Len() > 0 { + e.WriteByte(',') + } + e.discriminatorEncodeTypeName = false +} + +func discriminatorStructEncode(e *encodeState, v reflect.Value, opts encOpts) byte { + if !e.discriminatorEncodeTypeName && !opts.discriminatorEncodeMode.all() { + return '{' + } + discriminatorValue := opts.discriminatorValueFn(v.Type()) + if discriminatorValue == "" { + return '{' + } + e.WriteString(`{"`) + e.WriteString(opts.discriminatorTypeFieldName) + e.WriteString(`":"`) + e.WriteString(discriminatorValue) + e.WriteByte('"') + e.discriminatorEncodeTypeName = false + return ',' +} + +var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() + +// Discriminator is nested in map and struct unless they implement Unmarshaler. +func useNestedDiscriminator(t reflect.Type) bool { + if t.Implements(unmarshalerType) || reflect.PtrTo(t).Implements(unmarshalerType) { + return false + } + kind := t.Kind() + if kind == reflect.Struct || kind == reflect.Map { + return true + } + return false +} + +var discriminatorTypeRegistry = map[string]reflect.Type{ + "uint": reflect.TypeOf(uint(0)), + "uint8": reflect.TypeOf(uint8(0)), + "uint16": reflect.TypeOf(uint16(0)), + "uint32": reflect.TypeOf(uint32(0)), + "uint64": reflect.TypeOf(uint64(0)), + "uintptr": reflect.TypeOf(uintptr(0)), + "int": reflect.TypeOf(int(0)), + "int8": reflect.TypeOf(int8(0)), + "int16": reflect.TypeOf(int16(0)), + "int32": reflect.TypeOf(int32(0)), + "int64": reflect.TypeOf(int64(0)), + "float32": reflect.TypeOf(float32(0)), + "float64": reflect.TypeOf(float64(0)), + "bool": reflect.TypeOf(true), + "string": reflect.TypeOf(""), + "any": reflect.TypeOf((*interface{})(nil)).Elem(), + "interface{}": reflect.TypeOf((*interface{})(nil)).Elem(), + "interface {}": reflect.TypeOf((*interface{})(nil)).Elem(), + + // Not supported, but here to prevent the decoder from panicing + // if encountered. + "complex64": reflect.TypeOf(complex64(0)), + "complex128": reflect.TypeOf(complex128(0)), +} + +// discriminatorPointerTypeCache caches the pointer type for another type. +// For example, a key that was the int type would have a value that is the +// *int type. +var discriminatorPointerTypeCache sync.Map // map[reflect.Type]reflect.Type + +// cachedPointerType returns the pointer type for another and avoids repeated +// work by using a cache. +func cachedPointerType(t reflect.Type) reflect.Type { + if value, ok := discriminatorPointerTypeCache.Load(t); ok { + return value.(reflect.Type) + } + pt := reflect.New(t).Type() + value, _ := discriminatorPointerTypeCache.LoadOrStore(t, pt) + return value.(reflect.Type) +} + +var ( + mapPatt = regexp.MustCompile(`^\*?map\[([^\]]+)\](.+)$`) + arrayPatt = regexp.MustCompile(`^\*?\[(\d+)\](.+)$`) + slicePatt = regexp.MustCompile(`^\*?\[\](.+)$`) +) + +// discriminatorParseTypeName returns a reflect.Type for the given type name. +func discriminatorParseTypeName( + typeName string, + typeFn DiscriminatorToTypeFunc) (reflect.Type, error) { + + // Check to see if the type is an array, map, or slice. + var ( + aln = -1 // array length + etn string // map or slice element type name + ktn string // map key type name + ) + if m := arrayPatt.FindStringSubmatch(typeName); len(m) > 0 { + i, err := strconv.Atoi(m[1]) + if err != nil { + return nil, err + } + aln = i + etn = m[2] + } else if m := slicePatt.FindStringSubmatch(typeName); len(m) > 0 { + etn = m[1] + } else if m := mapPatt.FindStringSubmatch(typeName); len(m) > 0 { + ktn = m[1] + etn = m[2] + } + + // indirectTypeName checks to see if the type name begins with a + // "*" characters. If it does, then the type name sans the "*" + // character is returned along with a true value indicating the + // type is a pointer. Otherwise the original type name is returned + // along with a false value. + indirectTypeName := func(tn string) (string, bool) { + if len(tn) > 1 && tn[0] == '*' { + return tn[1:], true + } + return tn, false + } + + lookupType := func(tn string) (reflect.Type, bool) { + // Get the actual type name and a flag indicating whether the + // type is a pointer. + n, p := indirectTypeName(tn) + + var t reflect.Type + ok := false + // look up the type in the external registry to allow name override. + if typeFn != nil { + t, ok = typeFn(n) + } + if !ok { + // Use the built-in registry if the external registry fails + if t, ok = discriminatorTypeRegistry[n]; !ok { + return nil, false + } + } + // If the type was a pointer then get the type's pointer type. + if p { + t = cachedPointerType(t) + } + return t, true + } + + var t reflect.Type + + if ktn == "" && etn != "" { + et, ok := lookupType(etn) + if !ok { + return nil, fmt.Errorf("json: invalid array/slice element type: %s", etn) + } + if aln > -1 { + // Array + t = reflect.ArrayOf(aln, et) + } else { + // Slice + t = reflect.SliceOf(et) + } + } else if ktn != "" && etn != "" { + // Map + kt, ok := lookupType(ktn) + if !ok { + return nil, fmt.Errorf("json: invalid map key type: %s", ktn) + } + et, ok := lookupType(etn) + if !ok { + return nil, fmt.Errorf("json: invalid map element type: %s", etn) + } + t = reflect.MapOf(kt, et) + } else { + var ok bool + if t, ok = lookupType(typeName); !ok { + return nil, fmt.Errorf("json: invalid discriminator type: %s", typeName) + } + } + + return t, nil +} diff --git a/vendor/github.com/vmware/govmomi/vim25/json/encode.go b/vendor/github.com/vmware/govmomi/vim25/json/encode.go new file mode 100644 index 0000000000..0c8aa202fe --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/encode.go @@ -0,0 +1,1453 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package json implements encoding and decoding of JSON as defined in +// RFC 7159. The mapping between JSON and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method and encodes the result as a JSON string. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// So that the JSON will be safe to embed inside HTML