mirror of https://github.com/docker/docs.git
				
				
				
			Dependencies update
Signed-off-by: Fabio Rapposelli <fabio@vmware.com>
This commit is contained in:
		
							parent
							
								
									2e90b7cb55
								
							
						
					
					
						commit
						e7c0ebab5e
					
				|  | @ -181,6 +181,11 @@ | |||
| 		{ | ||||
| 			"ImportPath": "google.golang.org/cloud/internal", | ||||
| 			"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "github.com/vmware/govmomi", | ||||
| 			"Comment": "prerelease-v0.1.0-73-gfc131d4-65-g482cd82", | ||||
| 			"Rev": "482cd823716e0fa9bc4e186d262a6ea23d940fbf" | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,10 @@ | |||
| sudo: false | ||||
| language: go | ||||
| go: 1.4 | ||||
| 
 | ||||
| before_install: | ||||
|   - go get golang.org/x/tools/cmd/vet | ||||
|   - go get golang.org/x/tools/cmd/goimports | ||||
| 
 | ||||
| script: | ||||
|   - make check test | ||||
|  | @ -0,0 +1,43 @@ | |||
| # changelog | ||||
| 
 | ||||
| ### (unreleased) | ||||
| 
 | ||||
| ... | ||||
| 
 | ||||
| * Stop returning children from `ManagedObjectList` | ||||
| 
 | ||||
|     Change the `ManagedObjectList` function in the `find` package to only | ||||
|     return the managed objects specified by the path argument and not their | ||||
|     children. The original behavior was used by govc's `ls` command and is | ||||
|     now available in the newly added function `ManagedObjectListChildren`. | ||||
| 
 | ||||
| * Add retry functionality to vim25 package | ||||
| 
 | ||||
| * Change finder functions to no longer take varargs | ||||
| 
 | ||||
|     The `find` package had functions to return a list of objects, given a | ||||
|     variable number of patterns. This makes it impossible to distinguish which | ||||
|     patterns produced results and which ones didn't. | ||||
| 
 | ||||
|     In particular for govc, where multiple arguments can be passed from the | ||||
|     command line, it is useful to let the user know which ones produce results | ||||
|     and which ones don't. | ||||
| 
 | ||||
|     To evaluate multiple patterns, the user should call the find functions | ||||
|     multiple times (either serially or in parallel). | ||||
| 
 | ||||
| * Make optional boolean fields pointers (`vim25/types`). | ||||
| 
 | ||||
|     False is the zero value of a boolean field, which means they are not serialized | ||||
|     if the field is marked "omitempty". If the field is a pointer instead, the zero | ||||
|     value will be the nil pointer, and both true and false values are serialized. | ||||
| 
 | ||||
| ### 0.1.0 (2015-03-17) | ||||
| 
 | ||||
| Prior to this version the API of this library was in flux. | ||||
| 
 | ||||
| Notable changes w.r.t. the state of this library before March 2015 are: | ||||
| 
 | ||||
| * All functions that may execute a request take a `context.Context` parameter. | ||||
| * The `vim25` package contains a minimal client implementation. | ||||
| * The property collector and its convenience functions live in the `property` package. | ||||
|  | @ -0,0 +1,22 @@ | |||
| # People who can (and typically have) contributed to this repository. | ||||
| # | ||||
| # Please keep the list sorted. | ||||
| # | ||||
| 
 | ||||
| Alvaro Miranda <kikitux@gmail.com> | ||||
| Bob Killen <killen.bob@gmail.com> | ||||
| Bruce Downs <bdowns@vmware.com> | ||||
| Clint Greenwood <cgreenwood@vmware.com> <clint.greenwood@gmail.com> | ||||
| Danny Lockard <danny.lockard@banno.com> | ||||
| Doug MacEachern <dougm@vmware.com> | ||||
| Eric Yutao <eric.yutao@gmail.com> | ||||
| Faiyaz Ahmed <ahmedf@vmware.com> | ||||
| Gavin Gray <gavin@infinio.com> | ||||
| Gavrie Philipson <gavrie@philipson.co.il> <gavrie.philipson@elastifile.com> | ||||
| Mevan Samaratunga <mevansam@gmail.com> | ||||
| Pieter Noordhuis <pnoordhuis@vmware.com> <pcnoordhuis@gmail.com> | ||||
| S.Çağlar Onur <conur@vmware.com> | ||||
| Takaaki Furukawa <takaaki.frkw@gmail.com> | ||||
| Yang Yang <yangy@vmware.com> | ||||
| Yuya Kusakabe <yuya.kusakabe@gmail.com> | ||||
| Zee Yang <zeey@vmware.com> <zee.yang@gmail.com> | ||||
|  | @ -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. | ||||
|  | @ -0,0 +1,20 @@ | |||
| .PHONY: test | ||||
| 
 | ||||
| all: check test | ||||
| 
 | ||||
| check: goimports govet | ||||
| 
 | ||||
| goimports: | ||||
| 	@echo checking go imports... | ||||
| 	@! goimports -d . 2>&1 | egrep -v '^$$' | ||||
| 
 | ||||
| govet: | ||||
| 	@echo checking go vet... | ||||
| 	@go tool vet -structtags=false -methods=false . | ||||
| 
 | ||||
| test: | ||||
| 	go get | ||||
| 	go test -v $(TEST_OPTS) ./... | ||||
| 
 | ||||
| install: | ||||
| 	go install github.com/vmware/govmomi/govc | ||||
|  | @ -0,0 +1,36 @@ | |||
| [](https://travis-ci.org/vmware/govmomi) | ||||
| 
 | ||||
| # govmomi | ||||
| 
 | ||||
| A Go library for interacting with VMware vSphere APIs (ESXi and/or vCenter). | ||||
| 
 | ||||
| For `govc`, a CLI built on top of govmomi, check out the [govc](./govc) directory. | ||||
| 
 | ||||
| ## Compatibility | ||||
| 
 | ||||
| This library is built for and tested against ESXi and vCenter 5.5. | ||||
| 
 | ||||
| If you're able to use it against older versions of ESXi and/or vCenter, please | ||||
| leave a note and we'll include it in this compatibility list. | ||||
| 
 | ||||
| ## Documentation | ||||
| 
 | ||||
| The APIs exposed by this library very closely follow the API described in the [VMware vSphere API Reference Documentation][apiref]. | ||||
| Refer to this document 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][godoc] for documentation. | ||||
| 
 | ||||
| [apiref]:http://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/right-pane.html | ||||
| [godoc]:http://godoc.org/github.com/vmware/govmomi | ||||
| 
 | ||||
| ## Status | ||||
| 
 | ||||
| Changes to the API are subject to [semantic versioning](http://semver.org). | ||||
| 
 | ||||
| Refer to the [CHANGELOG](CHANGELOG.md) for version to version changes. | ||||
| 
 | ||||
| ## License | ||||
| 
 | ||||
| govmomi is available under the [Apache 2 license](LICENSE). | ||||
|  | @ -0,0 +1,131 @@ | |||
| /* | ||||
| 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. | ||||
| */ | ||||
| 
 | ||||
| /* | ||||
| 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 ( | ||||
| 	"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" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type Client struct { | ||||
| 	*vim25.Client | ||||
| 
 | ||||
| 	SessionManager *session.Manager | ||||
| } | ||||
| 
 | ||||
| // NewClient creates a new client from a URL. The client authenticates with the
 | ||||
| // server 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) | ||||
| } | ||||
|  | @ -0,0 +1,43 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # 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. | ||||
| 
 | ||||
| set -e | ||||
| 
 | ||||
| # This script shows for every request in a debug trace how long it took | ||||
| # and the name of the request body. | ||||
| 
 | ||||
| function body-name { | ||||
|   ( | ||||
|     xmllint --shell $1 <<EOS | ||||
|     setns soapenv=http://schemas.xmlsoap.org/soap/envelope/ | ||||
|     xpath name(//soapenv:Body/*) | ||||
| EOS | ||||
|   )  | head -1 | sed 's/.*Object is a string : \(.*\)$/\1/' | ||||
| } | ||||
| 
 | ||||
| if [ -n "$1" ]; then | ||||
|   cd $1 | ||||
| fi | ||||
| 
 | ||||
| for req in $(find . -name '*.req.xml'); do | ||||
|   base=$(basename $req .req.xml) | ||||
|   session=$(echo $base | awk -F'-' "{printf \"%d\", \$1}") | ||||
|   number=$(echo $base | awk -F'-' "{printf \"%d\", \$2}") | ||||
|   client_log=$(dirname $req)/${session}-client.log | ||||
|   took=$(awk "/ ${number} took / { print \$4 }" ${client_log}) | ||||
| 
 | ||||
|   printf "%s %8s: %s\n" ${base} ${took} $(body-name $req) | ||||
| done | ||||
|  | @ -0,0 +1,3 @@ | |||
| *.box | ||||
| *.ova | ||||
| .vagrant | ||||
|  | @ -0,0 +1,13 @@ | |||
| # -*- mode: ruby -*- | ||||
| # vi: set ft=ruby : | ||||
| 
 | ||||
| # Using the VCSA base box, no provisioning, inventory will be empty. | ||||
| 
 | ||||
| Vagrant.configure("2") do |config| | ||||
|   config.vm.hostname = "vcsa" | ||||
| 
 | ||||
|   config.vm.box = "vcsa" | ||||
|   config.vm.synced_folder ".", "/vagrant", disabled: true | ||||
| 
 | ||||
|   config.vm.network "forwarded_port", guest: 443, host: 16443 | ||||
| end | ||||
							
								
								
									
										73
									
								
								vendor/github.com/vmware/govmomi/contrib/vagrant/vcsa/create-box.sh
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										73
									
								
								vendor/github.com/vmware/govmomi/contrib/vagrant/vcsa/create-box.sh
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,73 @@ | |||
| #!/bin/bash -e | ||||
| 
 | ||||
| if [ "$(uname -s)" == "Darwin" ] | ||||
| then | ||||
|   PATH="/Applications/VMware Fusion.app/Contents/Library:$PATH" | ||||
|   PATH="/Applications/VMware Fusion.app/Contents/Library/VMware OVF Tool:$PATH" | ||||
| fi | ||||
| 
 | ||||
| ovf="$1" | ||||
| 
 | ||||
| if [ -z "$ovf" ] | ||||
| then | ||||
|   ovf="./VMware-vCenter-Server-Appliance-5.5.0.10300-2000350_OVA10.ova" | ||||
| fi | ||||
| 
 | ||||
| dir=$(readlink -nf $(dirname $0)) | ||||
| 
 | ||||
| tmp=$(mktemp -d) | ||||
| trap "rm -rf $tmp" EXIT | ||||
| 
 | ||||
| cd $tmp | ||||
| 
 | ||||
| echo "Converting ovf..." | ||||
| ovftool $ovf ./vcsa.vmx | ||||
| 
 | ||||
| echo "Starting vm..." | ||||
| vmrun start vcsa.vmx nogui | ||||
| 
 | ||||
| echo "Waiting for vm ip..." | ||||
| ip=$(vmrun getGuestIPAddress vcsa.vmx -wait) | ||||
| 
 | ||||
| echo "Configuring vm for use with vagrant..." | ||||
| vmrun -gu root -gp vmware CopyFileFromHostToGuest vcsa.vmx \ | ||||
|       $dir/vagrant.sh /tmp/vagrant.sh | ||||
| 
 | ||||
| vmrun -gu root -gp vmware runProgramInGuest vcsa.vmx \ | ||||
|       /bin/sh -e /tmp/vagrant.sh | ||||
| 
 | ||||
| vmrun -gu root -gp vmware deleteFileInGuest vcsa.vmx \ | ||||
|       /tmp/vagrant.sh | ||||
| 
 | ||||
| echo "Configuring vCenter Server Appliance..." | ||||
| 
 | ||||
| ssh_opts="-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oLogLevel=quiet" | ||||
| 
 | ||||
| ssh ${ssh_opts} -i ~/.vagrant.d/insecure_private_key vagrant@$ip <<EOF | ||||
| echo "Accepting EULA ..." | ||||
| sudo /usr/sbin/vpxd_servicecfg eula accept | ||||
| 
 | ||||
| echo "Configuring Embedded DB ..." | ||||
| sudo /usr/sbin/vpxd_servicecfg db write embedded | ||||
| 
 | ||||
| echo "Configuring SSO..." | ||||
| sudo /usr/sbin/vpxd_servicecfg sso write embedded | ||||
| 
 | ||||
| echo "Starting VCSA ..." | ||||
| sudo /usr/sbin/vpxd_servicecfg service start | ||||
| EOF | ||||
| 
 | ||||
| echo "Stopping vm..." | ||||
| vmrun stop vcsa.vmx | ||||
| 
 | ||||
| rm -f vmware.log | ||||
| 
 | ||||
| perl -pi -e 's/"bridged"/"nat"/' vcsa.vmx | ||||
| 
 | ||||
| echo '{"provider":"vmware_desktop"}' > ./metadata.json | ||||
| 
 | ||||
| cd $dir | ||||
| 
 | ||||
| tar -C $tmp -cvzf vcsa.box . | ||||
| 
 | ||||
| vagrant box add --name vcsa vcsa.box | ||||
|  | @ -0,0 +1,24 @@ | |||
| #!/bin/sh | ||||
| 
 | ||||
| useradd vagrant -m -s /bin/bash | ||||
| groupmod -A vagrant wheel | ||||
| 
 | ||||
| echo -e "vagrant ALL=(ALL) NOPASSWD: ALL\n" >> /etc/sudoers | ||||
| 
 | ||||
| mkdir ~vagrant/.ssh | ||||
| wget --no-check-certificate \ | ||||
|      https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub \ | ||||
|      -O ~vagrant/.ssh/authorized_keys | ||||
| chown -R vagrant ~vagrant/.ssh | ||||
| chmod -R go-rwsx ~vagrant/.ssh | ||||
| 
 | ||||
| perl -pi -e 's/^#UseDNS yes/UseDNS no/' /etc/ssh/sshd_config | ||||
| perl -pi -e 's/^AllowTcpForwarding no//' /etc/ssh/sshd_config | ||||
| perl -pi -e 's/^PermitTunnel no//' /etc/ssh/sshd_config | ||||
| perl -pi -e 's/^MaxSessions \d+//' /etc/ssh/sshd_config | ||||
| 
 | ||||
| # disable password expiration | ||||
| for uid in root vagrant | ||||
| do | ||||
|   chage -I -1 -E -1 -m 0 -M -1 $uid | ||||
| done | ||||
|  | @ -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 event | ||||
| 
 | ||||
| import ( | ||||
| 	"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" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type HistoryCollector struct { | ||||
| 	*object.HistoryCollector | ||||
| } | ||||
| 
 | ||||
| func NewHistoryCollector(c *vim25.Client, ref types.ManagedObjectReference) *HistoryCollector { | ||||
| 	return &HistoryCollector{ | ||||
| 		HistoryCollector: object.NewHistoryCollector(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 int) ([]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 int) ([]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 | ||||
| } | ||||
|  | @ -0,0 +1,162 @@ | |||
| /* | ||||
| 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 event | ||||
| 
 | ||||
| import ( | ||||
| 	"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" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type Manager struct { | ||||
| 	reference types.ManagedObjectReference | ||||
| 
 | ||||
| 	c *vim25.Client | ||||
| 
 | ||||
| 	eventCategory   map[string]string | ||||
| 	eventCategoryMu *sync.Mutex | ||||
| } | ||||
| 
 | ||||
| func NewManager(c *vim25.Client) *Manager { | ||||
| 	m := Manager{ | ||||
| 		reference: *c.ServiceContent.EventManager, | ||||
| 
 | ||||
| 		c: c, | ||||
| 
 | ||||
| 		eventCategoryMu: new(sync.Mutex), | ||||
| 	} | ||||
| 
 | ||||
| 	return &m | ||||
| } | ||||
| 
 | ||||
| func (m Manager) CreateCollectorForEvents(ctx context.Context, filter types.EventFilterSpec) (*HistoryCollector, error) { | ||||
| 	req := types.CreateCollectorForEvents{ | ||||
| 		This:   m.reference, | ||||
| 		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.reference, | ||||
| 		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.reference, | ||||
| 		EventToPost: eventToPost, | ||||
| 		TaskInfo:    &taskInfo, | ||||
| 	} | ||||
| 
 | ||||
| 	_, 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.reference, | ||||
| 		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.reference, | ||||
| 		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 m.eventCategory != nil { | ||||
| 		return m.eventCategory, nil | ||||
| 	} | ||||
| 
 | ||||
| 	var o mo.EventManager | ||||
| 
 | ||||
| 	ps := []string{"description.eventInfo"} | ||||
| 	err := property.DefaultCollector(m.c).RetrieveOne(ctx, m.reference, ps, &o) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	m.eventCategory = make(map[string]string, len(o.Description.EventInfo)) | ||||
| 
 | ||||
| 	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 | ||||
| 	} | ||||
| 
 | ||||
| 	class := reflect.TypeOf(event).Elem().Name() | ||||
| 
 | ||||
| 	return eventCategory[class], nil | ||||
| } | ||||
|  | @ -0,0 +1,45 @@ | |||
| /* | ||||
| 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 event | ||||
| 
 | ||||
| import ( | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| ) | ||||
| 
 | ||||
| // Sort events in accending 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] | ||||
| } | ||||
|  | @ -0,0 +1,180 @@ | |||
| /* | ||||
| 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. | ||||
| */ | ||||
| 
 | ||||
| /* | ||||
| This example program shows how the `finder` and `property` packages can | ||||
| be used to navigate a vSphere inventory structure using govmomi. | ||||
| */ | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi" | ||||
| 	"github.com/vmware/govmomi/find" | ||||
| 	"github.com/vmware/govmomi/property" | ||||
| 	"github.com/vmware/govmomi/units" | ||||
| 	"github.com/vmware/govmomi/vim25/mo" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| // GetEnvString returns string from environment variable.
 | ||||
| func GetEnvString(v string, def string) string { | ||||
| 	r := os.Getenv(v) | ||||
| 	if r == "" { | ||||
| 		return def | ||||
| 	} | ||||
| 
 | ||||
| 	return r | ||||
| } | ||||
| 
 | ||||
| // GetEnvBool returns boolean from environment variable.
 | ||||
| func GetEnvBool(v string, def bool) bool { | ||||
| 	r := os.Getenv(v) | ||||
| 	if r == "" { | ||||
| 		return def | ||||
| 	} | ||||
| 
 | ||||
| 	switch strings.ToLower(r[0:1]) { | ||||
| 	case "t", "y", "1": | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	envURL      = "GOVMOMI_URL" | ||||
| 	envUserName = "GOVMOMI_USERNAME" | ||||
| 	envPassword = "GOVMOMI_PASSWORD" | ||||
| 	envInsecure = "GOVMOMI_INSECURE" | ||||
| ) | ||||
| 
 | ||||
| var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL) | ||||
| var urlFlag = flag.String("url", GetEnvString(envURL, "https://username:password@host/sdk"), urlDescription) | ||||
| 
 | ||||
| var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure) | ||||
| var insecureFlag = flag.Bool("insecure", GetEnvBool(envInsecure, false), insecureDescription) | ||||
| 
 | ||||
| func processOverride(u *url.URL) { | ||||
| 	envUsername := os.Getenv(envUserName) | ||||
| 	envPassword := os.Getenv(envPassword) | ||||
| 
 | ||||
| 	// Override username if provided
 | ||||
| 	if envUsername != "" { | ||||
| 		var password string | ||||
| 		var ok bool | ||||
| 
 | ||||
| 		if u.User != nil { | ||||
| 			password, ok = u.User.Password() | ||||
| 		} | ||||
| 
 | ||||
| 		if ok { | ||||
| 			u.User = url.UserPassword(envUsername, password) | ||||
| 		} else { | ||||
| 			u.User = url.User(envUsername) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Override password if provided
 | ||||
| 	if envPassword != "" { | ||||
| 		var username string | ||||
| 
 | ||||
| 		if u.User != nil { | ||||
| 			username = u.User.Username() | ||||
| 		} | ||||
| 
 | ||||
| 		u.User = url.UserPassword(username, envPassword) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func exit(err error) { | ||||
| 	fmt.Fprintf(os.Stderr, "Error: %s\n", err) | ||||
| 	os.Exit(1) | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	ctx, cancel := context.WithCancel(context.Background()) | ||||
| 	defer cancel() | ||||
| 
 | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	// Parse URL from string
 | ||||
| 	u, err := url.Parse(*urlFlag) | ||||
| 	if err != nil { | ||||
| 		exit(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Override username and/or password as required
 | ||||
| 	processOverride(u) | ||||
| 
 | ||||
| 	// Connect and log in to ESX or vCenter
 | ||||
| 	c, err := govmomi.NewClient(ctx, u, *insecureFlag) | ||||
| 	if err != nil { | ||||
| 		exit(err) | ||||
| 	} | ||||
| 
 | ||||
| 	f := find.NewFinder(c.Client, true) | ||||
| 
 | ||||
| 	// Find one and only datacenter
 | ||||
| 	dc, err := f.DefaultDatacenter(ctx) | ||||
| 	if err != nil { | ||||
| 		exit(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Make future calls local to this datacenter
 | ||||
| 	f.SetDatacenter(dc) | ||||
| 
 | ||||
| 	// Find datastores in datacenter
 | ||||
| 	dss, err := f.DatastoreList(ctx, "*") | ||||
| 	if err != nil { | ||||
| 		exit(err) | ||||
| 	} | ||||
| 
 | ||||
| 	pc := property.DefaultCollector(c.Client) | ||||
| 
 | ||||
| 	// Convert datastores into list of references
 | ||||
| 	var refs []types.ManagedObjectReference | ||||
| 	for _, ds := range dss { | ||||
| 		refs = append(refs, ds.Reference()) | ||||
| 	} | ||||
| 
 | ||||
| 	// Retrieve summary property for all datastores
 | ||||
| 	var dst []mo.Datastore | ||||
| 	err = pc.Retrieve(ctx, refs, []string{"summary"}, &dst) | ||||
| 	if err != nil { | ||||
| 		exit(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Print summary per datastore
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 	fmt.Fprintf(tw, "Name:\tType:\tCapacity:\tFree:\n") | ||||
| 	for _, ds := range dst { | ||||
| 		fmt.Fprintf(tw, "%s\t", ds.Summary.Name) | ||||
| 		fmt.Fprintf(tw, "%s\t", ds.Summary.Type) | ||||
| 		fmt.Fprintf(tw, "%s\t", units.ByteSize(ds.Summary.Capacity)) | ||||
| 		fmt.Fprintf(tw, "%s\t", units.ByteSize(ds.Summary.FreeSpace)) | ||||
| 		fmt.Fprintf(tw, "\n") | ||||
| 	} | ||||
| 	tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,64 @@ | |||
| /* | ||||
| 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 find | ||||
| 
 | ||||
| import "fmt" | ||||
| 
 | ||||
| type NotFoundError struct { | ||||
| 	kind string | ||||
| 	path string | ||||
| } | ||||
| 
 | ||||
| func (e *NotFoundError) Error() string { | ||||
| 	return fmt.Sprintf("%s '%s' not found", e.kind, e.path) | ||||
| } | ||||
| 
 | ||||
| type MultipleFoundError struct { | ||||
| 	kind string | ||||
| 	path string | ||||
| } | ||||
| 
 | ||||
| func (e *MultipleFoundError) Error() string { | ||||
| 	return fmt.Sprintf("path '%s' resolves to multiple %ss", e.path, e.kind) | ||||
| } | ||||
| 
 | ||||
| type DefaultNotFoundError struct { | ||||
| 	kind string | ||||
| } | ||||
| 
 | ||||
| func (e *DefaultNotFoundError) Error() string { | ||||
| 	return fmt.Sprintf("no default %s found", e.kind) | ||||
| } | ||||
| 
 | ||||
| type DefaultMultipleFoundError struct { | ||||
| 	kind string | ||||
| } | ||||
| 
 | ||||
| func (e DefaultMultipleFoundError) Error() string { | ||||
| 	return fmt.Sprintf("default %s resolves to multiple instances, please specify", e.kind) | ||||
| } | ||||
| 
 | ||||
| func toDefaultError(err error) error { | ||||
| 	switch e := err.(type) { | ||||
| 	case *NotFoundError: | ||||
| 		return &DefaultNotFoundError{e.kind} | ||||
| 	case *MultipleFoundError: | ||||
| 		return &DefaultMultipleFoundError{e.kind} | ||||
| 	default: | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,607 @@ | |||
| /* | ||||
| 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 find | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"path" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/list" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/property" | ||||
| 	"github.com/vmware/govmomi/vim25" | ||||
| 	"github.com/vmware/govmomi/vim25/mo" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type Finder struct { | ||||
| 	client   *vim25.Client | ||||
| 	recurser list.Recurser | ||||
| 
 | ||||
| 	dc      *object.Datacenter | ||||
| 	folders *object.DatacenterFolders | ||||
| } | ||||
| 
 | ||||
| func NewFinder(client *vim25.Client, all bool) *Finder { | ||||
| 	f := &Finder{ | ||||
| 		client: client, | ||||
| 		recurser: list.Recurser{ | ||||
| 			Collector: property.DefaultCollector(client), | ||||
| 			All:       all, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	return f | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) SetDatacenter(dc *object.Datacenter) *Finder { | ||||
| 	f.dc = dc | ||||
| 	f.folders = nil | ||||
| 	return f | ||||
| } | ||||
| 
 | ||||
| type findRelativeFunc func(ctx context.Context) (object.Reference, error) | ||||
| 
 | ||||
| func (f *Finder) find(ctx context.Context, fn findRelativeFunc, tl bool, arg string) ([]list.Element, error) { | ||||
| 	root := list.Element{ | ||||
| 		Path:   "/", | ||||
| 		Object: object.NewRootFolder(f.client), | ||||
| 	} | ||||
| 
 | ||||
| 	parts := list.ToParts(arg) | ||||
| 
 | ||||
| 	if len(parts) > 0 { | ||||
| 		switch parts[0] { | ||||
| 		case "..": // Not supported; many edge case, little value
 | ||||
| 			return nil, errors.New("cannot traverse up a tree") | ||||
| 		case ".": // Relative to whatever
 | ||||
| 			pivot, err := fn(ctx) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 
 | ||||
| 			mes, err := mo.Ancestors(ctx, f.client, f.client.ServiceContent.PropertyCollector, pivot.Reference()) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 
 | ||||
| 			for _, me := range mes { | ||||
| 				// Skip root entity in building inventory path.
 | ||||
| 				if me.Parent == nil { | ||||
| 					continue | ||||
| 				} | ||||
| 				root.Path = path.Join(root.Path, me.Name) | ||||
| 			} | ||||
| 
 | ||||
| 			root.Object = pivot | ||||
| 			parts = parts[1:] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	f.recurser.TraverseLeafs = tl | ||||
| 	es, err := f.recurser.Recurse(ctx, root, parts) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return es, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) datacenter() (*object.Datacenter, error) { | ||||
| 	if f.dc == nil { | ||||
| 		return nil, errors.New("please specify a datacenter") | ||||
| 	} | ||||
| 
 | ||||
| 	return f.dc, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) dcFolders(ctx context.Context) (*object.DatacenterFolders, error) { | ||||
| 	if f.folders != nil { | ||||
| 		return f.folders, nil | ||||
| 	} | ||||
| 
 | ||||
| 	dc, err := f.datacenter() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	folders, err := dc.Folders(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	f.folders = folders | ||||
| 
 | ||||
| 	return f.folders, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) dcReference(_ context.Context) (object.Reference, error) { | ||||
| 	dc, err := f.datacenter() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return dc, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) vmFolder(ctx context.Context) (object.Reference, error) { | ||||
| 	folders, err := f.dcFolders(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return folders.VmFolder, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) hostFolder(ctx context.Context) (object.Reference, error) { | ||||
| 	folders, err := f.dcFolders(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return folders.HostFolder, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) datastoreFolder(ctx context.Context) (object.Reference, error) { | ||||
| 	folders, err := f.dcFolders(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return folders.DatastoreFolder, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) networkFolder(ctx context.Context) (object.Reference, error) { | ||||
| 	folders, err := f.dcFolders(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return folders.NetworkFolder, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) rootFolder(_ context.Context) (object.Reference, error) { | ||||
| 	return object.NewRootFolder(f.client), nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool) ([]list.Element, error) { | ||||
| 	fn := f.rootFolder | ||||
| 
 | ||||
| 	if f.dc != nil { | ||||
| 		fn = f.dcReference | ||||
| 	} | ||||
| 
 | ||||
| 	if len(path) == 0 { | ||||
| 		path = "." | ||||
| 	} | ||||
| 
 | ||||
| 	return f.find(ctx, fn, tl, path) | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) ManagedObjectList(ctx context.Context, path string) ([]list.Element, error) { | ||||
| 	return f.managedObjectList(ctx, path, false) | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) ManagedObjectListChildren(ctx context.Context, path string) ([]list.Element, error) { | ||||
| 	return f.managedObjectList(ctx, path, true) | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) DatacenterList(ctx context.Context, path string) ([]*object.Datacenter, error) { | ||||
| 	es, err := f.find(ctx, f.rootFolder, false, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var dcs []*object.Datacenter | ||||
| 	for _, e := range es { | ||||
| 		ref := e.Object.Reference() | ||||
| 		if ref.Type == "Datacenter" { | ||||
| 			dcs = append(dcs, object.NewDatacenter(f.client, ref)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(dcs) == 0 { | ||||
| 		return nil, &NotFoundError{"datacenter", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return dcs, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) Datacenter(ctx context.Context, path string) (*object.Datacenter, error) { | ||||
| 	dcs, err := f.DatacenterList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(dcs) > 1 { | ||||
| 		return nil, &MultipleFoundError{"datacenter", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return dcs[0], nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) DefaultDatacenter(ctx context.Context) (*object.Datacenter, error) { | ||||
| 	dc, err := f.Datacenter(ctx, "*") | ||||
| 	if err != nil { | ||||
| 		return nil, toDefaultError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return dc, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) DatastoreList(ctx context.Context, path string) ([]*object.Datastore, error) { | ||||
| 	es, err := f.find(ctx, f.datastoreFolder, false, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var dss []*object.Datastore | ||||
| 	for _, e := range es { | ||||
| 		ref := e.Object.Reference() | ||||
| 		if ref.Type == "Datastore" { | ||||
| 			ds := object.NewDatastore(f.client, ref) | ||||
| 			ds.InventoryPath = e.Path | ||||
| 
 | ||||
| 			dss = append(dss, ds) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(dss) == 0 { | ||||
| 		return nil, &NotFoundError{"datastore", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return dss, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) Datastore(ctx context.Context, path string) (*object.Datastore, error) { | ||||
| 	dss, err := f.DatastoreList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(dss) > 1 { | ||||
| 		return nil, &MultipleFoundError{"datastore", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return dss[0], nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) DefaultDatastore(ctx context.Context) (*object.Datastore, error) { | ||||
| 	ds, err := f.Datastore(ctx, "*") | ||||
| 	if err != nil { | ||||
| 		return nil, toDefaultError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return ds, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) ComputeResourceList(ctx context.Context, path string) ([]*object.ComputeResource, error) { | ||||
| 	es, err := f.find(ctx, f.hostFolder, false, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var crs []*object.ComputeResource | ||||
| 	for _, e := range es { | ||||
| 		var cr *object.ComputeResource | ||||
| 
 | ||||
| 		switch o := e.Object.(type) { | ||||
| 		case mo.ComputeResource, mo.ClusterComputeResource: | ||||
| 			cr = object.NewComputeResource(f.client, o.Reference()) | ||||
| 		default: | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		cr.InventoryPath = e.Path | ||||
| 		crs = append(crs, cr) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(crs) == 0 { | ||||
| 		return nil, &NotFoundError{"compute resource", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return crs, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) ComputeResource(ctx context.Context, path string) (*object.ComputeResource, error) { | ||||
| 	crs, err := f.ComputeResourceList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(crs) > 1 { | ||||
| 		return nil, &MultipleFoundError{"compute resource", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return crs[0], nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) DefaultComputeResource(ctx context.Context) (*object.ComputeResource, error) { | ||||
| 	cr, err := f.ComputeResource(ctx, "*") | ||||
| 	if err != nil { | ||||
| 		return nil, toDefaultError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return cr, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) ClusterComputeResourceList(ctx context.Context, path string) ([]*object.ClusterComputeResource, error) { | ||||
| 	es, err := f.find(ctx, f.hostFolder, false, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var ccrs []*object.ClusterComputeResource | ||||
| 	for _, e := range es { | ||||
| 		var ccr *object.ClusterComputeResource | ||||
| 
 | ||||
| 		switch o := e.Object.(type) { | ||||
| 		case mo.ClusterComputeResource: | ||||
| 			ccr = object.NewClusterComputeResource(f.client, o.Reference()) | ||||
| 		default: | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		ccr.InventoryPath = e.Path | ||||
| 		ccrs = append(ccrs, ccr) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(ccrs) == 0 { | ||||
| 		return nil, &NotFoundError{"cluster", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return ccrs, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) ClusterComputeResource(ctx context.Context, path string) (*object.ClusterComputeResource, error) { | ||||
| 	ccrs, err := f.ClusterComputeResourceList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(ccrs) > 1 { | ||||
| 		return nil, &MultipleFoundError{"cluster", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return ccrs[0], nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) HostSystemList(ctx context.Context, path string) ([]*object.HostSystem, error) { | ||||
| 	es, err := f.find(ctx, f.hostFolder, false, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var hss []*object.HostSystem | ||||
| 	for _, e := range es { | ||||
| 		var hs *object.HostSystem | ||||
| 
 | ||||
| 		switch o := e.Object.(type) { | ||||
| 		case mo.HostSystem: | ||||
| 			hs = object.NewHostSystem(f.client, o.Reference()) | ||||
| 		case mo.ComputeResource: | ||||
| 			cr := object.NewComputeResource(f.client, o.Reference()) | ||||
| 			hosts, err := cr.Hosts(ctx) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			hs = object.NewHostSystem(f.client, hosts[0]) | ||||
| 		default: | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		hs.InventoryPath = e.Path | ||||
| 		hss = append(hss, hs) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(hss) == 0 { | ||||
| 		return nil, &NotFoundError{"host", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return hss, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) HostSystem(ctx context.Context, path string) (*object.HostSystem, error) { | ||||
| 	hss, err := f.HostSystemList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(hss) > 1 { | ||||
| 		return nil, &MultipleFoundError{"host", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return hss[0], nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) DefaultHostSystem(ctx context.Context) (*object.HostSystem, error) { | ||||
| 	hs, err := f.HostSystem(ctx, "*/*") | ||||
| 	if err != nil { | ||||
| 		return nil, toDefaultError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return hs, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) NetworkList(ctx context.Context, path string) ([]object.NetworkReference, error) { | ||||
| 	es, err := f.find(ctx, f.networkFolder, false, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var ns []object.NetworkReference | ||||
| 	for _, e := range es { | ||||
| 		ref := e.Object.Reference() | ||||
| 		switch ref.Type { | ||||
| 		case "Network": | ||||
| 			r := object.NewNetwork(f.client, ref) | ||||
| 			r.InventoryPath = e.Path | ||||
| 			ns = append(ns, r) | ||||
| 		case "DistributedVirtualPortgroup": | ||||
| 			r := object.NewDistributedVirtualPortgroup(f.client, ref) | ||||
| 			r.InventoryPath = e.Path | ||||
| 			ns = append(ns, r) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(ns) == 0 { | ||||
| 		return nil, &NotFoundError{"network", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return ns, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) Network(ctx context.Context, path string) (object.NetworkReference, error) { | ||||
| 	networks, err := f.NetworkList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(networks) > 1 { | ||||
| 		return nil, &MultipleFoundError{"network", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return networks[0], nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) DefaultNetwork(ctx context.Context) (object.NetworkReference, error) { | ||||
| 	network, err := f.Network(ctx, "*") | ||||
| 	if err != nil { | ||||
| 		return nil, toDefaultError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return network, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) ResourcePoolList(ctx context.Context, path string) ([]*object.ResourcePool, error) { | ||||
| 	es, err := f.find(ctx, f.hostFolder, true, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var rps []*object.ResourcePool | ||||
| 	for _, e := range es { | ||||
| 		var rp *object.ResourcePool | ||||
| 
 | ||||
| 		switch o := e.Object.(type) { | ||||
| 		case mo.ResourcePool: | ||||
| 			rp = object.NewResourcePool(f.client, o.Reference()) | ||||
| 			rp.InventoryPath = e.Path | ||||
| 			rps = append(rps, rp) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(rps) == 0 { | ||||
| 		return nil, &NotFoundError{"resource pool", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return rps, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) ResourcePool(ctx context.Context, path string) (*object.ResourcePool, error) { | ||||
| 	rps, err := f.ResourcePoolList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(rps) > 1 { | ||||
| 		return nil, &MultipleFoundError{"resource pool", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return rps[0], nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) DefaultResourcePool(ctx context.Context) (*object.ResourcePool, error) { | ||||
| 	rp, err := f.ResourcePool(ctx, "*/Resources") | ||||
| 	if err != nil { | ||||
| 		return nil, toDefaultError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return rp, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) VirtualMachineList(ctx context.Context, path string) ([]*object.VirtualMachine, error) { | ||||
| 	es, err := f.find(ctx, f.vmFolder, false, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var vms []*object.VirtualMachine | ||||
| 	for _, e := range es { | ||||
| 		switch o := e.Object.(type) { | ||||
| 		case mo.VirtualMachine: | ||||
| 			vm := object.NewVirtualMachine(f.client, o.Reference()) | ||||
| 			vm.InventoryPath = e.Path | ||||
| 			vms = append(vms, vm) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(vms) == 0 { | ||||
| 		return nil, &NotFoundError{"vm", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return vms, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) VirtualMachine(ctx context.Context, path string) (*object.VirtualMachine, error) { | ||||
| 	vms, err := f.VirtualMachineList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(vms) > 1 { | ||||
| 		return nil, &MultipleFoundError{"vm", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return vms[0], nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) VirtualAppList(ctx context.Context, path string) ([]*object.VirtualApp, error) { | ||||
| 	es, err := f.find(ctx, f.vmFolder, false, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var apps []*object.VirtualApp | ||||
| 	for _, e := range es { | ||||
| 		switch o := e.Object.(type) { | ||||
| 		case mo.VirtualApp: | ||||
| 			app := object.NewVirtualApp(f.client, o.Reference()) | ||||
| 			app.InventoryPath = e.Path | ||||
| 			apps = append(apps, app) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(apps) == 0 { | ||||
| 		return nil, &NotFoundError{"app", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return apps, nil | ||||
| } | ||||
| 
 | ||||
| func (f *Finder) VirtualApp(ctx context.Context, path string) (*object.VirtualApp, error) { | ||||
| 	apps, err := f.VirtualAppList(ctx, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(apps) > 1 { | ||||
| 		return nil, &MultipleFoundError{"app", path} | ||||
| 	} | ||||
| 
 | ||||
| 	return apps[0], nil | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| source "https://rubygems.org" | ||||
| 
 | ||||
| gem "nokogiri" | ||||
|  | @ -0,0 +1,38 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # 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. | ||||
| 
 | ||||
| set -e | ||||
| 
 | ||||
| if [ ! -f rbvmomi/vmodl.db ]; then | ||||
|   git clone https://github.com/vmware/rbvmomi | ||||
| fi | ||||
| 
 | ||||
| dst=../vim25 | ||||
| 
 | ||||
| pkgs=$(echo $dst/{types,methods,mo}) | ||||
| mkdir -p $pkgs | ||||
| 
 | ||||
| bundle exec ruby gen_from_wsdl.rb $dst | ||||
| bundle exec ruby gen_from_vmodl.rb $dst | ||||
| 
 | ||||
| for p in $pkgs | ||||
| do | ||||
|   echo $p | ||||
|   cd $p | ||||
|   goimports -w *.go | ||||
|   go install | ||||
|   cd - | ||||
| done | ||||
|  | @ -0,0 +1,216 @@ | |||
| # 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. | ||||
| 
 | ||||
| $:.unshift(File.expand_path(File.dirname(__FILE__))) | ||||
| 
 | ||||
| require "vim_wsdl" | ||||
| 
 | ||||
| require "test/unit" | ||||
| 
 | ||||
| PATH = File.expand_path("../rbvmomi", __FILE__) | ||||
| 
 | ||||
| def read(file) | ||||
|   File.open(File.join(PATH, file)) | ||||
| end | ||||
| 
 | ||||
| class Prop | ||||
|   def initialize(vmodl, data) | ||||
|     @vmodl = vmodl | ||||
|     @data = data | ||||
|   end | ||||
| 
 | ||||
|   def slice? | ||||
|     @data["is-array"] | ||||
|   end | ||||
| 
 | ||||
|   def optional? | ||||
|     @data["is-optional"] | ||||
|   end | ||||
| 
 | ||||
|   def name | ||||
|     @data["name"] | ||||
|   end | ||||
| 
 | ||||
|   def var_field | ||||
|     n = name | ||||
|     n[0].capitalize + n[1..-1] | ||||
|   end | ||||
| 
 | ||||
|   def var_type_prefix(base=false) | ||||
|     if slice? | ||||
|       "[]" | ||||
|     else | ||||
|       if optional? && !base | ||||
|         "*" | ||||
|       else | ||||
|         "" | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def var_type | ||||
|     type = @data["wsdl_type"] | ||||
|     if @vmodl.managed_hash.has_key?(type) | ||||
|       type = "ManagedObjectReference" | ||||
|     end | ||||
| 
 | ||||
|     # Fix up type from vmodl | ||||
|     case type | ||||
|     when "TypeName", "MethodName" | ||||
|       type = "xsd:string" | ||||
|     when "ManagedObject" | ||||
|       type = "ManagedObjectReference" | ||||
|     when "xsd:anyType" | ||||
|       type = "AnyType" | ||||
|     end | ||||
| 
 | ||||
|     if type =~ /^xsd:(.*)$/ | ||||
|       type = $1 | ||||
|       case type | ||||
|       when "string" | ||||
|       when "int" | ||||
|       when "boolean" | ||||
|         type ="bool" | ||||
|       when "long" | ||||
|         type ="int64" | ||||
|       when "dateTime" | ||||
|         type ="time.Time" | ||||
|         prefix += "*" if !slice? && optional? | ||||
|       when "byte" | ||||
|       when "double" | ||||
|         type ="float64" | ||||
|       when "float" | ||||
|         type ="float32" | ||||
|       when "short" | ||||
|         type ="int16" | ||||
|       when "base64Binary" | ||||
|         type ="[]byte" | ||||
|       else | ||||
|         raise "unknown type: %s" % type | ||||
|       end | ||||
|     else | ||||
|       if Peek.base?(type) | ||||
|         type = "Base" + type | ||||
|         base = true | ||||
|       end | ||||
|       type = "types." + type | ||||
|     end | ||||
| 
 | ||||
|     var_type_prefix(base) + type | ||||
|   end | ||||
| 
 | ||||
|   def var_tag | ||||
|     "mo:\"%s\"" % name | ||||
|   end | ||||
| 
 | ||||
|   def dump(io) | ||||
|     io.print "%s %s `%s`\n" % [var_field, var_type, var_tag] | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class Managed | ||||
|   def initialize(vmodl, name, data) | ||||
|     @vmodl = vmodl | ||||
|     @name = name | ||||
|     @data = data | ||||
|   end | ||||
| 
 | ||||
|   def name | ||||
|     @name | ||||
|   end | ||||
| 
 | ||||
|   def props | ||||
|     @data["props"].map do |p| | ||||
|       Prop.new(@vmodl, p) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def dump(io) | ||||
|     include_ref_getter = false | ||||
| 
 | ||||
|     io.print "type %s struct {\n" % name | ||||
| 
 | ||||
|     case @data["wsdl_base"] | ||||
|     when nil, "ManagedObject", "View" | ||||
|       include_ref_getter = true | ||||
|       io.print "Self types.ManagedObjectReference\n\n" | ||||
|     else | ||||
|       io.print "%s\n\n" % @data["wsdl_base"] | ||||
|     end | ||||
| 
 | ||||
|     props.each do |p| | ||||
|       p.dump(io) | ||||
|     end | ||||
|     io.print "}\n\n" | ||||
| 
 | ||||
|     if include_ref_getter | ||||
|       io.print "func (m %s) Reference() types.ManagedObjectReference {\n" % [name] | ||||
|       io.print "return m.Self\n" | ||||
|       io.print "}\n\n" | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def dump_init(io) | ||||
|     io.print "func init() {\n" | ||||
|     io.print "t[\"%s\"] = reflect.TypeOf((*%s)(nil)).Elem()\n" % [name, name] | ||||
|     io.print "}\n\n" | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class Vmodl | ||||
|   def initialize(data) | ||||
|     @data = Marshal.load(data) | ||||
|   end | ||||
| 
 | ||||
|   def managed_hash | ||||
|     @managed_hash ||= begin | ||||
|                         h = {} | ||||
|                         managed.each do |m| | ||||
|                           h[m.name] = m | ||||
|                         end | ||||
|                         h | ||||
|                       end | ||||
|   end | ||||
| 
 | ||||
|   def managed | ||||
|     @data.map do |k,v| | ||||
|       next if !v.is_a?(Hash) | ||||
|       next if v["kind"] != "managed" | ||||
|       next if k =~ /^pbm/i | ||||
| 
 | ||||
|       Managed.new(self, k, v) | ||||
|     end.compact | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| if !File.directory?(ARGV.first) | ||||
|   raise "first argument not a directory" | ||||
| end | ||||
| 
 | ||||
| wsdl = WSDL.new(WSDL.read "vim.wsdl") | ||||
| wsdl.validate_assumptions! | ||||
| wsdl.peek() | ||||
| 
 | ||||
| File.open(File.join(ARGV.first, "mo/mo.go"), "w") do |io| | ||||
|   io.print WSDL.header("mo") | ||||
| 
 | ||||
|   vmodl = Vmodl.new(read "vmodl.db") | ||||
| 
 | ||||
|   vmodl. | ||||
|     managed. | ||||
|     sort_by { |m| m.name }. | ||||
|     each { |m| m.dump(io); m.dump_init(io); } | ||||
| end | ||||
| 
 | ||||
| exit(0) | ||||
|  | @ -0,0 +1,70 @@ | |||
| # 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. | ||||
| 
 | ||||
| $:.unshift(File.expand_path(File.dirname(__FILE__))) | ||||
| 
 | ||||
| require "vim_wsdl" | ||||
| 
 | ||||
| if !File.directory?(ARGV.first) | ||||
|   raise "first argument not a directory" | ||||
| end | ||||
| 
 | ||||
| wsdl = WSDL.new(WSDL.read "vim.wsdl") | ||||
| wsdl.validate_assumptions! | ||||
| wsdl.peek() | ||||
| 
 | ||||
| ifs = Peek.types.keys.select { |name| Peek.base?(name) }.size() | ||||
| puts "%d classes, %d interfaces" % [Peek.types.size(), ifs] | ||||
| 
 | ||||
| File.open(File.join(ARGV.first, "types/enum.go"), "w") do |io| | ||||
|   io.print WSDL.header("types") | ||||
| 
 | ||||
|   wsdl. | ||||
|     types. | ||||
|     sort_by { |x| x.name }. | ||||
|     uniq { |x| x.name }. | ||||
|     select { |x| x.name[0] == x.name[0].upcase }. # Only capitalized methods for now... | ||||
|     select { |t| t.is_enum? }. | ||||
|     each { |e| e.dump(io); e.dump_init(io) } | ||||
| end | ||||
| 
 | ||||
| File.open(File.join(ARGV.first, "types/types.go"), "w") do |io| | ||||
|   io.print WSDL.header("types") | ||||
| 
 | ||||
|   wsdl. | ||||
|     types. | ||||
|     sort_by { |x| x.name }. | ||||
|     uniq { |x| x.name }. | ||||
|     select { |x| x.name[0] == x.name[0].upcase }. # Only capitalized methods for now... | ||||
|     select { |t| !t.is_enum? }. | ||||
|     each { |e| e.dump(io); e.dump_init(io) } | ||||
| end | ||||
| 
 | ||||
| File.open(File.join(ARGV.first, "types/if.go"), "w") do |io| | ||||
|   io.print WSDL.header("types") | ||||
| 
 | ||||
|   Peek.dump_interfaces(io) | ||||
| end | ||||
| 
 | ||||
| File.open(File.join(ARGV.first, "methods/methods.go"), "w") do |io| | ||||
|   io.print WSDL.header("methods") | ||||
| 
 | ||||
|   wsdl. | ||||
|     operations. | ||||
|     sort_by { |x| x.name }. | ||||
|     select { |x| x.name[0] == x.name[0].upcase }. # Only capitalized methods for now... | ||||
|     each { |e| e.dump(io) } | ||||
| end | ||||
| 
 | ||||
| exit(0) | ||||
|  | @ -0,0 +1,761 @@ | |||
| # 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. | ||||
| 
 | ||||
| require "nokogiri" | ||||
| require "test/unit" | ||||
| 
 | ||||
| class Peek | ||||
|   class Type | ||||
|     attr_accessor :parent, :children, :klass | ||||
| 
 | ||||
|     def initialize(name) | ||||
|       @name = name | ||||
|       @children = [] | ||||
|     end | ||||
| 
 | ||||
|     def base? | ||||
|       return !children.empty? | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   @@types = {} | ||||
|   @@refs = {} | ||||
|   @@enums = {} | ||||
| 
 | ||||
|   def self.types | ||||
|     return @@types | ||||
|   end | ||||
| 
 | ||||
|   def self.refs | ||||
|     return @@refs | ||||
|   end | ||||
| 
 | ||||
|   def self.enums | ||||
|     return @@enums | ||||
|   end | ||||
| 
 | ||||
|   def self.ref(type) | ||||
|     refs[type] = true | ||||
|   end | ||||
| 
 | ||||
|   def self.enum(type) | ||||
|     enums[type] = true | ||||
|   end | ||||
| 
 | ||||
|   def self.enum?(type) | ||||
|     enums[type] | ||||
|   end | ||||
| 
 | ||||
|   def self.register(name) | ||||
|     raise unless name | ||||
|     types[name] ||= Type.new(name) | ||||
|   end | ||||
| 
 | ||||
|   def self.base?(name) | ||||
|     return unless c = types[name] | ||||
|     c.base? | ||||
|   end | ||||
| 
 | ||||
|   def self.dump_interfaces(io) | ||||
|     types.keys.sort.each do |name| | ||||
|       next unless base?(name) | ||||
| 
 | ||||
|       types[name].klass.dump_interface(io, name) | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class EnumValue | ||||
|   def initialize(type, value) | ||||
|     @type = type | ||||
|     @value = value | ||||
|   end | ||||
| 
 | ||||
|   def type_name | ||||
|     @type.name | ||||
|   end | ||||
| 
 | ||||
|   def var_name | ||||
|     n = @type.name | ||||
|     v = var_value | ||||
|     if v == "" | ||||
|       n += "Null" | ||||
|     else | ||||
|       n += (v[0].capitalize + v[1..-1]) | ||||
|     end | ||||
| 
 | ||||
|     return n | ||||
|   end | ||||
| 
 | ||||
|   def var_value | ||||
|     @value | ||||
|   end | ||||
| 
 | ||||
|   def dump(io) | ||||
|     io.print "%s = %s(\"%s\")\n" % [var_name, type_name, var_value] | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class Simple | ||||
|   include Test::Unit::Assertions | ||||
| 
 | ||||
|   attr_accessor :name, :type | ||||
| 
 | ||||
|   def initialize(node) | ||||
|     @node = node | ||||
|   end | ||||
| 
 | ||||
|   def name | ||||
|     @name || @node["name"] | ||||
|   end | ||||
| 
 | ||||
|   def type | ||||
|     @type || @node["type"] | ||||
|   end | ||||
| 
 | ||||
|   def is_enum? | ||||
|     false | ||||
|   end | ||||
| 
 | ||||
|   def dump_init(io) | ||||
|     # noop | ||||
|   end | ||||
| 
 | ||||
|   def var_name | ||||
|     n = self.name | ||||
|     n = n[1..-1] if n[0] == "_" # Strip leading _ | ||||
|     n = n[0].capitalize + n[1..-1] # Capitalize | ||||
|     return n | ||||
|   end | ||||
| 
 | ||||
|   def vim_type? | ||||
|     ns, _ = self.type.split(":", 2) | ||||
|     ns == "vim25" | ||||
|   end | ||||
| 
 | ||||
|   def vim_type(t = self.type) | ||||
|     ns, t = t.split(":", 2) | ||||
|     raise if ns != "vim25" | ||||
|     t | ||||
|   end | ||||
| 
 | ||||
|   def base_type? | ||||
|     vim_type? && Peek.base?(vim_type) | ||||
|   end | ||||
| 
 | ||||
|   def enum_type? | ||||
|     vim_type? && Peek.enum?(vim_type) | ||||
|   end | ||||
| 
 | ||||
|   def any_type? | ||||
|     self.type == "xsd:anyType" | ||||
|   end | ||||
| 
 | ||||
|   def var_type | ||||
|     t = self.type | ||||
|     prefix = "" | ||||
| 
 | ||||
|     prefix += "[]" if slice? | ||||
| 
 | ||||
|     if t =~ /^xsd:(.*)$/ | ||||
|       t = $1 | ||||
|       case t | ||||
|       when "string" | ||||
|       when "int" | ||||
|       when "boolean" | ||||
|         t = "bool" | ||||
|         if !slice? && optional? | ||||
|           prefix += "*" | ||||
|           self.need_omitempty = false | ||||
|         end | ||||
|       when "long" | ||||
|         t = "int64" | ||||
|       when "dateTime" | ||||
|         t = "time.Time" | ||||
|         if !slice? && optional? | ||||
|           prefix += "*" | ||||
|           self.need_omitempty = false | ||||
|         end | ||||
|       when "anyType" | ||||
|         t = "AnyType" | ||||
|       when "byte" | ||||
|       when "double" | ||||
|         t = "float64" | ||||
|       when "float" | ||||
|         t = "float32" | ||||
|       when "short" | ||||
|         t = "int16" | ||||
|       when "base64Binary" | ||||
|         t = "[]byte" | ||||
|       when "anyURI" | ||||
|         t = "url.URL" | ||||
|       else | ||||
|         raise "unknown type: %s" % t | ||||
|       end | ||||
|     else | ||||
|       t = vim_type | ||||
|       if base_type? | ||||
|         prefix += "Base" | ||||
|       else | ||||
|         prefix += "*" if !slice? && !enum_type? && optional? | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     prefix + t | ||||
|   end | ||||
| 
 | ||||
|   def slice? | ||||
|     test_attr("maxOccurs", "unbounded") | ||||
|   end | ||||
| 
 | ||||
|   def optional? | ||||
|     test_attr("minOccurs", "0") | ||||
|   end | ||||
| 
 | ||||
|   def need_omitempty=(v) | ||||
|     @need_omitempty = v | ||||
|   end | ||||
| 
 | ||||
|   def need_omitempty? | ||||
|     var_type # HACK: trigger setting need_omitempty if necessary | ||||
|     if @need_omitempty.nil? | ||||
|       @need_omitempty = optional? | ||||
|     else | ||||
|       @need_omitempty | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def need_typeattr? | ||||
|     base_type? || any_type? | ||||
|   end | ||||
| 
 | ||||
|   protected | ||||
| 
 | ||||
|   def test_attr(attr, expected) | ||||
|     actual = @node.attr(attr) | ||||
|     if actual != nil | ||||
|       case actual | ||||
|       when expected | ||||
|         true | ||||
|       else | ||||
|         raise "%s=%s" % [value, type.attr(value)] | ||||
|       end | ||||
|     else | ||||
|       false | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class Element < Simple | ||||
|   def initialize(node) | ||||
|     super(node) | ||||
|   end | ||||
| 
 | ||||
|   def has_type? | ||||
|     !@node["type"].nil? | ||||
|   end | ||||
| 
 | ||||
|   def child | ||||
|     cs = @node.element_children | ||||
|     assert_equal 1, cs.length | ||||
|     assert_equal "complexType", cs.first.name | ||||
| 
 | ||||
|     t = ComplexType.new(cs.first) | ||||
|     t.name = self.name | ||||
|     t | ||||
|   end | ||||
| 
 | ||||
|   def dump(io) | ||||
|     if has_type? | ||||
|       io.print "type %s %s\n\n" % [name, var_type] | ||||
|     else | ||||
|       child.dump(io) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def dump_init(io) | ||||
|     if has_type? | ||||
|       io.print "func init() {\n" | ||||
|       io.print "t[\"%s\"] = reflect.TypeOf((*%s)(nil)).Elem()\n" % [name, name] | ||||
|       io.print "}\n\n" | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def dump_field(io) | ||||
|     tag = name | ||||
|     tag += ",omitempty" if need_omitempty? | ||||
|     tag += ",typeattr" if need_typeattr? | ||||
|     io.print "%s %s `xml:\"%s\"`\n" % [var_name, var_type, tag] | ||||
|   end | ||||
| 
 | ||||
|   def peek(type=nil) | ||||
|     if has_type? | ||||
|       return if self.type =~ /^xsd:/ | ||||
| 
 | ||||
|       Peek.ref(vim_type) | ||||
|     else | ||||
|       child.peek() | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class Attribute < Simple | ||||
|   def dump_field(io) | ||||
|     tag = name | ||||
|     tag += ",omitempty" if need_omitempty? | ||||
|     tag += ",attr" | ||||
|     io.print "%s %s `xml:\"%s\"`\n" % [var_name, var_type, tag] | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class SimpleType < Simple | ||||
|   def is_enum? | ||||
|     true | ||||
|   end | ||||
| 
 | ||||
|   def dump(io) | ||||
|     enums = @node.xpath(".//xsd:enumeration").map do |n| | ||||
|       EnumValue.new(self, n["value"]) | ||||
|     end | ||||
| 
 | ||||
|     io.print "type %s string\n\n" % name | ||||
|     io.print "const (\n" | ||||
|     enums.each { |e| e.dump(io) } | ||||
|     io.print ")\n\n" | ||||
|   end | ||||
| 
 | ||||
|   def dump_init(io) | ||||
|     io.print "func init() {\n" | ||||
|     io.print "t[\"%s\"] = reflect.TypeOf((*%s)(nil)).Elem()\n" % [name, name] | ||||
|     io.print "}\n\n" | ||||
|   end | ||||
| 
 | ||||
|   def peek | ||||
|     Peek.enum(name) | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class ComplexType < Simple | ||||
|   class SimpleContent < Simple | ||||
|     def dump(io) | ||||
|       attr = Attribute.new(@node.at_xpath(".//xsd:attribute")) | ||||
|       attr.dump_field(io) | ||||
| 
 | ||||
|       # HACK DELUXE(PN) | ||||
|       extension = @node.at_xpath(".//xsd:extension") | ||||
|       type = extension["base"].split(":", 2)[1] | ||||
|       io.print "Value %s `xml:\",chardata\"`\n" % type | ||||
|     end | ||||
| 
 | ||||
|     def peek | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   class ComplexContent < Simple | ||||
|     def base | ||||
|       extension = @node.at_xpath(".//xsd:extension") | ||||
|       assert_not_nil extension | ||||
| 
 | ||||
|       base = extension["base"] | ||||
|       assert_not_nil base | ||||
| 
 | ||||
|       vim_type(base) | ||||
|     end | ||||
| 
 | ||||
|     def dump(io) | ||||
|       Sequence.new(@node).dump(io, base) | ||||
|     end | ||||
| 
 | ||||
|     def dump_interface(io, name) | ||||
|       Sequence.new(@node).dump_interface(io, name) | ||||
|     end | ||||
| 
 | ||||
|     def peek | ||||
|       Sequence.new(@node).peek(base) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   class Sequence < Simple | ||||
|     def sequence | ||||
|       sequence = @node.at_xpath(".//xsd:sequence") | ||||
|       if sequence != nil | ||||
|         sequence.element_children.map do |n| | ||||
|           Element.new(n) | ||||
|         end | ||||
|       else | ||||
|         nil | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def dump(io, base = nil) | ||||
|       return unless elements = sequence | ||||
| 
 | ||||
|       io.print "%s\n\n" % base | ||||
| 
 | ||||
|       elements.each do |e| | ||||
|         e.dump_field(io) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def dump_interface(io, name) | ||||
|       method = "Get%s() *%s" % [name, name] | ||||
|       io.print "func (b *%s) %s { return b }\n" % [name, method] | ||||
|       io.print "type Base%s interface {\n" % name | ||||
|       io.print "%s\n" % method | ||||
|       io.print "}\n\n" | ||||
|       io.print "func init() {\n" | ||||
|       io.print "t[\"Base%s\"] = reflect.TypeOf((*%s)(nil)).Elem()\n" % [name, name] | ||||
|       io.print "}\n\n" | ||||
|     end | ||||
| 
 | ||||
|     def peek(base = nil) | ||||
|       return unless elements = sequence | ||||
|       name = @node.attr("name") | ||||
|       return unless name | ||||
| 
 | ||||
|       elements.each do |e| | ||||
|         e.peek(name) | ||||
|       end | ||||
| 
 | ||||
|       c = Peek.register(name) | ||||
|       if base | ||||
|         c.parent = base | ||||
|         Peek.register(c.parent).children << name | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def klass | ||||
|     @klass ||= begin | ||||
|                  cs = @node.element_children | ||||
|                  if !cs.empty? | ||||
|                    assert_equal 1, cs.length | ||||
| 
 | ||||
|                    case cs.first.name | ||||
|                    when "simpleContent" | ||||
|                      SimpleContent.new(@node) | ||||
|                    when "complexContent" | ||||
|                      ComplexContent.new(@node) | ||||
|                    when "sequence" | ||||
|                      Sequence.new(@node) | ||||
|                    else | ||||
|                      raise "don't know what to do for element: %s..." % cs.first.name | ||||
|                    end | ||||
|                  end | ||||
|                end | ||||
|   end | ||||
| 
 | ||||
|   def dump_init(io) | ||||
|     io.print "func init() {\n" | ||||
|     io.print "t[\"%s\"] = reflect.TypeOf((*%s)(nil)).Elem()\n" % [name, name] | ||||
|     io.print "}\n\n" | ||||
|   end | ||||
| 
 | ||||
|   def dump(io) | ||||
|     io.print "type %s struct {\n" % name | ||||
|     klass.dump(io) if klass | ||||
|     io.print "}\n\n" | ||||
|   end | ||||
| 
 | ||||
|   def peek | ||||
|     Peek.register(name).klass = klass | ||||
|     klass.peek if klass | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class Schema | ||||
|   include Test::Unit::Assertions | ||||
| 
 | ||||
|   def initialize(xml, parent = nil) | ||||
|     @xml = Nokogiri::XML.parse(xml) | ||||
|   end | ||||
| 
 | ||||
|   def targetNamespace | ||||
|     @xml.root["targetNamespace"] | ||||
|   end | ||||
| 
 | ||||
|   # We have some assumptions about structure, make sure they hold. | ||||
|   def validate_assumptions! | ||||
|     # Every enumeration is part of a restriction | ||||
|     @xml.xpath(".//xsd:enumeration").each do |n| | ||||
|       assert_equal "restriction", n.parent.name | ||||
|     end | ||||
| 
 | ||||
|     # See type == enum | ||||
|     @xml.xpath(".//xsd:restriction").each do |n| | ||||
|       # Every restriction has type xsd:string (it's an enum) | ||||
|       assert_equal "xsd:string", n["base"] | ||||
| 
 | ||||
|       # Every restriction is part of a simpleType | ||||
|       assert_equal "simpleType", n.parent.name | ||||
| 
 | ||||
|       # Every restriction is alone | ||||
|       assert_equal 1, n.parent.element_children.size | ||||
|     end | ||||
| 
 | ||||
|     # See type == complex_content | ||||
|     @xml.xpath(".//xsd:complexContent").each do |n| | ||||
|       # complexContent is child of complexType | ||||
|       assert_equal "complexType", n.parent.name | ||||
| 
 | ||||
|     end | ||||
| 
 | ||||
|     # See type == complex_type | ||||
|     @xml.xpath(".//xsd:complexType").each do |n| | ||||
|       cc = n.element_children | ||||
| 
 | ||||
|       # OK to have an empty complexType | ||||
|       next if cc.size == 0 | ||||
| 
 | ||||
|       # Require 1 element otherwise | ||||
|       assert_equal 1, cc.size | ||||
| 
 | ||||
|       case cc.first.name | ||||
|       when "complexContent" | ||||
|         # complexContent has 1 "extension" element | ||||
|         cc = cc.first.element_children | ||||
|         assert_equal 1, cc.size | ||||
|         assert_equal "extension", cc.first.name | ||||
| 
 | ||||
|         # extension has 1 "sequence" element | ||||
|         ec = cc.first.element_children | ||||
|         assert_equal 1, ec.size | ||||
|         assert_equal "sequence", ec.first.name | ||||
| 
 | ||||
|         # sequence has N "element" elements | ||||
|         sc = ec.first.element_children | ||||
|         assert sc.all? { |e| e.name == "element" } | ||||
|       when "simpleContent" | ||||
|         # simpleContent has 1 "extension" element | ||||
|         cc = cc.first.element_children | ||||
|         assert_equal 1, cc.size | ||||
|         assert_equal "extension", cc.first.name | ||||
| 
 | ||||
|         # extension has 1 or more "attribute" elements | ||||
|         ec = cc.first.element_children | ||||
|         assert_not_equal 0, ec.size | ||||
|         assert_equal "attribute", ec.first.name | ||||
|       when "sequence" | ||||
|         # sequence has N "element" elements | ||||
|         sc = cc.first.element_children | ||||
|         assert sc.all? { |e| e.name == "element" } | ||||
|       else | ||||
|         raise "unknown element: %s" % cc.first.name | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     includes.each do |i| | ||||
|       i.validate_assumptions! | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def types | ||||
|     return to_enum(:types) unless block_given? | ||||
| 
 | ||||
|     includes.each do |i| | ||||
|       i.types do |t| | ||||
|         yield t | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     @xml.root.children.each do |n| | ||||
|       case n.class.to_s | ||||
|       when "Nokogiri::XML::Text" | ||||
|         next | ||||
|       when "Nokogiri::XML::Element" | ||||
|         case n.name | ||||
|         when "include", "import" | ||||
|           next | ||||
|         when "element" | ||||
|           yield Element.new(n) | ||||
|         when "simpleType" | ||||
|           yield SimpleType.new(n) | ||||
|         when "complexType" | ||||
|           yield ComplexType.new(n) | ||||
|         else | ||||
|           raise "unknown child: %s" % n.name | ||||
|         end | ||||
|       else | ||||
|         raise "unknown type: %s" % n.class | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def includes | ||||
|     @includes ||= @xml.root.xpath(".//xmlns:include").map do |n| | ||||
|       Schema.new(WSDL.read n["schemaLocation"]) | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| class Operation | ||||
|   include Test::Unit::Assertions | ||||
| 
 | ||||
|   def initialize(wsdl, operation_node) | ||||
|     @wsdl = wsdl | ||||
|     @operation_node = operation_node | ||||
|   end | ||||
| 
 | ||||
|   def name | ||||
|     @operation_node["name"] | ||||
|   end | ||||
| 
 | ||||
|   def remove_ns(x) | ||||
|     ns, x = x.split(":", 2) | ||||
|     assert_equal "vim25", ns | ||||
|     x | ||||
|   end | ||||
| 
 | ||||
|   def find_type_for(type) | ||||
|     type = remove_ns(type) | ||||
| 
 | ||||
|     message = @wsdl.message(type) | ||||
|     assert_not_nil message | ||||
| 
 | ||||
|     part = message.at_xpath("./xmlns:part") | ||||
|     assert_not_nil message | ||||
| 
 | ||||
|     remove_ns(part["element"]) | ||||
|   end | ||||
| 
 | ||||
|   def input | ||||
|     type = @operation_node.at_xpath("./xmlns:input").attr("message") | ||||
|     find_type_for(type) | ||||
|   end | ||||
| 
 | ||||
|   def go_input | ||||
|     "types." + input | ||||
|   end | ||||
| 
 | ||||
|   def output | ||||
|     type = @operation_node.at_xpath("./xmlns:output").attr("message") | ||||
|     find_type_for(type) | ||||
|   end | ||||
| 
 | ||||
|   def go_output | ||||
|     "types." + output | ||||
|   end | ||||
| 
 | ||||
|   def dump(io) | ||||
|     io.print <<EOS | ||||
|   type #{name}Body struct{ | ||||
|     Req *#{go_input} `xml:"urn:vim25 #{input},omitempty"` | ||||
|     Res *#{go_output} `xml:"urn:vim25 #{output},omitempty"` | ||||
|     Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` | ||||
|   } | ||||
| 
 | ||||
|   func (b *#{name}Body) Fault() *soap.Fault { return b.Fault_ } | ||||
| 
 | ||||
| EOS | ||||
| 
 | ||||
|     io.print "func %s(ctx context.Context, r soap.RoundTripper, req *%s) (*%s, error) {\n" % [name, go_input, go_output] | ||||
|     io.print <<EOS | ||||
|   var reqBody, resBody #{name}Body | ||||
| 
 | ||||
|   reqBody.Req = req | ||||
| 
 | ||||
|   if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { | ||||
|     return nil, err | ||||
|   } | ||||
| 
 | ||||
|   return resBody.Res, nil | ||||
| EOS | ||||
| 
 | ||||
|     io.print "}\n\n" | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| class WSDL | ||||
|   attr_reader :xml | ||||
| 
 | ||||
|   PATH = File.expand_path("../sdk", __FILE__) | ||||
| 
 | ||||
|   def self.read(file) | ||||
|     File.open(File.join(PATH, file)) | ||||
|   end | ||||
| 
 | ||||
|   def initialize(xml) | ||||
|     @xml = Nokogiri::XML.parse(xml) | ||||
|   end | ||||
| 
 | ||||
|   def validate_assumptions! | ||||
|     schemas.each do |s| | ||||
|       s.validate_assumptions! | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def types(&blk) | ||||
|     return to_enum(:types) unless block_given? | ||||
| 
 | ||||
|     schemas.each do |s| | ||||
|       s.types(&blk) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def schemas | ||||
|     @schemas ||= @xml.xpath('.//xmlns:types/xsd:schema').map do |n| | ||||
|       Schema.new(n.to_xml) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def operations | ||||
|     @operations ||= @xml.xpath('.//xmlns:portType/xmlns:operation').map do |o| | ||||
|       Operation.new(self, o) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def message(type) | ||||
|     @messages ||= begin | ||||
|                     h = {} | ||||
|                     @xml.xpath('.//xmlns:message').each do |n| | ||||
|                       h[n.attr("name")] = n | ||||
|                     end | ||||
|                     h | ||||
|                   end | ||||
| 
 | ||||
|     @messages[type] | ||||
|   end | ||||
| 
 | ||||
|   def peek | ||||
|     types. | ||||
|       sort_by { |x| x.name }. | ||||
|       uniq { |x| x.name }. | ||||
|       select { |x| x.name[0] == x.name[0].upcase }. # Only capitalized methods for now... | ||||
|       each { |e| e.peek() } | ||||
|   end | ||||
| 
 | ||||
|   def self.header(name) | ||||
|     return <<EOF | ||||
| /* | ||||
| 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 #{name} | ||||
| 
 | ||||
| EOF | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1 @@ | |||
| /govc* | ||||
|  | @ -0,0 +1,28 @@ | |||
| # changelog | ||||
| 
 | ||||
| ### (unreleased) | ||||
| 
 | ||||
| * Add `PowerOn, InjectOvfEnv, WaitForIP` options to `import.ovf` and `import.ova` option spec file | ||||
| 
 | ||||
| * Add `import.spec` to produce an example json document | ||||
| 
 | ||||
| * Add `-options` to `import.ovf` and `import.ova` | ||||
| 
 | ||||
| * Add `-folder` to `import.ovf` and `import.ova` | ||||
| 
 | ||||
| * Add `host.add` command to add host to datacenter. | ||||
| 
 | ||||
| * Add `GOVC_USERNAME` and `GOVC_PASSWORD` to allow overriding username and/or | ||||
|   password (used when they contain special characters that prevent them from | ||||
|   being embedded in the URL). | ||||
| 
 | ||||
| * Retry twice on temporary network errors. | ||||
| 
 | ||||
| * Add `host.autostart` commands to manage VM autostart. | ||||
| 
 | ||||
| * Add `-persist-session` flag to control whether or not the session is | ||||
|   persisted to disk (defaults to true). | ||||
| 
 | ||||
| ### 0.1.0 (2015-03-17) | ||||
| 
 | ||||
| Prior to this version the changes to govc's command set were not documented. | ||||
|  | @ -0,0 +1,116 @@ | |||
| # govc | ||||
| 
 | ||||
| govc is a vSphere CLI built on top of govmomi. | ||||
| 
 | ||||
| ## Installation | ||||
| 
 | ||||
| You can find prebuilt govc binaries on the [releases page](https://github.com/vmware/govmomi/releases). | ||||
| 
 | ||||
| Download and install a binary locally like this: | ||||
| 
 | ||||
| ```sh | ||||
| curl $URL_TO_BINARY | gzip -d > /usr/local/bin/govc | ||||
| chmod +x /usr/local/bin/govc | ||||
| ``` | ||||
| 
 | ||||
| ### Source | ||||
| 
 | ||||
| You can install the latest govc version from source if you have the Go toolchain installed. | ||||
| 
 | ||||
| ```sh | ||||
| go get github.com/vmware/govmomi/govc | ||||
| ``` | ||||
| 
 | ||||
| (make sure `$GOPATH/bin` is in your `PATH`) | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| govc exposes its functionality through subcommands. Option flags | ||||
| to these subcommands are often shared. | ||||
| 
 | ||||
| Common flags include: | ||||
| 
 | ||||
| * `-u`: ESXi or vCenter URL (ex: `user:pass@host`) | ||||
| * `-debug`: Trace requests and responses (to `~/.govmomi/debug`) | ||||
| 
 | ||||
| Managed entities can be referred to by their absolute path or by their relative | ||||
| path. For example, when specifying a datastore to use for a subcommand, you can | ||||
| either specify it as `/mydatacenter/datastore/mydatastore`, or as | ||||
| `mydatastore`. If you're not sure about the name of the datastore, or even the | ||||
| full path to the datastore, you can specify a pattern to match. Both | ||||
| `/*center/*/my*` (absolute) and `my*store` (relative) will resolve to the same | ||||
| datastore, given there are no other datastores that match those globs. | ||||
| 
 | ||||
| The relative path in this example can only be used if the command can | ||||
| umambigously resolve a datacenter to use as origin for the query. If no | ||||
| datacenter is specified, govc defaults to the only datacenter, if there is only | ||||
| one. The datacenter itself can be specified as a pattern as well, enabling the | ||||
| following arguments: `-dc='my*' -ds='*store'`. The datastore pattern is looked | ||||
| up and matched relative to the datacenter which itself is specified as a | ||||
| pattern. | ||||
| 
 | ||||
| Besides specifying managed entities as arguments, they can also be specified | ||||
| using environment variables. The following environment variables are used by govc | ||||
| to set defaults: | ||||
| 
 | ||||
| * `GOVC_USERNAME`: USERNAME to use. | ||||
| 
 | ||||
| * `GOVC_PASSWORD`: PASSWORD to use. | ||||
| 
 | ||||
| * `GOVC_URL`: URL of ESXi or vCenter instance to connect to. | ||||
| 
 | ||||
|   > The URL scheme defaults to `https` and the URL path defaults to `/sdk`. | ||||
|   > This means that specifying `user:pass@host` is equivalent to | ||||
|   > `https://user:pass@host/sdk`. | ||||
|    | ||||
|   > If password include special characters like `#` or `:` you can use | ||||
|   > `GOVC_USERNAME` and `GOVC_PASSWORD` to have a simple `GOVC_URL` | ||||
|    | ||||
| * `GOVC_INSECURE`: Allow establishing insecure connections. | ||||
| 
 | ||||
|   > Use this option when the host you're connecting is using self-signed | ||||
|   > certificates, or is otherwise trusted. Set this option to `1` to enable. | ||||
| 
 | ||||
| * `GOVC_DATACENTER` | ||||
| 
 | ||||
| * `GOVC_DATASTORE` | ||||
| 
 | ||||
| * `GOVC_NETWORK` | ||||
| 
 | ||||
| * `GOVC_RESOURCE_POOL` | ||||
| 
 | ||||
| * `GOVC_HOST` | ||||
| 
 | ||||
| * `GOVC_GUEST_LOGIN`: Guest credentials for guest operations | ||||
| 
 | ||||
| ## Examples | ||||
| 
 | ||||
| * About | ||||
|   ``` | ||||
|   $ export GOVC_URL="192.168.1.20" | ||||
|   $ export GOVC_USERNAME="domain\administrator" | ||||
|   $ export GOVC_PASSWORD="Password123#" | ||||
|   $ govc about | ||||
|    | ||||
|   Name:         VMware vCenter Server | ||||
|   Vendor:       VMware, Inc. | ||||
|   Version:      6.0.0 | ||||
|   Build:        2656761 | ||||
|   OS type:      linux-x64 | ||||
|   API type:     VirtualCenter | ||||
|   API version:  6.0 | ||||
|   Product ID:   vpx | ||||
|   UUID:         c9f0242f-10e3-4e10-85d7-5eea7c855188 | ||||
|   ``` | ||||
| 
 | ||||
| * [Upload ssh public key to a VM](examples/lib/ssh.sh) | ||||
| 
 | ||||
| * [Create and configure a vCenter VM](examples/vcsa.sh) | ||||
| 
 | ||||
| ## Projects using govc | ||||
| 
 | ||||
| * [Kubernetes vSphere Provider](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/cluster/vsphere) | ||||
| 
 | ||||
| ## License | ||||
| 
 | ||||
| govc is available under the [Apache 2 license](../LICENSE). | ||||
|  | @ -0,0 +1,59 @@ | |||
| /* | ||||
| 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 about | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| ) | ||||
| 
 | ||||
| type about struct { | ||||
| 	*flags.ClientFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("about", &about{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *about) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *about) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *about) Run(f *flag.FlagSet) error { | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	a := c.ServiceContent.About | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 	fmt.Fprintf(tw, "Name:\t%s\n", a.Name) | ||||
| 	fmt.Fprintf(tw, "Vendor:\t%s\n", a.Vendor) | ||||
| 	fmt.Fprintf(tw, "Version:\t%s\n", a.Version) | ||||
| 	fmt.Fprintf(tw, "Build:\t%s\n", a.Build) | ||||
| 	fmt.Fprintf(tw, "OS type:\t%s\n", a.OsType) | ||||
| 	fmt.Fprintf(tw, "API type:\t%s\n", a.ApiType) | ||||
| 	fmt.Fprintf(tw, "API version:\t%s\n", a.ApiVersion) | ||||
| 	fmt.Fprintf(tw, "Product ID:\t%s\n", a.ProductLineId) | ||||
| 	fmt.Fprintf(tw, "UUID:\t%s\n", a.InstanceUuid) | ||||
| 	return tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,22 @@ | |||
| #!/bin/bash -e | ||||
| 
 | ||||
| if ! which gox > /dev/null; then | ||||
|   echo "gox is not installed..." | ||||
|   exit 1 | ||||
| fi | ||||
| 
 | ||||
| git_version=$(git describe) | ||||
| if git_status=$(git status --porcelain 2>/dev/null) && [ -n "${git_status}" ]; then | ||||
|   git_version="${git_version}-dirty" | ||||
| fi | ||||
| 
 | ||||
| ldflags="-X github.com/vmware/govmomi/govc/version.gitVersion ${git_version}" | ||||
| BUILD_OS=${BUILD_OS:-darwin linux windows freebsd} | ||||
| BUILD_ARCH=${BUILD_ARCH:-386 amd64} | ||||
| 
 | ||||
| gox \ | ||||
|   -parallel=1 \ | ||||
|   -ldflags="${ldflags}" \ | ||||
|   -os="${BUILD_OS}" \ | ||||
|   -arch="${BUILD_ARCH}" \ | ||||
|   github.com/vmware/govmomi/govc | ||||
|  | @ -0,0 +1,170 @@ | |||
| /* | ||||
| 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 cli | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"text/tabwriter" | ||||
| ) | ||||
| 
 | ||||
| type HasFlags interface { | ||||
| 	// Register may be called more than once and should be idempotent.
 | ||||
| 	Register(f *flag.FlagSet) | ||||
| 
 | ||||
| 	// Process may be called more than once and should be idempotent.
 | ||||
| 	Process() error | ||||
| } | ||||
| 
 | ||||
| type Command interface { | ||||
| 	HasFlags | ||||
| 
 | ||||
| 	Run(f *flag.FlagSet) error | ||||
| } | ||||
| 
 | ||||
| var hasFlagsType = reflect.TypeOf((*HasFlags)(nil)).Elem() | ||||
| 
 | ||||
| func RegisterCommand(h HasFlags, f *flag.FlagSet) { | ||||
| 	visited := make(map[interface{}]struct{}) | ||||
| 	Walk(h, hasFlagsType, func(v interface{}) error { | ||||
| 		if _, ok := visited[v]; ok { | ||||
| 			return nil | ||||
| 		} | ||||
| 		visited[v] = struct{}{} | ||||
| 		v.(HasFlags).Register(f) | ||||
| 		return nil | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func ProcessCommand(h HasFlags) error { | ||||
| 	visited := make(map[interface{}]struct{}) | ||||
| 	err := Walk(h, hasFlagsType, func(v interface{}) error { | ||||
| 		if _, ok := visited[v]; ok { | ||||
| 			return nil | ||||
| 		} | ||||
| 		visited[v] = struct{}{} | ||||
| 		err := v.(HasFlags).Process() | ||||
| 		return err | ||||
| 	}) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func generalHelp() { | ||||
| 	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) | ||||
| 
 | ||||
| 	cmds := []string{} | ||||
| 	for name := range commands { | ||||
| 		cmds = append(cmds, name) | ||||
| 	} | ||||
| 
 | ||||
| 	sort.Strings(cmds) | ||||
| 
 | ||||
| 	for _, name := range cmds { | ||||
| 		fmt.Fprintf(os.Stderr, "  %s\n", name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func commandHelp(name string, cmd Command, f *flag.FlagSet) { | ||||
| 	type HasUsage interface { | ||||
| 		Usage() string | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Fprintf(os.Stderr, "Usage: %s %s [OPTIONS]", os.Args[0], name) | ||||
| 	if u, ok := cmd.(HasUsage); ok { | ||||
| 		fmt.Fprintf(os.Stderr, " %s", u.Usage()) | ||||
| 	} | ||||
| 	fmt.Fprintf(os.Stderr, "\n") | ||||
| 
 | ||||
| 	type HasDescription interface { | ||||
| 		Description() string | ||||
| 	} | ||||
| 
 | ||||
| 	if u, ok := cmd.(HasDescription); ok { | ||||
| 		fmt.Fprintf(os.Stderr, "%s\n", u.Description()) | ||||
| 	} | ||||
| 
 | ||||
| 	n := 0 | ||||
| 	f.VisitAll(func(_ *flag.Flag) { | ||||
| 		n += 1 | ||||
| 	}) | ||||
| 
 | ||||
| 	if n > 0 { | ||||
| 		fmt.Fprintf(os.Stderr, "\nOptions:\n") | ||||
| 		tw := tabwriter.NewWriter(os.Stderr, 2, 0, 2, ' ', 0) | ||||
| 		f.VisitAll(func(f *flag.Flag) { | ||||
| 			fmt.Fprintf(tw, "\t-%s=%s\t%s\n", f.Name, f.DefValue, f.Usage) | ||||
| 		}) | ||||
| 		tw.Flush() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func Run(args []string) int { | ||||
| 	if len(args) == 0 { | ||||
| 		generalHelp() | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	// Look up real command name in aliases table.
 | ||||
| 	name, ok := aliases[args[0]] | ||||
| 	if !ok { | ||||
| 		name = args[0] | ||||
| 	} | ||||
| 
 | ||||
| 	cmd, ok := commands[name] | ||||
| 	if !ok { | ||||
| 		generalHelp() | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	f := flag.NewFlagSet("", flag.ContinueOnError) | ||||
| 	f.SetOutput(ioutil.Discard) | ||||
| 
 | ||||
| 	RegisterCommand(cmd, f) | ||||
| 
 | ||||
| 	if err := f.Parse(args[1:]); err != nil { | ||||
| 		if err == flag.ErrHelp { | ||||
| 			commandHelp(args[0], cmd, f) | ||||
| 		} else { | ||||
| 			fmt.Fprintf(os.Stderr, "Error: %s\n", err) | ||||
| 		} | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	if err := ProcessCommand(cmd); err != nil { | ||||
| 		if err == flag.ErrHelp { | ||||
| 			commandHelp(args[0], cmd, f) | ||||
| 		} else { | ||||
| 			fmt.Fprintf(os.Stderr, "Error: %s\n", err) | ||||
| 		} | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	if err := cmd.Run(f); err != nil { | ||||
| 		if err == flag.ErrHelp { | ||||
| 			commandHelp(args[0], cmd, f) | ||||
| 		} else { | ||||
| 			fmt.Fprintf(os.Stderr, "Error: %s\n", err) | ||||
| 		} | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	return 0 | ||||
| } | ||||
|  | @ -0,0 +1,33 @@ | |||
| /* | ||||
| 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 cli | ||||
| 
 | ||||
| var commands = map[string]Command{} | ||||
| 
 | ||||
| var aliases = map[string]string{} | ||||
| 
 | ||||
| func Register(name string, c Command) { | ||||
| 	commands[name] = c | ||||
| } | ||||
| 
 | ||||
| func Alias(name string, alias string) { | ||||
| 	aliases[alias] = name | ||||
| } | ||||
| 
 | ||||
| func Commands() map[string]Command { | ||||
| 	return commands | ||||
| } | ||||
|  | @ -0,0 +1,108 @@ | |||
| /* | ||||
| 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 cli | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| ) | ||||
| 
 | ||||
| type WalkFn func(c interface{}) error | ||||
| 
 | ||||
| // Walk recursively walks struct types that implement the specified interface.
 | ||||
| // Fields that implement the specified interface are expected to be pointer
 | ||||
| // values. This allows the function to cache pointer values on a per-type
 | ||||
| // basis. If, during a recursive walk, the same type is encountered twice, the
 | ||||
| // function creates a new value of that type the first time, and reuses that
 | ||||
| // same value the second time.
 | ||||
| //
 | ||||
| // This function is used to make sure that a hierarchy of flags where multiple
 | ||||
| // structs refer to the `Client` flag will not end up with more than one
 | ||||
| // instance of the actual client. Rather, every struct referring to the
 | ||||
| // `Client` flag will have a pointer to the same underlying `Client` struct.
 | ||||
| //
 | ||||
| func Walk(c interface{}, ifaceType reflect.Type, fn WalkFn) error { | ||||
| 	var walker WalkFn | ||||
| 
 | ||||
| 	visited := make(map[reflect.Type]reflect.Value) | ||||
| 	walker = func(c interface{}) error { | ||||
| 		v := reflect.ValueOf(c) | ||||
| 		if v.Kind() == reflect.Interface { | ||||
| 			v = v.Elem() | ||||
| 		} | ||||
| 		if v.Kind() == reflect.Ptr { | ||||
| 			v = v.Elem() | ||||
| 		} | ||||
| 
 | ||||
| 		t := v.Type() | ||||
| 
 | ||||
| 		// Call user specified function.
 | ||||
| 		err := fn(c) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		for i := 0; i < t.NumField(); i++ { | ||||
| 			ff := t.Field(i) | ||||
| 			ft := ff.Type | ||||
| 			fv := v.Field(i) | ||||
| 
 | ||||
| 			// Check that a pointer to this field's type doesn't implement the
 | ||||
| 			// specified interface. If it does, this field references the type as
 | ||||
| 			// value. This is not allowed because it prohibits a value from being
 | ||||
| 			// shared among multiple structs that reference it.
 | ||||
| 			//
 | ||||
| 			// For example: if a struct has two fields of the same type, they must
 | ||||
| 			// both point to the same value after this routine has executed. If these
 | ||||
| 			// fields are not a pointer type, the value cannot be shared.
 | ||||
| 			//
 | ||||
| 			if reflect.PtrTo(ft).Implements(ifaceType) { | ||||
| 				panic(fmt.Sprintf(`field "%s" in struct "%s" must be a pointer`, ff.Name, v.Type())) | ||||
| 			} | ||||
| 
 | ||||
| 			// Type must implement specified interface.
 | ||||
| 			if !ft.Implements(ifaceType) { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// Type must be a pointer.
 | ||||
| 			if ft.Kind() != reflect.Ptr { | ||||
| 				panic(fmt.Sprintf(`field "%s" in struct "%s" must be a pointer`, ff.Name, v.Type())) | ||||
| 			} | ||||
| 
 | ||||
| 			// Have not seen this type before, create a value.
 | ||||
| 			if _, ok := visited[ft]; !ok { | ||||
| 				visited[ft] = reflect.New(ft.Elem()) | ||||
| 			} | ||||
| 
 | ||||
| 			// Make sure current field is set.
 | ||||
| 			if fv.IsNil() { | ||||
| 				fv.Set(visited[ft]) | ||||
| 			} | ||||
| 
 | ||||
| 			// Recurse.
 | ||||
| 			err := walker(fv.Interface()) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	return walker(c) | ||||
| } | ||||
|  | @ -0,0 +1,77 @@ | |||
| /* | ||||
| 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 datacenter | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/find" | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type create struct { | ||||
| 	*flags.ClientFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datacenter.create", &create{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *create) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *create) Usage() string { | ||||
| 	return "[DATACENTER NAME]..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *create) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *create) Run(f *flag.FlagSet) error { | ||||
| 	datacenters := f.Args() | ||||
| 	if len(datacenters) < 1 { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	client, err := cmd.ClientFlag.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	finder := find.NewFinder(client, false) | ||||
| 	rootFolder := object.NewRootFolder(client) | ||||
| 	for _, datacenterToCreate := range datacenters { | ||||
| 		_, err := finder.Datacenter(context.TODO(), datacenterToCreate) | ||||
| 		if err == nil { | ||||
| 			// The datacenter was found, no need to create it
 | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		switch err.(type) { | ||||
| 		case *find.NotFoundError: | ||||
| 			_, err = rootFolder.CreateDatacenter(context.TODO(), datacenterToCreate) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		default: | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -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 datacenter | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/find" | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type destroy struct { | ||||
| 	*flags.ClientFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datacenter.destroy", &destroy{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *destroy) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *destroy) Usage() string { | ||||
| 	return "[DATACENTER NAME]..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *destroy) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *destroy) Run(f *flag.FlagSet) error { | ||||
| 	if len(f.Args()) < 1 { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 	datacentersToDestroy := f.Args() | ||||
| 
 | ||||
| 	client, err := cmd.ClientFlag.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	finder := find.NewFinder(client, false) | ||||
| 	for _, datacenterToDestroy := range datacentersToDestroy { | ||||
| 		foundDatacenters, err := finder.DatacenterList(context.TODO(), datacenterToDestroy) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		for _, foundDatacenter := range foundDatacenters { | ||||
| 			task, err := foundDatacenter.Destroy(context.TODO()) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			if err := task.Wait(context.TODO()); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,85 @@ | |||
| /* | ||||
| 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 datastore | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type cp struct { | ||||
| 	*flags.OutputFlag | ||||
| 	*flags.DatastoreFlag | ||||
| 
 | ||||
| 	force bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datastore.cp", &cp{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *cp) Register(f *flag.FlagSet) { | ||||
| 	f.BoolVar(&cmd.force, "f", false, "If true, overwrite any identically named file at the destination") | ||||
| } | ||||
| 
 | ||||
| func (cmd *cp) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *cp) Usage() string { | ||||
| 	return "SRC DST" | ||||
| } | ||||
| 
 | ||||
| func (cmd *cp) Run(f *flag.FlagSet) error { | ||||
| 	args := f.Args() | ||||
| 	if len(args) != 2 { | ||||
| 		return errors.New("SRC and DST arguments are required") | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	dc, err := cmd.Datacenter() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: support cross-datacenter copy
 | ||||
| 
 | ||||
| 	src, err := cmd.DatastorePath(args[0]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	dst, err := cmd.DatastorePath(args[1]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m := object.NewFileManager(c) | ||||
| 	task, err := m.CopyDatastoreFile(context.TODO(), src, dc, dst, dc, cmd.force) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return task.Wait(context.TODO()) | ||||
| } | ||||
|  | @ -0,0 +1,68 @@ | |||
| /* | ||||
| 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 datastore | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/vim25/soap" | ||||
| ) | ||||
| 
 | ||||
| type download struct { | ||||
| 	*flags.DatastoreFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datastore.download", &download{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *download) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *download) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *download) Usage() string { | ||||
| 	return "REMOTE LOCAL" | ||||
| } | ||||
| 
 | ||||
| func (cmd *download) Run(f *flag.FlagSet) error { | ||||
| 	args := f.Args() | ||||
| 	if len(args) != 2 { | ||||
| 		return errors.New("invalid arguments") | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	u, err := cmd.DatastoreURL(args[0]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	p := soap.DefaultDownload | ||||
| 	if cmd.OutputFlag.TTY { | ||||
| 		logger := cmd.ProgressLogger("Downloading... ") | ||||
| 		p.Progress = logger | ||||
| 		defer logger.Wait() | ||||
| 	} | ||||
| 
 | ||||
| 	return c.Client.DownloadFile(args[1], u, &p) | ||||
| } | ||||
|  | @ -0,0 +1,120 @@ | |||
| /* | ||||
| 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 datastore | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/property" | ||||
| 	"github.com/vmware/govmomi/vim25/mo" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type info struct { | ||||
| 	*flags.ClientFlag | ||||
| 	*flags.OutputFlag | ||||
| 	*flags.DatacenterFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datastore.info", &info{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *info) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *info) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *info) Usage() string { | ||||
| 	return "[PATH]..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *info) Run(f *flag.FlagSet) error { | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := context.TODO() | ||||
| 
 | ||||
| 	finder, err := cmd.Finder() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	args := f.Args() | ||||
| 	if len(args) == 0 { | ||||
| 		args = []string{"*"} | ||||
| 	} | ||||
| 
 | ||||
| 	datastores, err := finder.DatastoreList(ctx, args[0]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	refs := make([]types.ManagedObjectReference, 0, len(datastores)) | ||||
| 	for _, ds := range datastores { | ||||
| 		refs = append(refs, ds.Reference()) | ||||
| 	} | ||||
| 
 | ||||
| 	var res infoResult | ||||
| 	var props []string | ||||
| 
 | ||||
| 	if cmd.OutputFlag.JSON { | ||||
| 		props = nil // Load everything
 | ||||
| 	} else { | ||||
| 		props = []string{"info", "summary"} // Load summary
 | ||||
| 	} | ||||
| 
 | ||||
| 	pc := property.DefaultCollector(c) | ||||
| 	err = pc.Retrieve(ctx, refs, props, &res.Datastores) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd.WriteResult(&res) | ||||
| } | ||||
| 
 | ||||
| type infoResult struct { | ||||
| 	Datastores []mo.Datastore | ||||
| } | ||||
| 
 | ||||
| func (r *infoResult) Write(w io.Writer) error { | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	for _, ds := range r.Datastores { | ||||
| 		s := ds.Summary | ||||
| 		fmt.Fprintf(tw, "Name:\t%s\n", s.Name) | ||||
| 		fmt.Fprintf(tw, "  Type:\t%s\n", s.Type) | ||||
| 		fmt.Fprintf(tw, "  URL:\t%s\n", s.Url) | ||||
| 		fmt.Fprintf(tw, "  Capacity:\t%.1f GB\n", float64(s.Capacity)/(1<<30)) | ||||
| 		fmt.Fprintf(tw, "  Free:\t%.1f GB\n", float64(s.FreeSpace)/(1<<30)) | ||||
| 
 | ||||
| 		switch info := ds.Info.(type) { | ||||
| 		case *types.NasDatastoreInfo: | ||||
| 			fmt.Fprintf(tw, "  Remote:\t%s:%s\n", info.Nas.RemoteHost, info.Nas.RemotePath) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,197 @@ | |||
| /* | ||||
| 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 datastore | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"path" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/units" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type ls struct { | ||||
| 	*flags.DatastoreFlag | ||||
| 	*flags.OutputFlag | ||||
| 
 | ||||
| 	long bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datastore.ls", &ls{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *ls) Register(f *flag.FlagSet) { | ||||
| 	f.BoolVar(&cmd.long, "l", false, "Long listing format") | ||||
| } | ||||
| 
 | ||||
| func (cmd *ls) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *ls) Usage() string { | ||||
| 	return "[FILE]..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *ls) Run(f *flag.FlagSet) error { | ||||
| 	ds, err := cmd.Datastore() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	b, err := ds.Browser(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	args := f.Args() | ||||
| 	if len(args) == 0 { | ||||
| 		args = []string{""} | ||||
| 	} | ||||
| 
 | ||||
| 	result := &listOutput{ | ||||
| 		rs:   make([]types.HostDatastoreBrowserSearchResults, 0), | ||||
| 		long: cmd.long, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, arg := range args { | ||||
| 		spec := types.HostDatastoreBrowserSearchSpec{ | ||||
| 			MatchPattern: []string{"*"}, | ||||
| 		} | ||||
| 
 | ||||
| 		if cmd.long { | ||||
| 			spec.Details = &types.FileQueryFlags{ | ||||
| 				FileType:     true, | ||||
| 				FileSize:     true, | ||||
| 				FileOwner:    types.NewBool(true), // TODO: omitempty is generated, but seems to be required
 | ||||
| 				Modification: true, | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for i := 0; ; i++ { | ||||
| 			r, err := cmd.ListPath(b, arg, spec) | ||||
| 			if err != nil { | ||||
| 				// Treat the argument as a match pattern if not found as directory
 | ||||
| 				if i == 0 && types.IsFileNotFound(err) { | ||||
| 					spec.MatchPattern[0] = path.Base(arg) | ||||
| 					arg = path.Dir(arg) | ||||
| 					continue | ||||
| 				} | ||||
| 
 | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Treat an empty result against match pattern as file not found
 | ||||
| 			if i == 1 && len(r.File) == 0 { | ||||
| 				return fmt.Errorf("File %s/%s was not found", r.FolderPath, spec.MatchPattern[0]) | ||||
| 			} | ||||
| 
 | ||||
| 			result.add(r) | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd.WriteResult(result) | ||||
| } | ||||
| 
 | ||||
| func (cmd *ls) ListPath(b *object.HostDatastoreBrowser, path string, spec types.HostDatastoreBrowserSearchSpec) (types.HostDatastoreBrowserSearchResults, error) { | ||||
| 	var res types.HostDatastoreBrowserSearchResults | ||||
| 
 | ||||
| 	path, err := cmd.DatastorePath(path) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	task, err := b.SearchDatastore(context.TODO(), path, &spec) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	info, err := task.WaitForResult(context.TODO(), nil) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	res = info.Result.(types.HostDatastoreBrowserSearchResults) | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| type listOutput struct { | ||||
| 	rs   []types.HostDatastoreBrowserSearchResults | ||||
| 	long bool | ||||
| } | ||||
| 
 | ||||
| func (o *listOutput) add(r types.HostDatastoreBrowserSearchResults) { | ||||
| 	o.rs = append(o.rs, r) | ||||
| } | ||||
| 
 | ||||
| // hasMultiplePaths returns whether or not the slice of search results contains
 | ||||
| // results from more than one folder path.
 | ||||
| func (o *listOutput) hasMultiplePaths() bool { | ||||
| 	if len(o.rs) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	p := o.rs[0].FolderPath | ||||
| 
 | ||||
| 	// Multiple paths if any entry is not equal to the first one.
 | ||||
| 	for _, e := range o.rs { | ||||
| 		if e.FolderPath != p { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (o *listOutput) MarshalJSON() ([]byte, error) { | ||||
| 	return json.Marshal(o.rs) | ||||
| } | ||||
| 
 | ||||
| func (o *listOutput) Write(w io.Writer) error { | ||||
| 	// Only include path header if we're dealing with more than one path.
 | ||||
| 	includeHeader := false | ||||
| 	if o.hasMultiplePaths() { | ||||
| 		includeHeader = true | ||||
| 	} | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(w, 3, 0, 2, ' ', 0) | ||||
| 	for i, r := range o.rs { | ||||
| 		if includeHeader { | ||||
| 			if i > 0 { | ||||
| 				fmt.Fprintf(tw, "\n") | ||||
| 			} | ||||
| 			fmt.Fprintf(tw, "%s:\n", r.FolderPath) | ||||
| 		} | ||||
| 		for _, file := range r.File { | ||||
| 			info := file.GetFileInfo() | ||||
| 			if o.long { | ||||
| 				fmt.Fprintf(tw, "%s\t%s\t%s\n", units.ByteSize(info.FileSize), info.Modification.Format("Mon Jan 2 15:04:05 2006"), info.Path) | ||||
| 			} else { | ||||
| 				fmt.Fprintf(tw, "%s\n", info.Path) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	tw.Flush() | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,87 @@ | |||
| /* | ||||
| 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 datastore | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25/soap" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type mkdir struct { | ||||
| 	*flags.DatastoreFlag | ||||
| 
 | ||||
| 	createParents bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datastore.mkdir", &mkdir{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *mkdir) Register(f *flag.FlagSet) { | ||||
| 	f.BoolVar(&cmd.createParents, "p", false, "Create intermediate directories as needed") | ||||
| } | ||||
| 
 | ||||
| func (cmd *mkdir) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *mkdir) Usage() string { | ||||
| 	return "DIRECTORY" | ||||
| } | ||||
| 
 | ||||
| func (cmd *mkdir) Run(f *flag.FlagSet) error { | ||||
| 	args := f.Args() | ||||
| 	if len(args) == 0 { | ||||
| 		return errors.New("missing operand") | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	dc, err := cmd.Datacenter() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(PN): Accept multiple args
 | ||||
| 	path, err := cmd.DatastorePath(args[0]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m := object.NewFileManager(c) | ||||
| 	err = m.MakeDirectory(context.TODO(), path, dc, cmd.createParents) | ||||
| 
 | ||||
| 	// ignore EEXIST if -p flag is given
 | ||||
| 	if err != nil && cmd.createParents { | ||||
| 		if soap.IsSoapFault(err) { | ||||
| 			soapFault := soap.ToSoapFault(err) | ||||
| 			if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
|  | @ -0,0 +1,84 @@ | |||
| /* | ||||
| 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 datastore | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type mv struct { | ||||
| 	*flags.DatastoreFlag | ||||
| 
 | ||||
| 	force bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datastore.mv", &mv{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *mv) Register(f *flag.FlagSet) { | ||||
| 	f.BoolVar(&cmd.force, "f", false, "If true, overwrite any identically named file at the destination") | ||||
| } | ||||
| 
 | ||||
| func (cmd *mv) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *mv) Usage() string { | ||||
| 	return "SRC DST" | ||||
| } | ||||
| 
 | ||||
| func (cmd *mv) Run(f *flag.FlagSet) error { | ||||
| 	args := f.Args() | ||||
| 	if len(args) != 2 { | ||||
| 		return errors.New("SRC and DST arguments are required") | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	dc, err := cmd.Datacenter() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: support cross-datacenter move
 | ||||
| 
 | ||||
| 	src, err := cmd.DatastorePath(args[0]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	dst, err := cmd.DatastorePath(args[1]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m := object.NewFileManager(c) | ||||
| 	task, err := m.MoveDatastoreFile(context.TODO(), src, dc, dst, dc, cmd.force) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return task.Wait(context.TODO()) | ||||
| } | ||||
|  | @ -0,0 +1,88 @@ | |||
| /* | ||||
| 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 datastore | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type rm struct { | ||||
| 	*flags.DatastoreFlag | ||||
| 
 | ||||
| 	force bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datastore.rm", &rm{}) | ||||
| 	cli.Alias("datastore.rm", "datastore.delete") | ||||
| } | ||||
| 
 | ||||
| func (cmd *rm) Register(f *flag.FlagSet) { | ||||
| 	f.BoolVar(&cmd.force, "f", false, "Force; ignore nonexistent files and arguments") | ||||
| } | ||||
| 
 | ||||
| func (cmd *rm) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *rm) Usage() string { | ||||
| 	return "FILE" | ||||
| } | ||||
| 
 | ||||
| func (cmd *rm) Run(f *flag.FlagSet) error { | ||||
| 	args := f.Args() | ||||
| 	if len(args) == 0 { | ||||
| 		return errors.New("missing operand") | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	dc, err := cmd.Datacenter() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(PN): Accept multiple args
 | ||||
| 	path, err := cmd.DatastorePath(args[0]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m := object.NewFileManager(c) | ||||
| 	task, err := m.DeleteDatastoreFile(context.TODO(), path, dc) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = task.Wait(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		if types.IsFileNotFound(err) && cmd.force { | ||||
| 			// Ignore error
 | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
|  | @ -0,0 +1,69 @@ | |||
| /* | ||||
| 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 datastore | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/vim25/soap" | ||||
| ) | ||||
| 
 | ||||
| type upload struct { | ||||
| 	*flags.OutputFlag | ||||
| 	*flags.DatastoreFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("datastore.upload", &upload{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *upload) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *upload) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *upload) Usage() string { | ||||
| 	return "LOCAL REMOTE" | ||||
| } | ||||
| 
 | ||||
| func (cmd *upload) Run(f *flag.FlagSet) error { | ||||
| 	args := f.Args() | ||||
| 	if len(args) != 2 { | ||||
| 		return errors.New("invalid arguments") | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	u, err := cmd.DatastoreURL(args[1]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	p := soap.DefaultUpload | ||||
| 	if cmd.OutputFlag.TTY { | ||||
| 		logger := cmd.ProgressLogger("Uploading... ") | ||||
| 		p.Progress = logger | ||||
| 		defer logger.Wait() | ||||
| 	} | ||||
| 
 | ||||
| 	return c.Client.UploadFile(args[0], u, &p) | ||||
| } | ||||
|  | @ -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 device | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type boot struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	order string | ||||
| 	types.VirtualMachineBootOptions | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.boot", &boot{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *boot) Register(f *flag.FlagSet) { | ||||
| 	f.Int64Var(&cmd.BootDelay, "delay", 0, "Delay in ms before starting the boot sequence") | ||||
| 	f.StringVar(&cmd.order, "order", "", "Boot device order") | ||||
| 	f.Int64Var(&cmd.BootRetryDelay, "retry-delay", 0, "Delay in ms before a boot retry") | ||||
| 
 | ||||
| 	cmd.BootRetryEnabled = types.NewBool(false) | ||||
| 	f.BoolVar(cmd.BootRetryEnabled, "retry", false, "If true, retry boot after retry-delay") | ||||
| 
 | ||||
| 	cmd.EnterBIOSSetup = types.NewBool(false) | ||||
| 	f.BoolVar(cmd.EnterBIOSSetup, "setup", false, "If true, enter BIOS setup on next boot") | ||||
| } | ||||
| 
 | ||||
| func (cmd *boot) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *boot) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if cmd.order != "" { | ||||
| 		o := strings.Split(cmd.order, ",") | ||||
| 		cmd.BootOrder = devices.BootOrder(o) | ||||
| 	} | ||||
| 
 | ||||
| 	return vm.SetBootOptions(context.TODO(), &cmd.VirtualMachineBootOptions) | ||||
| } | ||||
|  | @ -0,0 +1,87 @@ | |||
| /* | ||||
| 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 cdrom | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	controller string | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.cdrom.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.controller, "controller", "", "IDE controller name") | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := devices.FindIDEController(cmd.controller) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	d, err := devices.CreateCdrom(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = vm.AddDevice(context.TODO(), d) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// output name of device we just created
 | ||||
| 	devices, err = vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	devices = devices.SelectByType(d) | ||||
| 
 | ||||
| 	name := devices.Name(devices[len(devices)-1]) | ||||
| 
 | ||||
| 	fmt.Println(name) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,70 @@ | |||
| /* | ||||
| 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 cdrom | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type eject struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	device string | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.cdrom.eject", &eject{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *eject) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.device, "device", "", "CD-ROM device name") | ||||
| } | ||||
| 
 | ||||
| func (cmd *eject) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *eject) Description() string { | ||||
| 	return `Eject media from CD-ROM device. | ||||
| 
 | ||||
| If device is not specified, the first CD-ROM device is used.` | ||||
| } | ||||
| 
 | ||||
| func (cmd *eject) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := devices.FindCdrom(cmd.device) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return vm.EditDevice(context.TODO(), devices.EjectIso(c)) | ||||
| } | ||||
|  | @ -0,0 +1,80 @@ | |||
| /* | ||||
| 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 cdrom | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type insert struct { | ||||
| 	*flags.DatastoreFlag | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	device string | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.cdrom.insert", &insert{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *insert) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.device, "device", "", "CD-ROM device name") | ||||
| } | ||||
| 
 | ||||
| func (cmd *insert) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *insert) Usage() string { | ||||
| 	return "ISO" | ||||
| } | ||||
| 
 | ||||
| func (cmd *insert) Description() string { | ||||
| 	return `Insert media on datastore into CD-ROM device. | ||||
| 
 | ||||
| If device is not specified, the first CD-ROM device is used.` | ||||
| } | ||||
| 
 | ||||
| func (cmd *insert) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil || f.NArg() != 1 { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := devices.FindCdrom(cmd.device) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	iso, err := cmd.DatastorePath(f.Arg(0)) | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	return vm.EditDevice(context.TODO(), devices.InsertIso(c, iso)) | ||||
| } | ||||
|  | @ -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 device | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type connect struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.connect", &connect{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *connect) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *connect) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *connect) Usage() string { | ||||
| 	return "DEVICE..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *connect) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, name := range f.Args() { | ||||
| 		device := devices.Find(name) | ||||
| 		if device == nil { | ||||
| 			return fmt.Errorf("device '%s' not found", name) | ||||
| 		} | ||||
| 
 | ||||
| 		if err = devices.Connect(device); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if err = vm.EditDevice(context.TODO(), device); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -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 device | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type disconnect struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.disconnect", &disconnect{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *disconnect) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *disconnect) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *disconnect) Usage() string { | ||||
| 	return "DEVICE..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *disconnect) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, name := range f.Args() { | ||||
| 		device := devices.Find(name) | ||||
| 		if device == nil { | ||||
| 			return fmt.Errorf("device '%s' not found", name) | ||||
| 		} | ||||
| 
 | ||||
| 		if err = devices.Disconnect(device); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if err = vm.EditDevice(context.TODO(), device); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,78 @@ | |||
| /* | ||||
| 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 floppy | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.floppy.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *add) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	d, err := devices.CreateFloppy() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = vm.AddDevice(context.TODO(), d) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// output name of device we just created
 | ||||
| 	devices, err = vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	devices = devices.SelectByType(d) | ||||
| 
 | ||||
| 	name := devices.Name(devices[len(devices)-1]) | ||||
| 
 | ||||
| 	fmt.Println(name) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,70 @@ | |||
| /* | ||||
| 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 floppy | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type eject struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	device string | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.floppy.eject", &eject{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *eject) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.device, "device", "", "Floppy device name") | ||||
| } | ||||
| 
 | ||||
| func (cmd *eject) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *eject) Description() string { | ||||
| 	return `Eject image from floppy device. | ||||
| 
 | ||||
| If device is not specified, the first floppy device is used.` | ||||
| } | ||||
| 
 | ||||
| func (cmd *eject) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := devices.FindFloppy(cmd.device) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return vm.EditDevice(context.TODO(), devices.EjectImg(c)) | ||||
| } | ||||
|  | @ -0,0 +1,80 @@ | |||
| /* | ||||
| 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 floppy | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type insert struct { | ||||
| 	*flags.DatastoreFlag | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	device string | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.floppy.insert", &insert{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *insert) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.device, "device", "", "Floppy device name") | ||||
| } | ||||
| 
 | ||||
| func (cmd *insert) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *insert) Usage() string { | ||||
| 	return "IMG" | ||||
| } | ||||
| 
 | ||||
| func (cmd *insert) Description() string { | ||||
| 	return `Insert image on datastore into floppy device. | ||||
| 
 | ||||
| If device is not specified, the first floppy device is used.` | ||||
| } | ||||
| 
 | ||||
| func (cmd *insert) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil || f.NArg() != 1 { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := devices.FindFloppy(cmd.device) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	img, err := cmd.DatastorePath(f.Arg(0)) | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	return vm.EditDevice(context.TODO(), devices.InsertImg(c, img)) | ||||
| } | ||||
|  | @ -0,0 +1,115 @@ | |||
| /* | ||||
| 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 device | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type info struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.info", &info{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *info) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *info) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *info) Usage() string { | ||||
| 	return "DEVICE..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *info) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	for _, name := range f.Args() { | ||||
| 		device := devices.Find(name) | ||||
| 		if device == nil { | ||||
| 			return fmt.Errorf("device '%s' not found", name) | ||||
| 		} | ||||
| 
 | ||||
| 		d := device.GetVirtualDevice() | ||||
| 		info := d.DeviceInfo.GetDescription() | ||||
| 
 | ||||
| 		fmt.Fprintf(tw, "Name:\t%s\n", name) | ||||
| 		fmt.Fprintf(tw, "  Type:\t%s\n", devices.TypeName(device)) | ||||
| 		fmt.Fprintf(tw, "  Label:\t%s\n", info.Label) | ||||
| 		fmt.Fprintf(tw, "  Summary:\t%s\n", info.Summary) | ||||
| 		fmt.Fprintf(tw, "  Key:\t%d\n", d.Key) | ||||
| 
 | ||||
| 		if c, ok := device.(types.BaseVirtualController); ok { | ||||
| 			var attached []string | ||||
| 			for _, key := range c.GetVirtualController().Device { | ||||
| 				attached = append(attached, devices.Name(devices.FindByKey(key))) | ||||
| 			} | ||||
| 			fmt.Fprintf(tw, "  Devices:\t%s\n", strings.Join(attached, ", ")) | ||||
| 		} else { | ||||
| 			if c := devices.FindByKey(d.ControllerKey); c != nil { | ||||
| 				fmt.Fprintf(tw, "  Controller:\t%s\n", devices.Name(c)) | ||||
| 				fmt.Fprintf(tw, "  Unit number:\t%d\n", d.UnitNumber) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if ca := d.Connectable; ca != nil { | ||||
| 			fmt.Fprintf(tw, "  Connected:\t%t\n", ca.Connected) | ||||
| 			fmt.Fprintf(tw, "  Start connected:\t%t\n", ca.StartConnected) | ||||
| 			fmt.Fprintf(tw, "  Guest control:\t%t\n", ca.AllowGuestControl) | ||||
| 			fmt.Fprintf(tw, "  Status:\t%s\n", ca.Status) | ||||
| 		} | ||||
| 
 | ||||
| 		switch md := device.(type) { | ||||
| 		case types.BaseVirtualEthernetCard: | ||||
| 			fmt.Fprintf(tw, "  MAC Address:\t%s\n", md.GetVirtualEthernetCard().MacAddress) | ||||
| 			fmt.Fprintf(tw, "  Address type:\t%s\n", md.GetVirtualEthernetCard().AddressType) | ||||
| 		case *types.VirtualDisk: | ||||
| 			if b, ok := md.Backing.(types.BaseVirtualDeviceFileBackingInfo); ok { | ||||
| 				fmt.Fprintf(tw, "  File:\t%s\n", b.GetVirtualDeviceFileBackingInfo().FileName) | ||||
| 			} | ||||
| 			if b, ok := md.Backing.(*types.VirtualDiskFlatVer2BackingInfo); ok && b.Parent != nil { | ||||
| 				fmt.Fprintf(tw, "  Parent:\t%s\n", b.Parent.GetVirtualDeviceFileBackingInfo().FileName) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,78 @@ | |||
| /* | ||||
| 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 device | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type ls struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	boot bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.ls", &ls{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *ls) Register(f *flag.FlagSet) { | ||||
| 	f.BoolVar(&cmd.boot, "boot", false, "List devices configured in the VM's boot options") | ||||
| } | ||||
| 
 | ||||
| func (cmd *ls) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *ls) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if cmd.boot { | ||||
| 		options, err := vm.BootOptions(context.TODO()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		devices = devices.SelectBootOrder(options.BootOrder) | ||||
| 	} | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 3, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	for _, device := range devices { | ||||
| 		fmt.Fprintf(tw, "%s\t%s\t%s\n", devices.Name(device), devices.TypeName(device), | ||||
| 			device.GetVirtualDevice().DeviceInfo.GetDescription().Summary) | ||||
| 	} | ||||
| 
 | ||||
| 	return tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,71 @@ | |||
| /* | ||||
| 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 device | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type remove struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.remove", &remove{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *remove) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *remove) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *remove) Usage() string { | ||||
| 	return "DEVICE..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *remove) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, name := range f.Args() { | ||||
| 		device := devices.Find(name) | ||||
| 		if device == nil { | ||||
| 			return fmt.Errorf("device '%s' not found", name) | ||||
| 		} | ||||
| 
 | ||||
| 		if err = vm.RemoveDevice(context.TODO(), device); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,99 @@ | |||
| /* | ||||
| 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 scsi | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	controller   string | ||||
| 	sharedBus    string | ||||
| 	hotAddRemove bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.scsi.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) { | ||||
| 	var ctypes []string | ||||
| 	ct := object.SCSIControllerTypes() | ||||
| 	for _, t := range ct { | ||||
| 		ctypes = append(ctypes, ct.Type(t)) | ||||
| 	} | ||||
| 	f.StringVar(&cmd.controller, "type", ct.Type(ct[0]), | ||||
| 		fmt.Sprintf("SCSI controller type (%s)", strings.Join(ctypes, "|"))) | ||||
| 	f.StringVar(&cmd.sharedBus, "sharing", string(types.VirtualSCSISharingNoSharing), "SCSI sharing") | ||||
| 	f.BoolVar(&cmd.hotAddRemove, "hot", false, "Enable hot-add/remove") | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	d, err := devices.CreateSCSIController(cmd.controller) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c := d.(types.BaseVirtualSCSIController).GetVirtualSCSIController() | ||||
| 	c.HotAddRemove = &cmd.hotAddRemove | ||||
| 	c.SharedBus = types.VirtualSCSISharing(cmd.sharedBus) | ||||
| 
 | ||||
| 	err = vm.AddDevice(context.TODO(), d) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// output name of device we just created
 | ||||
| 	devices, err = vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	devices = devices.SelectByType(d) | ||||
| 
 | ||||
| 	name := devices.Name(devices[len(devices)-1]) | ||||
| 
 | ||||
| 	fmt.Println(name) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,78 @@ | |||
| /* | ||||
| 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 serial | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.serial.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *add) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	d, err := devices.CreateSerialPort() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = vm.AddDevice(context.TODO(), d) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// output name of device we just created
 | ||||
| 	devices, err = vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	devices = devices.SelectByType(d) | ||||
| 
 | ||||
| 	name := devices.Name(devices[len(devices)-1]) | ||||
| 
 | ||||
| 	fmt.Println(name) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,66 @@ | |||
| /* | ||||
| 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 serial | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type connect struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	device string | ||||
| 	client bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.serial.connect", &connect{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *connect) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.device, "device", "", "serial port device name") | ||||
| 	f.BoolVar(&cmd.client, "client", false, "Use client direction") | ||||
| } | ||||
| 
 | ||||
| func (cmd *connect) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *connect) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	d, err := devices.FindSerialPort(cmd.device) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return vm.EditDevice(context.TODO(), devices.ConnectSerialPort(d, f.Arg(0), cmd.client)) | ||||
| } | ||||
|  | @ -0,0 +1,64 @@ | |||
| /* | ||||
| 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 serial | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type disconnect struct { | ||||
| 	*flags.VirtualMachineFlag | ||||
| 
 | ||||
| 	device string | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("device.serial.disconnect", &disconnect{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *disconnect) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.device, "device", "", "serial port device name") | ||||
| } | ||||
| 
 | ||||
| func (cmd *disconnect) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *disconnect) Run(f *flag.FlagSet) error { | ||||
| 	vm, err := cmd.VirtualMachine() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if vm == nil { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	devices, err := vm.Device(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	d, err := devices.FindSerialPort(cmd.device) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return vm.EditDevice(context.TODO(), devices.DisconnectSerialPort(d)) | ||||
| } | ||||
|  | @ -0,0 +1,138 @@ | |||
| /* | ||||
| 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 events | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"text/tabwriter" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/event" | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/list" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type events struct { | ||||
| 	*flags.DatacenterFlag | ||||
| 
 | ||||
| 	Max int | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("events", &events{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *events) Register(f *flag.FlagSet) { | ||||
| 	f.IntVar(&cmd.Max, "n", 25, "Output the last N events") | ||||
| } | ||||
| 
 | ||||
| func (cmd *events) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *events) Usage() string { | ||||
| 	return "[PATH]..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *events) Run(f *flag.FlagSet) error { | ||||
| 	ctx := context.TODO() | ||||
| 
 | ||||
| 	finder, err := cmd.Finder() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m := event.NewManager(c) | ||||
| 
 | ||||
| 	var objs []list.Element | ||||
| 
 | ||||
| 	args := f.Args() | ||||
| 	if len(args) == 0 { | ||||
| 		args = []string{"."} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, arg := range args { | ||||
| 		es, err := finder.ManagedObjectList(ctx, arg) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		objs = append(objs, es...) | ||||
| 	} | ||||
| 
 | ||||
| 	var events []types.BaseEvent | ||||
| 
 | ||||
| 	for _, o := range objs { | ||||
| 		filter := types.EventFilterSpec{ | ||||
| 			Entity: &types.EventFilterSpecByEntity{ | ||||
| 				Entity:    o.Object.Reference(), | ||||
| 				Recursion: types.EventFilterSpecRecursionOptionAll, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		collector, err := m.CreateCollectorForEvents(ctx, filter) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("[%s] %s", o.Path, err) | ||||
| 		} | ||||
| 		defer collector.Destroy(ctx) | ||||
| 
 | ||||
| 		err = collector.SetPageSize(ctx, cmd.Max) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		page, err := collector.LatestPage(ctx) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		events = append(events, page...) | ||||
| 	} | ||||
| 
 | ||||
| 	event.Sort(events) | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 3, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	for _, e := range events { | ||||
| 		cat, err := m.EventCategory(ctx, e) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		event := e.GetEvent() | ||||
| 		msg := strings.TrimSpace(event.FullFormattedMessage) | ||||
| 
 | ||||
| 		if t, ok := e.(*types.TaskEvent); ok { | ||||
| 			msg = fmt.Sprintf("%s (target=%s %s)", msg, t.Info.Entity.Type, t.Info.EntityName) | ||||
| 		} | ||||
| 
 | ||||
| 		fmt.Fprintf(tw, "[%s]\t[%s]\t%s\n", | ||||
| 			event.CreatedTime.Local().Format(time.ANSIC), | ||||
| 			cat, msg) | ||||
| 	} | ||||
| 
 | ||||
| 	return tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,44 @@ | |||
| function public-key { | ||||
|   local dir=${HOME}/.ssh | ||||
| 
 | ||||
|   for f in $HOME/.ssh/{id_{rsa,dsa},*}.pub; do | ||||
|     if [ -r $f ]; then | ||||
|       echo $f | ||||
|       return | ||||
|     fi | ||||
|   done | ||||
| 
 | ||||
|   echo "Can't find public key file..." | ||||
|   exit 1 | ||||
| } | ||||
| 
 | ||||
| PUBLIC_KEY_FILE=${PUBLIC_KEY_FILE-$(public-key)} | ||||
| SSH_OPTS="-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oLogLevel=quiet" | ||||
| 
 | ||||
| function upload-public-key { | ||||
|   local vm_name=$1 | ||||
|   local dir=$2 | ||||
| 
 | ||||
|   if [ -z "$dir" ] | ||||
|   then | ||||
|     uid=$(echo $GOVC_GUEST_LOGIN | awk -F: '{print $1}') | ||||
|     dir=$(govc guest.getenv -vm ${vm_name} HOME | awk -F= '{print $2}') | ||||
| 
 | ||||
|     if [ -z "$dir" ] | ||||
|     then | ||||
|       echo "Can't find ${uid}'s HOME dir..." | ||||
|       exit 1 | ||||
|     fi | ||||
|   fi | ||||
| 
 | ||||
|   govc guest.mkdir \ | ||||
|        -vm ${vm_name} \ | ||||
|        -p \ | ||||
|        ${dir}/.ssh | ||||
| 
 | ||||
|   govc guest.upload \ | ||||
|        -vm ${vm_name} \ | ||||
|        -f \ | ||||
|        ${PUBLIC_KEY_FILE} \ | ||||
|        ${dir}/.ssh/authorized_keys | ||||
| } | ||||
|  | @ -0,0 +1,57 @@ | |||
| #!/bin/bash -e | ||||
| 
 | ||||
| lib=$(readlink -nf $(dirname $0))/lib | ||||
| . $lib/ssh.sh | ||||
| 
 | ||||
| ova=$1 | ||||
| 
 | ||||
| if [ -z "$ova" ] | ||||
| then | ||||
|   ova=./VMware-vCenter-Server-Appliance-5.5.0.10300-2000350_OVF10.ova | ||||
| fi | ||||
| 
 | ||||
| # default to local Vagrant esxbox for testing | ||||
| export GOVC_URL=${GOVC_URL-"https://root:vagrant@localhost:8443/sdk"} | ||||
| 
 | ||||
| # default VCSA credentials | ||||
| export GOVC_GUEST_LOGIN=root:vmware | ||||
| 
 | ||||
| # VM name as defined in the VCSA .ovf | ||||
| vm_name=VMware_vCenter_Server_Appliance | ||||
| 
 | ||||
| echo "Importing $ova..." | ||||
| govc import.ova $ova | ||||
| 
 | ||||
| echo "Powering on $vm_name..." | ||||
| govc vm.power -on $vm_name | ||||
| 
 | ||||
| echo "Waiting for $vm_name's IP address..." | ||||
| vc=$(govc vm.ip $vm_name) | ||||
| 
 | ||||
| govc vm.info $vm_name | ||||
| 
 | ||||
| echo "Uploading ssh public key to $vm_name..." | ||||
| upload-public-key $vm_name | ||||
| 
 | ||||
| echo "Configuring vCenter Server Appliance..." | ||||
| 
 | ||||
| # http://www.virtuallyghetto.com/2012/02/automating-vcenter-server-appliance.html | ||||
| ssh ${SSH_OPTS} root@$vc <<EOF | ||||
| echo "Accepting EULA ..." | ||||
| /usr/sbin/vpxd_servicecfg eula accept | ||||
| 
 | ||||
| echo "Configuring Embedded DB ..." | ||||
| /usr/sbin/vpxd_servicecfg db write embedded | ||||
| 
 | ||||
| echo "Configuring SSO..." | ||||
| /usr/sbin/vpxd_servicecfg sso write embedded | ||||
| 
 | ||||
| echo "Starting VCSA ..." | ||||
| /usr/sbin/vpxd_servicecfg service start | ||||
| EOF | ||||
| 
 | ||||
| vc_url=https://${GOVC_GUEST_LOGIN}@${vc}/sdk | ||||
| 
 | ||||
| echo "VCSA configured and ready..." | ||||
| 
 | ||||
| govc about -u $vc_url | ||||
|  | @ -0,0 +1,72 @@ | |||
| /* | ||||
| 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 fields | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*flags.ClientFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("fields.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *add) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *add) Usage() string { | ||||
| 	return "NAME" | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	if f.NArg() != 1 { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := context.TODO() | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m, err := object.GetCustomFieldsManager(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	name := f.Arg(0) | ||||
| 
 | ||||
| 	def, err := m.Add(ctx, name, "", nil, nil) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("%d\n", def.Key) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,68 @@ | |||
| /* | ||||
| 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 fields | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type ls struct { | ||||
| 	*flags.ClientFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("fields.ls", &ls{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *ls) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *ls) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *ls) Run(f *flag.FlagSet) error { | ||||
| 	ctx := context.TODO() | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m, err := object.GetCustomFieldsManager(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	field, err := m.Field(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	for _, def := range field { | ||||
| 		fmt.Fprintf(tw, "%d\t%s\n", def.Key, def.Name) | ||||
| 	} | ||||
| 
 | ||||
| 	return tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,69 @@ | |||
| /* | ||||
| 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 fields | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type rename struct { | ||||
| 	*flags.ClientFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("fields.rename", &rename{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *rename) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *rename) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *rename) Usage() string { | ||||
| 	return "KEY NAME" | ||||
| } | ||||
| 
 | ||||
| func (cmd *rename) Run(f *flag.FlagSet) error { | ||||
| 	if f.NArg() != 2 { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := context.TODO() | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m, err := object.GetCustomFieldsManager(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	key, err := m.FindKey(ctx, f.Arg(0)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	name := f.Arg(1) | ||||
| 
 | ||||
| 	return m.Rename(ctx, key, name) | ||||
| } | ||||
|  | @ -0,0 +1,69 @@ | |||
| /* | ||||
| 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 fields | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type rm struct { | ||||
| 	*flags.ClientFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("fields.rm", &rm{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *rm) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *rm) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *rm) Usage() string { | ||||
| 	return "KEY..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *rm) Run(f *flag.FlagSet) error { | ||||
| 	ctx := context.TODO() | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m, err := object.GetCustomFieldsManager(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, name := range f.Args() { | ||||
| 		key, err := m.FindKey(ctx, name) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if err := m.Remove(ctx, key); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,95 @@ | |||
| /* | ||||
| 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 fields | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/list" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type set struct { | ||||
| 	*flags.DatacenterFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("fields.set", &set{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *set) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *set) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *set) Usage() string { | ||||
| 	return "KEY VALUE PATH..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *set) Run(f *flag.FlagSet) error { | ||||
| 	if f.NArg() < 3 { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := context.TODO() | ||||
| 
 | ||||
| 	finder, err := cmd.Finder() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m, err := object.GetCustomFieldsManager(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var objs []list.Element | ||||
| 
 | ||||
| 	args := f.Args() | ||||
| 
 | ||||
| 	key, err := m.FindKey(ctx, args[0]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	val := args[1] | ||||
| 
 | ||||
| 	for _, arg := range args[2:] { | ||||
| 		es, err := finder.ManagedObjectList(ctx, arg) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		objs = append(objs, es...) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, ref := range objs { | ||||
| 		err := m.Set(ctx, ref.Object.Reference(), key, val) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,366 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/sha1" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/session" | ||||
| 	"github.com/vmware/govmomi/vim25" | ||||
| 	"github.com/vmware/govmomi/vim25/soap" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	envURL           = "GOVC_URL" | ||||
| 	envUsername      = "GOVC_USERNAME" | ||||
| 	envPassword      = "GOVC_PASSWORD" | ||||
| 	envInsecure      = "GOVC_INSECURE" | ||||
| 	envPersist       = "GOVC_PERSIST_SESSION" | ||||
| 	envMinAPIVersion = "GOVC_MIN_API_VERSION" | ||||
| ) | ||||
| 
 | ||||
| const cDescr = "ESX or vCenter URL" | ||||
| 
 | ||||
| type ClientFlag struct { | ||||
| 	*DebugFlag | ||||
| 
 | ||||
| 	register sync.Once | ||||
| 
 | ||||
| 	url           *url.URL | ||||
| 	username      string | ||||
| 	password      string | ||||
| 	insecure      bool | ||||
| 	persist       bool | ||||
| 	minAPIVersion string | ||||
| 
 | ||||
| 	client *vim25.Client | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) URLWithoutPassword() *url.URL { | ||||
| 	if flag.url == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	withoutCredentials := *flag.url | ||||
| 	withoutCredentials.User = url.User(flag.url.User.Username()) | ||||
| 	return &withoutCredentials | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) String() string { | ||||
| 	url := flag.URLWithoutPassword() | ||||
| 	if url == nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 
 | ||||
| 	return url.String() | ||||
| } | ||||
| 
 | ||||
| var schemeMatch = regexp.MustCompile(`^\w+://`) | ||||
| 
 | ||||
| func (flag *ClientFlag) Set(s string) error { | ||||
| 	var err error | ||||
| 
 | ||||
| 	if s != "" { | ||||
| 		// Default the scheme to https
 | ||||
| 		if !schemeMatch.MatchString(s) { | ||||
| 			s = "https://" + s | ||||
| 		} | ||||
| 
 | ||||
| 		flag.url, err = url.Parse(s) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		// Default the path to /sdk
 | ||||
| 		if flag.url.Path == "" { | ||||
| 			flag.url.Path = "/sdk" | ||||
| 		} | ||||
| 
 | ||||
| 		if flag.url.User == nil { | ||||
| 			flag.url.User = url.UserPassword("", "") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) Register(f *flag.FlagSet) { | ||||
| 	flag.register.Do(func() { | ||||
| 		{ | ||||
| 			flag.Set(os.Getenv(envURL)) | ||||
| 			usage := fmt.Sprintf("%s [%s]", cDescr, envURL) | ||||
| 			f.Var(flag, "u", usage) | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			flag.username = os.Getenv(envUsername) | ||||
| 			flag.password = os.Getenv(envPassword) | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			insecure := false | ||||
| 			switch env := strings.ToLower(os.Getenv(envInsecure)); env { | ||||
| 			case "1", "true": | ||||
| 				insecure = true | ||||
| 			} | ||||
| 
 | ||||
| 			usage := fmt.Sprintf("Skip verification of server certificate [%s]", envInsecure) | ||||
| 			f.BoolVar(&flag.insecure, "k", insecure, usage) | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			persist := true | ||||
| 			switch env := strings.ToLower(os.Getenv(envPersist)); env { | ||||
| 			case "0", "false": | ||||
| 				persist = false | ||||
| 			} | ||||
| 
 | ||||
| 			usage := fmt.Sprintf("Persist session to disk [%s]", envPersist) | ||||
| 			f.BoolVar(&flag.persist, "persist-session", persist, usage) | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			env := os.Getenv(envMinAPIVersion) | ||||
| 			if env == "" { | ||||
| 				env = "5.5" | ||||
| 			} | ||||
| 
 | ||||
| 			flag.minAPIVersion = env | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) Process() error { | ||||
| 	if flag.url == nil { | ||||
| 		return errors.New("specify an " + cDescr) | ||||
| 	} | ||||
| 
 | ||||
| 	// Override username if set
 | ||||
| 	if flag.username != "" { | ||||
| 		var password string | ||||
| 		var ok bool | ||||
| 
 | ||||
| 		if flag.url.User != nil { | ||||
| 			password, ok = flag.url.User.Password() | ||||
| 		} | ||||
| 
 | ||||
| 		if ok { | ||||
| 			flag.url.User = url.UserPassword(flag.username, password) | ||||
| 		} else { | ||||
| 			flag.url.User = url.User(flag.username) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Override password if set
 | ||||
| 	if flag.password != "" { | ||||
| 		var username string | ||||
| 
 | ||||
| 		if flag.url.User != nil { | ||||
| 			username = flag.url.User.Username() | ||||
| 		} | ||||
| 
 | ||||
| 		flag.url.User = url.UserPassword(username, flag.password) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Retry twice when a temporary I/O error occurs.
 | ||||
| // This means a maximum of 3 attempts.
 | ||||
| func attachRetries(rt soap.RoundTripper) soap.RoundTripper { | ||||
| 	return vim25.Retry(rt, vim25.TemporaryNetworkError(3)) | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) sessionFile() string { | ||||
| 	url := flag.URLWithoutPassword() | ||||
| 
 | ||||
| 	// Key session file off of full URI and insecure setting.
 | ||||
| 	// Hash key to get a predictable, canonical format.
 | ||||
| 	key := fmt.Sprintf("%s#insecure=%t", url.String(), flag.insecure) | ||||
| 	name := fmt.Sprintf("%040x", sha1.Sum([]byte(key))) | ||||
| 	return filepath.Join(os.Getenv("HOME"), ".govmomi", "sessions", name) | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) saveClient(c *vim25.Client) error { | ||||
| 	if !flag.persist { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	p := flag.sessionFile() | ||||
| 	err := os.MkdirAll(filepath.Dir(p), 0700) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, 0600) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	defer f.Close() | ||||
| 
 | ||||
| 	enc := json.NewEncoder(f) | ||||
| 	err = enc.Encode(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) restoreClient(c *vim25.Client) (bool, error) { | ||||
| 	if !flag.persist { | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	f, err := os.Open(flag.sessionFile()) | ||||
| 	if err != nil { | ||||
| 		if os.IsNotExist(err) { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 
 | ||||
| 		return false, err | ||||
| 	} | ||||
| 
 | ||||
| 	defer f.Close() | ||||
| 
 | ||||
| 	dec := json.NewDecoder(f) | ||||
| 	err = dec.Decode(c) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 
 | ||||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) loadClient() (*vim25.Client, error) { | ||||
| 	c := new(vim25.Client) | ||||
| 	ok, err := flag.restoreClient(c) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if !ok || !c.Valid() { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Add retry functionality before making any calls
 | ||||
| 	c.RoundTripper = attachRetries(c.RoundTripper) | ||||
| 
 | ||||
| 	m := session.NewManager(c) | ||||
| 	u, err := m.UserSession(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// If the session is nil, the client is not authenticated
 | ||||
| 	if u == nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return c, nil | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) newClient() (*vim25.Client, error) { | ||||
| 	sc := soap.NewClient(flag.url, flag.insecure) | ||||
| 
 | ||||
| 	// Add retry functionality before making any calls
 | ||||
| 	rt := attachRetries(sc) | ||||
| 	c, err := vim25.NewClient(context.TODO(), rt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Set client, since we didn't pass it in the constructor
 | ||||
| 	c.Client = sc | ||||
| 
 | ||||
| 	m := session.NewManager(c) | ||||
| 	err = m.Login(context.TODO(), flag.url.User) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	err = flag.saveClient(c) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return c, nil | ||||
| } | ||||
| 
 | ||||
| // apiVersionValid returns whether or not the API version supported by the
 | ||||
| // server the client is connected to is not recent enough.
 | ||||
| func apiVersionValid(c *vim25.Client, minVersionString string) error { | ||||
| 	realVersion, err := ParseVersion(c.ServiceContent.About.ApiVersion) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	minVersion, err := ParseVersion(minVersionString) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if !minVersion.Lte(realVersion) { | ||||
| 		err = fmt.Errorf("Require API version %s, connected to API version %s (set %s to override)", | ||||
| 			minVersionString, | ||||
| 			c.ServiceContent.About.ApiVersion, | ||||
| 			envMinAPIVersion) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (flag *ClientFlag) Client() (*vim25.Client, error) { | ||||
| 	if flag.client != nil { | ||||
| 		return flag.client, nil | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := flag.loadClient() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// loadClient returns nil if it was unable to load a session from disk
 | ||||
| 	if c == nil { | ||||
| 		c, err = flag.newClient() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Check that the endpoint has the right API version
 | ||||
| 	err = apiVersionValid(c, flag.minAPIVersion) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	flag.client = c | ||||
| 	return flag.client, nil | ||||
| } | ||||
|  | @ -0,0 +1,98 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/find" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type DatacenterFlag struct { | ||||
| 	*ClientFlag | ||||
| 	*OutputFlag | ||||
| 
 | ||||
| 	register sync.Once | ||||
| 	path     string | ||||
| 	dc       *object.Datacenter | ||||
| 	finder   *find.Finder | ||||
| 	err      error | ||||
| } | ||||
| 
 | ||||
| func (flag *DatacenterFlag) Register(f *flag.FlagSet) { | ||||
| 	flag.register.Do(func() { | ||||
| 		env := "GOVC_DATACENTER" | ||||
| 		value := os.Getenv(env) | ||||
| 		usage := fmt.Sprintf("Datacenter [%s]", env) | ||||
| 		f.StringVar(&flag.path, "dc", value, usage) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (flag *DatacenterFlag) Process() error { return nil } | ||||
| 
 | ||||
| func (flag *DatacenterFlag) Finder() (*find.Finder, error) { | ||||
| 	if flag.finder != nil { | ||||
| 		return flag.finder, nil | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := flag.Client() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	finder := find.NewFinder(c, flag.JSON) | ||||
| 
 | ||||
| 	// Datacenter is not required (ls command for example).
 | ||||
| 	// Set for relative func if dc flag is given or
 | ||||
| 	// if there is a single (default) Datacenter
 | ||||
| 	if flag.path == "" { | ||||
| 		flag.dc, flag.err = finder.DefaultDatacenter(context.TODO()) | ||||
| 	} else { | ||||
| 		if flag.dc, err = finder.Datacenter(context.TODO(), flag.path); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	finder.SetDatacenter(flag.dc) | ||||
| 
 | ||||
| 	flag.finder = finder | ||||
| 
 | ||||
| 	return flag.finder, nil | ||||
| } | ||||
| 
 | ||||
| func (flag *DatacenterFlag) Datacenter() (*object.Datacenter, error) { | ||||
| 	if flag.dc != nil { | ||||
| 		return flag.dc, nil | ||||
| 	} | ||||
| 
 | ||||
| 	_, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if flag.err != nil { | ||||
| 		// Should only happen if no dc is specified and len(dcs) > 1
 | ||||
| 		return nil, flag.err | ||||
| 	} | ||||
| 
 | ||||
| 	return flag.dc, err | ||||
| } | ||||
|  | @ -0,0 +1,149 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	ErrDatastoreDirNotExist  = errors.New("datastore directory does not exist") | ||||
| 	ErrDatastoreFileNotExist = errors.New("datastore file does not exist") | ||||
| ) | ||||
| 
 | ||||
| type DatastoreFlag struct { | ||||
| 	*DatacenterFlag | ||||
| 
 | ||||
| 	register sync.Once | ||||
| 	name     string | ||||
| 	ds       *object.Datastore | ||||
| } | ||||
| 
 | ||||
| func (flag *DatastoreFlag) Register(f *flag.FlagSet) { | ||||
| 	flag.register.Do(func() { | ||||
| 		env := "GOVC_DATASTORE" | ||||
| 		value := os.Getenv(env) | ||||
| 		usage := fmt.Sprintf("Datastore [%s]", env) | ||||
| 		f.StringVar(&flag.name, "ds", value, usage) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (flag *DatastoreFlag) Process() error { return nil } | ||||
| 
 | ||||
| func (flag *DatastoreFlag) Datastore() (*object.Datastore, error) { | ||||
| 	if flag.ds != nil { | ||||
| 		return flag.ds, nil | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if flag.name == "" { | ||||
| 		flag.ds, err = finder.DefaultDatastore(context.TODO()) | ||||
| 	} else { | ||||
| 		flag.ds, err = finder.Datastore(context.TODO(), flag.name) | ||||
| 	} | ||||
| 
 | ||||
| 	return flag.ds, err | ||||
| } | ||||
| 
 | ||||
| func (flag *DatastoreFlag) DatastorePath(name string) (string, error) { | ||||
| 	ds, err := flag.Datastore() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	return ds.Path(name), nil | ||||
| } | ||||
| 
 | ||||
| func (flag *DatastoreFlag) DatastoreURL(path string) (*url.URL, error) { | ||||
| 	dc, err := flag.Datacenter() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	ds, err := flag.Datastore() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	u, err := ds.URL(context.TODO(), dc, path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return u, nil | ||||
| } | ||||
| 
 | ||||
| func (flag *DatastoreFlag) Stat(file string) (types.BaseFileInfo, error) { | ||||
| 	ds, err := flag.Datastore() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	b, err := ds.Browser(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	spec := types.HostDatastoreBrowserSearchSpec{ | ||||
| 		Details: &types.FileQueryFlags{ | ||||
| 			FileType:  true, | ||||
| 			FileOwner: types.NewBool(true), // TODO: omitempty is generated, but seems to be required
 | ||||
| 		}, | ||||
| 		MatchPattern: []string{path.Base(file)}, | ||||
| 	} | ||||
| 
 | ||||
| 	dsPath := ds.Path(path.Dir(file)) | ||||
| 	task, err := b.SearchDatastore(context.TODO(), dsPath, &spec) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	info, err := task.WaitForResult(context.TODO(), nil) | ||||
| 	if err != nil { | ||||
| 		if info != nil && info.Error != nil { | ||||
| 			_, ok := info.Error.Fault.(*types.FileNotFound) | ||||
| 			if ok { | ||||
| 				// FileNotFound means the base path doesn't exist.
 | ||||
| 				return nil, ErrDatastoreDirNotExist | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	res := info.Result.(types.HostDatastoreBrowserSearchResults) | ||||
| 	if len(res.File) == 0 { | ||||
| 		// File doesn't exist
 | ||||
| 		return nil, ErrDatastoreFileNotExist | ||||
| 	} | ||||
| 
 | ||||
| 	return res.File[0], nil | ||||
| } | ||||
|  | @ -0,0 +1,72 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/vim25/debug" | ||||
| ) | ||||
| 
 | ||||
| type DebugFlag struct { | ||||
| 	enable bool | ||||
| } | ||||
| 
 | ||||
| func (flag *DebugFlag) Register(f *flag.FlagSet) { | ||||
| 	env := "GOVC_DEBUG" | ||||
| 	enable := false | ||||
| 	switch env := strings.ToLower(os.Getenv(env)); env { | ||||
| 	case "1", "true": | ||||
| 		enable = true | ||||
| 	} | ||||
| 
 | ||||
| 	usage := fmt.Sprintf("Store debug logs [%s]", env) | ||||
| 	f.BoolVar(&flag.enable, "debug", enable, usage) | ||||
| } | ||||
| 
 | ||||
| func (flag *DebugFlag) Process() error { | ||||
| 	if flag.enable { | ||||
| 		// Base path for storing debug logs.
 | ||||
| 		r := os.Getenv("GOVC_DEBUG_PATH") | ||||
| 		if r == "" { | ||||
| 			r = filepath.Join(os.Getenv("HOME"), ".govmomi") | ||||
| 		} | ||||
| 		r = filepath.Join(r, "debug") | ||||
| 
 | ||||
| 		// Path for this particular run.
 | ||||
| 		now := time.Now().Format("2006-01-02T15-04-05.999999999") | ||||
| 		r = filepath.Join(r, now) | ||||
| 
 | ||||
| 		err := os.MkdirAll(r, 0700) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		p := debug.FileProvider{ | ||||
| 			Path: r, | ||||
| 		} | ||||
| 
 | ||||
| 		debug.SetProvider(&p) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,25 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import "flag" | ||||
| 
 | ||||
| type EmptyFlag struct{} | ||||
| 
 | ||||
| func (flag *EmptyFlag) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (flag *EmptyFlag) Process() error { return nil } | ||||
|  | @ -0,0 +1,111 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type HostSystemFlag struct { | ||||
| 	*ClientFlag | ||||
| 	*DatacenterFlag | ||||
| 	*SearchFlag | ||||
| 
 | ||||
| 	register sync.Once | ||||
| 	name     string | ||||
| 	host     *object.HostSystem | ||||
| 	pool     *object.ResourcePool | ||||
| } | ||||
| 
 | ||||
| func (flag *HostSystemFlag) Register(f *flag.FlagSet) { | ||||
| 	flag.SearchFlag = NewSearchFlag(SearchHosts) | ||||
| 
 | ||||
| 	flag.register.Do(func() { | ||||
| 		env := "GOVC_HOST" | ||||
| 		value := os.Getenv(env) | ||||
| 		usage := fmt.Sprintf("Host system [%s]", env) | ||||
| 		f.StringVar(&flag.name, "host", value, usage) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (flag *HostSystemFlag) Process() error { return nil } | ||||
| 
 | ||||
| func (flag *HostSystemFlag) HostSystemIfSpecified() (*object.HostSystem, error) { | ||||
| 	if flag.host != nil { | ||||
| 		return flag.host, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Use search flags if specified.
 | ||||
| 	if flag.SearchFlag.IsSet() { | ||||
| 		host, err := flag.SearchFlag.HostSystem() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		flag.host = host | ||||
| 		return flag.host, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Never look for a default host system.
 | ||||
| 	// A host system parameter is optional for vm creation. It uses a mandatory
 | ||||
| 	// resource pool parameter to determine where the vm should be placed.
 | ||||
| 	if flag.name == "" { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	flag.host, err = finder.HostSystem(context.TODO(), flag.name) | ||||
| 	return flag.host, err | ||||
| } | ||||
| 
 | ||||
| func (flag *HostSystemFlag) HostSystem() (*object.HostSystem, error) { | ||||
| 	host, err := flag.HostSystemIfSpecified() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if host != nil { | ||||
| 		return host, nil | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	flag.host, err = finder.DefaultHostSystem(context.TODO()) | ||||
| 	return flag.host, err | ||||
| } | ||||
| 
 | ||||
| func (flag *HostSystemFlag) HostNetworkSystem() (*object.HostNetworkSystem, error) { | ||||
| 	host, err := flag.HostSystem() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return host.ConfigManager().NetworkSystem(context.TODO()) | ||||
| } | ||||
|  | @ -0,0 +1,109 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type NetworkFlag struct { | ||||
| 	*DatacenterFlag | ||||
| 
 | ||||
| 	register sync.Once | ||||
| 	name     string | ||||
| 	net      object.NetworkReference | ||||
| 	adapter  string | ||||
| 	address  string | ||||
| } | ||||
| 
 | ||||
| func NewNetworkFlag() *NetworkFlag { | ||||
| 	return &NetworkFlag{} | ||||
| } | ||||
| 
 | ||||
| func (flag *NetworkFlag) Register(f *flag.FlagSet) { | ||||
| 	flag.register.Do(func() { | ||||
| 		env := "GOVC_NETWORK" | ||||
| 		value := os.Getenv(env) | ||||
| 		flag.Set(value) | ||||
| 		usage := fmt.Sprintf("Network [%s]", env) | ||||
| 		f.Var(flag, "net", usage) | ||||
| 		f.StringVar(&flag.adapter, "net.adapter", "e1000", "Network adapter type") | ||||
| 		f.StringVar(&flag.address, "net.address", "", "Network hardware address") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (flag *NetworkFlag) Process() error { return nil } | ||||
| 
 | ||||
| func (flag *NetworkFlag) String() string { | ||||
| 	return flag.name | ||||
| } | ||||
| 
 | ||||
| func (flag *NetworkFlag) Set(name string) error { | ||||
| 	flag.name = name | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (flag *NetworkFlag) Network() (object.NetworkReference, error) { | ||||
| 	if flag.net != nil { | ||||
| 		return flag.net, nil | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if flag.name == "" { | ||||
| 		flag.net, err = finder.DefaultNetwork(context.TODO()) | ||||
| 	} else { | ||||
| 		flag.net, err = finder.Network(context.TODO(), flag.name) | ||||
| 	} | ||||
| 
 | ||||
| 	return flag.net, err | ||||
| } | ||||
| 
 | ||||
| func (flag *NetworkFlag) Device() (types.BaseVirtualDevice, error) { | ||||
| 	net, err := flag.Network() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	backing, err := net.EthernetCardBackingInfo(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	device, err := object.EthernetCardTypes().CreateEthernetCard(flag.adapter, backing) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if flag.address != "" { | ||||
| 		card := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() | ||||
| 		card.AddressType = string(types.VirtualEthernetCardMacTypeManual) | ||||
| 		card.MacAddress = flag.address | ||||
| 	} | ||||
| 
 | ||||
| 	return device, nil | ||||
| } | ||||
|  | @ -0,0 +1,191 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/vim25/progress" | ||||
| ) | ||||
| 
 | ||||
| type OutputWriter interface { | ||||
| 	Write(io.Writer) error | ||||
| } | ||||
| 
 | ||||
| type OutputFlag struct { | ||||
| 	JSON bool | ||||
| 	TTY  bool | ||||
| } | ||||
| 
 | ||||
| func (flag *OutputFlag) Register(f *flag.FlagSet) { | ||||
| 	f.BoolVar(&flag.JSON, "json", false, "Enable JSON output") | ||||
| } | ||||
| 
 | ||||
| func (flag *OutputFlag) Process() error { | ||||
| 	if !flag.JSON { | ||||
| 		// Assume we have a tty if not outputting JSON
 | ||||
| 		flag.TTY = true | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Log outputs the specified string, prefixed with the current time.
 | ||||
| // A newline is not automatically added. If the specified string
 | ||||
| // starts with a '\r', the current line is cleared first.
 | ||||
| func (flag *OutputFlag) Log(s string) (int, error) { | ||||
| 	if len(s) > 0 && s[0] == '\r' { | ||||
| 		flag.Write([]byte{'\r', 033, '[', 'K'}) | ||||
| 		s = s[1:] | ||||
| 	} | ||||
| 
 | ||||
| 	return flag.WriteString(time.Now().Format("[02-01-06 15:04:05] ") + s) | ||||
| } | ||||
| 
 | ||||
| func (flag *OutputFlag) Write(b []byte) (int, error) { | ||||
| 	if !flag.TTY { | ||||
| 		return 0, nil | ||||
| 	} | ||||
| 
 | ||||
| 	n, err := os.Stdout.Write(b) | ||||
| 	os.Stdout.Sync() | ||||
| 	return n, err | ||||
| } | ||||
| 
 | ||||
| func (flag *OutputFlag) WriteString(s string) (int, error) { | ||||
| 	return flag.Write([]byte(s)) | ||||
| } | ||||
| 
 | ||||
| func (flag *OutputFlag) WriteResult(result OutputWriter) error { | ||||
| 	var err error | ||||
| 	var out = os.Stdout | ||||
| 
 | ||||
| 	if flag.JSON { | ||||
| 		enc := json.NewEncoder(out) | ||||
| 		err = enc.Encode(result) | ||||
| 	} else { | ||||
| 		err = result.Write(out) | ||||
| 	} | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| type progressLogger struct { | ||||
| 	flag   *OutputFlag | ||||
| 	prefix string | ||||
| 
 | ||||
| 	wg sync.WaitGroup | ||||
| 
 | ||||
| 	sink chan chan progress.Report | ||||
| 	done chan struct{} | ||||
| } | ||||
| 
 | ||||
| func newProgressLogger(flag *OutputFlag, prefix string) *progressLogger { | ||||
| 	p := &progressLogger{ | ||||
| 		flag:   flag, | ||||
| 		prefix: prefix, | ||||
| 
 | ||||
| 		sink: make(chan chan progress.Report), | ||||
| 		done: make(chan struct{}), | ||||
| 	} | ||||
| 
 | ||||
| 	p.wg.Add(1) | ||||
| 
 | ||||
| 	go p.loopA() | ||||
| 
 | ||||
| 	return p | ||||
| } | ||||
| 
 | ||||
| // loopA runs before Sink() has been called.
 | ||||
| func (p *progressLogger) loopA() { | ||||
| 	var err error | ||||
| 
 | ||||
| 	defer p.wg.Done() | ||||
| 
 | ||||
| 	tick := time.NewTicker(100 * time.Millisecond) | ||||
| 	defer tick.Stop() | ||||
| 
 | ||||
| 	for stop := false; !stop; { | ||||
| 		select { | ||||
| 		case ch := <-p.sink: | ||||
| 			err = p.loopB(tick, ch) | ||||
| 			stop = true | ||||
| 		case <-p.done: | ||||
| 			stop = true | ||||
| 		case <-tick.C: | ||||
| 			line := fmt.Sprintf("\r%s", p.prefix) | ||||
| 			p.flag.Log(line) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if err != nil && err != io.EOF { | ||||
| 		p.flag.Log(fmt.Sprintf("\r%sError: %s\n", p.prefix, err)) | ||||
| 	} else { | ||||
| 		p.flag.Log(fmt.Sprintf("\r%sOK\n", p.prefix)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // loopA runs after Sink() has been called.
 | ||||
| func (p *progressLogger) loopB(tick *time.Ticker, ch <-chan progress.Report) error { | ||||
| 	var r progress.Report | ||||
| 	var ok bool | ||||
| 	var err error | ||||
| 
 | ||||
| 	for ok = true; ok; { | ||||
| 		select { | ||||
| 		case r, ok = <-ch: | ||||
| 			if !ok { | ||||
| 				break | ||||
| 			} | ||||
| 			err = r.Error() | ||||
| 		case <-tick.C: | ||||
| 			line := fmt.Sprintf("\r%s", p.prefix) | ||||
| 			if r != nil { | ||||
| 				line += fmt.Sprintf("(%.0f%%", r.Percentage()) | ||||
| 				detail := r.Detail() | ||||
| 				if detail != "" { | ||||
| 					line += fmt.Sprintf(", %s", detail) | ||||
| 				} | ||||
| 				line += ")" | ||||
| 			} | ||||
| 			p.flag.Log(line) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (p *progressLogger) Sink() chan<- progress.Report { | ||||
| 	ch := make(chan progress.Report) | ||||
| 	p.sink <- ch | ||||
| 	return ch | ||||
| } | ||||
| 
 | ||||
| func (p *progressLogger) Wait() { | ||||
| 	close(p.done) | ||||
| 	p.wg.Wait() | ||||
| } | ||||
| 
 | ||||
| func (flag *OutputFlag) ProgressLogger(prefix string) *progressLogger { | ||||
| 	return newProgressLogger(flag, prefix) | ||||
| } | ||||
|  | @ -0,0 +1,65 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type ResourcePoolFlag struct { | ||||
| 	*DatacenterFlag | ||||
| 
 | ||||
| 	register sync.Once | ||||
| 	name     string | ||||
| 	pool     *object.ResourcePool | ||||
| } | ||||
| 
 | ||||
| func (flag *ResourcePoolFlag) Register(f *flag.FlagSet) { | ||||
| 	flag.register.Do(func() { | ||||
| 		env := "GOVC_RESOURCE_POOL" | ||||
| 		value := os.Getenv(env) | ||||
| 		usage := fmt.Sprintf("Resource pool [%s]", env) | ||||
| 		f.StringVar(&flag.name, "pool", value, usage) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (flag *ResourcePoolFlag) Process() error { return nil } | ||||
| 
 | ||||
| func (flag *ResourcePoolFlag) ResourcePool() (*object.ResourcePool, error) { | ||||
| 	if flag.pool != nil { | ||||
| 		return flag.pool, nil | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if flag.name == "" { | ||||
| 		flag.pool, err = finder.DefaultResourcePool(context.TODO()) | ||||
| 	} else { | ||||
| 		flag.pool, err = finder.ResourcePool(context.TODO(), flag.name) | ||||
| 	} | ||||
| 
 | ||||
| 	return flag.pool, err | ||||
| } | ||||
|  | @ -0,0 +1,305 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	SearchVirtualMachines = iota + 1 | ||||
| 	SearchHosts | ||||
| ) | ||||
| 
 | ||||
| type SearchFlag struct { | ||||
| 	*ClientFlag | ||||
| 	*DatacenterFlag | ||||
| 
 | ||||
| 	t      int | ||||
| 	entity string | ||||
| 
 | ||||
| 	byDatastorePath string | ||||
| 	byDNSName       string | ||||
| 	byInventoryPath string | ||||
| 	byIP            string | ||||
| 	byUUID          string | ||||
| 
 | ||||
| 	isset bool | ||||
| } | ||||
| 
 | ||||
| func NewSearchFlag(t int) *SearchFlag { | ||||
| 	s := SearchFlag{ | ||||
| 		t: t, | ||||
| 	} | ||||
| 
 | ||||
| 	switch t { | ||||
| 	case SearchVirtualMachines: | ||||
| 		s.entity = "VM" | ||||
| 	case SearchHosts: | ||||
| 		s.entity = "host" | ||||
| 	default: | ||||
| 		panic("invalid search type") | ||||
| 	} | ||||
| 
 | ||||
| 	return &s | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) Register(fs *flag.FlagSet) { | ||||
| 	register := func(v *string, f string, d string) { | ||||
| 		f = fmt.Sprintf("%s.%s", strings.ToLower(flag.entity), f) | ||||
| 		d = fmt.Sprintf(d, flag.entity) | ||||
| 		fs.StringVar(v, f, "", d) | ||||
| 	} | ||||
| 
 | ||||
| 	switch flag.t { | ||||
| 	case SearchVirtualMachines: | ||||
| 		register(&flag.byDatastorePath, "path", "Find %s by path to .vmx file") | ||||
| 	} | ||||
| 
 | ||||
| 	switch flag.t { | ||||
| 	case SearchVirtualMachines, SearchHosts: | ||||
| 		register(&flag.byDNSName, "dns", "Find %s by FQDN") | ||||
| 		register(&flag.byIP, "ip", "Find %s by IP address") | ||||
| 		register(&flag.byUUID, "uuid", "Find %s by instance UUID") | ||||
| 	} | ||||
| 
 | ||||
| 	register(&flag.byInventoryPath, "ipath", "Find %s by inventory path") | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) Process() error { | ||||
| 	flags := []string{ | ||||
| 		flag.byDatastorePath, | ||||
| 		flag.byDNSName, | ||||
| 		flag.byInventoryPath, | ||||
| 		flag.byIP, | ||||
| 		flag.byUUID, | ||||
| 	} | ||||
| 
 | ||||
| 	flag.isset = false | ||||
| 	for _, f := range flags { | ||||
| 		if f != "" { | ||||
| 			if flag.isset { | ||||
| 				return errors.New("cannot use more than one search flag") | ||||
| 			} | ||||
| 			flag.isset = true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) IsSet() bool { | ||||
| 	return flag.isset | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) searchIndex(c *vim25.Client) *object.SearchIndex { | ||||
| 	return object.NewSearchIndex(c) | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) searchByDatastorePath(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { | ||||
| 	switch flag.t { | ||||
| 	case SearchVirtualMachines: | ||||
| 		return flag.searchIndex(c).FindByDatastorePath(context.TODO(), dc, flag.byDatastorePath) | ||||
| 	default: | ||||
| 		panic("unsupported type") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) searchByDNSName(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { | ||||
| 	switch flag.t { | ||||
| 	case SearchVirtualMachines: | ||||
| 		return flag.searchIndex(c).FindByDnsName(context.TODO(), dc, flag.byDNSName, true) | ||||
| 	case SearchHosts: | ||||
| 		return flag.searchIndex(c).FindByDnsName(context.TODO(), dc, flag.byDNSName, false) | ||||
| 	default: | ||||
| 		panic("unsupported type") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) searchByInventoryPath(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { | ||||
| 	// TODO(PN): The datacenter flag should not be set because it is ignored.
 | ||||
| 	return flag.searchIndex(c).FindByInventoryPath(context.TODO(), flag.byInventoryPath) | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) searchByIP(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { | ||||
| 	switch flag.t { | ||||
| 	case SearchVirtualMachines: | ||||
| 		return flag.searchIndex(c).FindByIp(context.TODO(), dc, flag.byIP, true) | ||||
| 	case SearchHosts: | ||||
| 		return flag.searchIndex(c).FindByIp(context.TODO(), dc, flag.byIP, false) | ||||
| 	default: | ||||
| 		panic("unsupported type") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) searchByUUID(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { | ||||
| 	switch flag.t { | ||||
| 	case SearchVirtualMachines: | ||||
| 		return flag.searchIndex(c).FindByUuid(context.TODO(), dc, flag.byUUID, true) | ||||
| 	case SearchHosts: | ||||
| 		return flag.searchIndex(c).FindByUuid(context.TODO(), dc, flag.byUUID, false) | ||||
| 	default: | ||||
| 		panic("unsupported type") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) search() (object.Reference, error) { | ||||
| 	var ref object.Reference | ||||
| 	var err error | ||||
| 
 | ||||
| 	c, err := flag.Client() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	dc, err := flag.Datacenter() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	switch { | ||||
| 	case flag.byDatastorePath != "": | ||||
| 		ref, err = flag.searchByDatastorePath(c, dc) | ||||
| 	case flag.byDNSName != "": | ||||
| 		ref, err = flag.searchByDNSName(c, dc) | ||||
| 	case flag.byInventoryPath != "": | ||||
| 		ref, err = flag.searchByInventoryPath(c, dc) | ||||
| 	case flag.byIP != "": | ||||
| 		ref, err = flag.searchByIP(c, dc) | ||||
| 	case flag.byUUID != "": | ||||
| 		ref, err = flag.searchByUUID(c, dc) | ||||
| 	default: | ||||
| 		err = errors.New("no search flag specified") | ||||
| 	} | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if ref == nil { | ||||
| 		return nil, fmt.Errorf("no such %s", flag.entity) | ||||
| 	} | ||||
| 
 | ||||
| 	return ref, nil | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) VirtualMachine() (*object.VirtualMachine, error) { | ||||
| 	ref, err := flag.search() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	vm, ok := ref.(*object.VirtualMachine) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("expected VirtualMachine entity, got %s", ref.Reference().Type) | ||||
| 	} | ||||
| 
 | ||||
| 	return vm, nil | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) VirtualMachines(args []string) ([]*object.VirtualMachine, error) { | ||||
| 	var out []*object.VirtualMachine | ||||
| 
 | ||||
| 	if flag.IsSet() { | ||||
| 		vm, err := flag.VirtualMachine() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		out = append(out, vm) | ||||
| 		return out, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// List virtual machines
 | ||||
| 	if len(args) == 0 { | ||||
| 		return nil, errors.New("no argument") | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// List virtual machines for every argument
 | ||||
| 	for _, arg := range args { | ||||
| 		vms, err := finder.VirtualMachineList(context.TODO(), arg) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		out = append(out, vms...) | ||||
| 	} | ||||
| 
 | ||||
| 	return out, nil | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) HostSystem() (*object.HostSystem, error) { | ||||
| 	ref, err := flag.search() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	host, ok := ref.(*object.HostSystem) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("expected HostSystem entity, got %s", ref.Reference().Type) | ||||
| 	} | ||||
| 
 | ||||
| 	return host, nil | ||||
| } | ||||
| 
 | ||||
| func (flag *SearchFlag) HostSystems(args []string) ([]*object.HostSystem, error) { | ||||
| 	var out []*object.HostSystem | ||||
| 
 | ||||
| 	if flag.IsSet() { | ||||
| 		host, err := flag.HostSystem() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		out = append(out, host) | ||||
| 		return out, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// List host system
 | ||||
| 	if len(args) == 0 { | ||||
| 		return nil, errors.New("no argument") | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// List host systems for every argument
 | ||||
| 	for _, arg := range args { | ||||
| 		vms, err := finder.HostSystemList(context.TODO(), arg) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		out = append(out, vms...) | ||||
| 	} | ||||
| 
 | ||||
| 	return out, nil | ||||
| } | ||||
|  | @ -0,0 +1,61 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| type version []int | ||||
| 
 | ||||
| func ParseVersion(s string) (version, error) { | ||||
| 	v := make(version, 0) | ||||
| 	ps := strings.Split(s, ".") | ||||
| 	for _, p := range ps { | ||||
| 		i, err := strconv.Atoi(p) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		v = append(v, i) | ||||
| 	} | ||||
| 
 | ||||
| 	return v, nil | ||||
| } | ||||
| 
 | ||||
| func (v version) Lte(u version) bool { | ||||
| 	lv := len(v) | ||||
| 	lu := len(u) | ||||
| 
 | ||||
| 	for i := 0; i < lv; i++ { | ||||
| 		// Everything up to here has been equal and v has more elements than u.
 | ||||
| 		if i >= lu { | ||||
| 			return false | ||||
| 		} | ||||
| 
 | ||||
| 		// Move to next digit if equal.
 | ||||
| 		if v[i] == u[i] { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		return v[i] < u[i] | ||||
| 	} | ||||
| 
 | ||||
| 	// Equal.
 | ||||
| 	return true | ||||
| } | ||||
|  | @ -0,0 +1,80 @@ | |||
| /* | ||||
| 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 flags | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type VirtualMachineFlag struct { | ||||
| 	*ClientFlag | ||||
| 	*DatacenterFlag | ||||
| 	*SearchFlag | ||||
| 
 | ||||
| 	register sync.Once | ||||
| 	name     string | ||||
| 	vm       *object.VirtualMachine | ||||
| } | ||||
| 
 | ||||
| func (flag *VirtualMachineFlag) Register(f *flag.FlagSet) { | ||||
| 	flag.SearchFlag = NewSearchFlag(SearchVirtualMachines) | ||||
| 
 | ||||
| 	flag.register.Do(func() { | ||||
| 		env := "GOVC_VM" | ||||
| 		value := os.Getenv(env) | ||||
| 		usage := fmt.Sprintf("Virtual machine [%s]", env) | ||||
| 		f.StringVar(&flag.name, "vm", value, usage) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (flag *VirtualMachineFlag) Process() error { return nil } | ||||
| 
 | ||||
| func (flag *VirtualMachineFlag) VirtualMachine() (*object.VirtualMachine, error) { | ||||
| 	if flag.vm != nil { | ||||
| 		return flag.vm, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Use search flags if specified.
 | ||||
| 	if flag.SearchFlag.IsSet() { | ||||
| 		vm, err := flag.SearchFlag.VirtualMachine() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		flag.vm = vm | ||||
| 		return flag.vm, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Never look for a default virtual machine.
 | ||||
| 	if flag.name == "" { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := flag.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	flag.vm, err = finder.VirtualMachine(context.TODO(), flag.name) | ||||
| 	return flag.vm, err | ||||
| } | ||||
|  | @ -0,0 +1,165 @@ | |||
| /* | ||||
| 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 host | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25/methods" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*flags.ClientFlag | ||||
| 	*flags.DatacenterFlag | ||||
| 
 | ||||
| 	parent string | ||||
| 
 | ||||
| 	host        string | ||||
| 	username    string | ||||
| 	password    string | ||||
| 	connect     bool | ||||
| 	fingerprint string | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.parent, "parent", "", "Path to folder to add the host to") | ||||
| 
 | ||||
| 	f.StringVar(&cmd.host, "host", "", "Hostname or IP address of the host") | ||||
| 	f.StringVar(&cmd.username, "username", "", "Username of administration account on the host") | ||||
| 	f.StringVar(&cmd.password, "password", "", "Password of administration account on the host") | ||||
| 	f.BoolVar(&cmd.connect, "connect", true, "Immediately connect to host") | ||||
| 	f.StringVar(&cmd.fingerprint, "fingerprint", "", "Fingerprint of the host's SSL certificate") | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Process() error { | ||||
| 	if cmd.host == "" { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 	if cmd.username == "" { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 	if cmd.password == "" { | ||||
| 		return flag.ErrHelp | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Usage() string { | ||||
| 	return "HOST" | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Description() string { | ||||
| 	return `Add HOST to datacenter. | ||||
| 
 | ||||
| The host is added to the folder specified by the 'parent' flag. If not given, | ||||
| this defaults to the hosts folder in the specified or default datacenter.` | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	var ctx = context.Background() | ||||
| 	var parent *object.Folder | ||||
| 
 | ||||
| 	client, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if cmd.parent == "" { | ||||
| 		dc, err := cmd.Datacenter() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		folders, err := dc.Folders(ctx) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		parent = folders.HostFolder | ||||
| 	} else { | ||||
| 		finder, err := cmd.Finder() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		mo, err := finder.ManagedObjectList(ctx, cmd.parent) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if len(mo) == 0 { | ||||
| 			return errors.New("parent does not resolve to object") | ||||
| 		} | ||||
| 
 | ||||
| 		if len(mo) > 1 { | ||||
| 			return errors.New("parent resolves to more than one object") | ||||
| 		} | ||||
| 
 | ||||
| 		ref := mo[0].Object.Reference() | ||||
| 		if ref.Type != "Folder" { | ||||
| 			return errors.New("parent does not resolve to folder") | ||||
| 		} | ||||
| 
 | ||||
| 		parent = object.NewFolder(client, ref) | ||||
| 	} | ||||
| 
 | ||||
| 	req := types.AddStandaloneHost_Task{ | ||||
| 		This: parent.Reference(), | ||||
| 		Spec: types.HostConnectSpec{ | ||||
| 			HostName:      cmd.host, | ||||
| 			UserName:      cmd.username, | ||||
| 			Password:      cmd.password, | ||||
| 			SslThumbprint: cmd.fingerprint, | ||||
| 		}, | ||||
| 		AddConnected: cmd.connect, | ||||
| 	} | ||||
| 
 | ||||
| 	res, err := methods.AddStandaloneHost_Task(ctx, client, &req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	task := object.NewTask(client, res.Returnval) | ||||
| 	_, err = task.WaitForResult(ctx, nil) | ||||
| 	if err != nil { | ||||
| 		f, ok := err.(types.HasFault) | ||||
| 		if !ok { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		switch fault := f.Fault().(type) { | ||||
| 		case *types.SSLVerifyFault: | ||||
| 			// Add fingerprint to error message
 | ||||
| 			return fmt.Errorf("%s Fingerprint is %s.", err.Error(), fault.Thumbprint) | ||||
| 		default: | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,53 @@ | |||
| /* | ||||
| 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 autostart | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*AutostartFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.autostart.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *add) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *add) Usage() string { | ||||
| 	return "VM..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	var powerInfo = types.AutoStartPowerInfo{ | ||||
| 		StartAction:      "powerOn", | ||||
| 		StartDelay:       -1, | ||||
| 		StartOrder:       -1, | ||||
| 		StopAction:       "systemDefault", | ||||
| 		StopDelay:        -1, | ||||
| 		WaitForHeartbeat: types.AutoStartWaitHeartbeatSettingSystemDefault, | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd.ReconfigureVMs(f.Args(), powerInfo) | ||||
| } | ||||
							
								
								
									
										150
									
								
								vendor/github.com/vmware/govmomi/govc/host/autostart/autostart.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										150
									
								
								vendor/github.com/vmware/govmomi/govc/host/autostart/autostart.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,150 @@ | |||
| /* | ||||
| 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 autostart | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25/methods" | ||||
| 	"github.com/vmware/govmomi/vim25/mo" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type AutostartFlag struct { | ||||
| 	*flags.ClientFlag | ||||
| 	*flags.DatacenterFlag | ||||
| 	*flags.HostSystemFlag | ||||
| } | ||||
| 
 | ||||
| func (f *AutostartFlag) Register(fs *flag.FlagSet) {} | ||||
| 
 | ||||
| func (f *AutostartFlag) Process() error { return nil } | ||||
| 
 | ||||
| // VirtualMachines returns list of virtual machine objects based on the
 | ||||
| // arguments specified on the command line. This helper is defined in
 | ||||
| // flags.SearchFlag as well, but that pulls in other virtual machine flags that
 | ||||
| // are not relevant here.
 | ||||
| func (f *AutostartFlag) VirtualMachines(args []string) ([]*object.VirtualMachine, error) { | ||||
| 	if len(args) == 0 { | ||||
| 		return nil, errors.New("no argument") | ||||
| 	} | ||||
| 
 | ||||
| 	finder, err := f.Finder() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var out []*object.VirtualMachine | ||||
| 	for _, arg := range args { | ||||
| 		vms, err := finder.VirtualMachineList(context.TODO(), arg) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		out = append(out, vms...) | ||||
| 	} | ||||
| 
 | ||||
| 	return out, nil | ||||
| } | ||||
| 
 | ||||
| func (f *AutostartFlag) HostAutoStartManager() (*mo.HostAutoStartManager, error) { | ||||
| 	h, err := f.HostSystem() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var mhs mo.HostSystem | ||||
| 	err = h.Properties(context.TODO(), h.Reference(), []string{"configManager.autoStartManager"}, &mhs) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var mhas mo.HostAutoStartManager | ||||
| 	err = h.Properties(context.TODO(), *mhs.ConfigManager.AutoStartManager, nil, &mhas) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return &mhas, nil | ||||
| } | ||||
| 
 | ||||
| func (f *AutostartFlag) ReconfigureDefaults(template types.AutoStartDefaults) error { | ||||
| 	c, err := f.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	mhas, err := f.HostAutoStartManager() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	req := types.ReconfigureAutostart{ | ||||
| 		This: mhas.Reference(), | ||||
| 		Spec: types.HostAutoStartManagerConfig{ | ||||
| 			Defaults: &template, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = methods.ReconfigureAutostart(context.TODO(), c, &req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (f *AutostartFlag) ReconfigureVMs(args []string, template types.AutoStartPowerInfo) error { | ||||
| 	c, err := f.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	mhas, err := f.HostAutoStartManager() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	req := types.ReconfigureAutostart{ | ||||
| 		This: mhas.Reference(), | ||||
| 		Spec: types.HostAutoStartManagerConfig{ | ||||
| 			PowerInfo: make([]types.AutoStartPowerInfo, 0), | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	vms, err := f.VirtualMachines(args) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, vm := range vms { | ||||
| 		pi := template | ||||
| 		pi.Key = vm.Reference() | ||||
| 		req.Spec.PowerInfo = append(req.Spec.PowerInfo, pi) | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = methods.ReconfigureAutostart(context.TODO(), c, &req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,59 @@ | |||
| /* | ||||
| 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 autostart | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| ) | ||||
| 
 | ||||
| type configure struct { | ||||
| 	*AutostartFlag | ||||
| 
 | ||||
| 	defaults types.AutoStartDefaults | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.autostart.configure", &configure{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *configure) Register(f *flag.FlagSet) { | ||||
| 	cmd.defaults.Enabled = types.NewBool(false) | ||||
| 	f.BoolVar(cmd.defaults.Enabled, "enabled", false, "") | ||||
| 
 | ||||
| 	f.IntVar(&cmd.defaults.StartDelay, "start-delay", 0, "") | ||||
| 	f.StringVar(&cmd.defaults.StopAction, "stop-action", "", "") | ||||
| 	f.IntVar(&cmd.defaults.StopDelay, "stop-delay", 0, "") | ||||
| 
 | ||||
| 	cmd.defaults.WaitForHeartbeat = types.NewBool(false) | ||||
| 	f.BoolVar(cmd.defaults.WaitForHeartbeat, "wait-for-heartbeat", false, "") | ||||
| } | ||||
| 
 | ||||
| func (cmd *configure) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *configure) Usage() string { | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func (cmd *configure) Run(f *flag.FlagSet) error { | ||||
| 	// Note: this command cannot DISABLE autostart because the "Enabled" field is
 | ||||
| 	// marked "omitempty", which means that it is not included when it is false.
 | ||||
| 	// Also see: https://github.com/vmware/govmomi/issues/240
 | ||||
| 	return cmd.ReconfigureDefaults(cmd.defaults) | ||||
| } | ||||
|  | @ -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 autostart | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/vim25" | ||||
| 	"github.com/vmware/govmomi/vim25/mo" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type info struct { | ||||
| 	*AutostartFlag | ||||
| 
 | ||||
| 	*flags.OutputFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.autostart.info", &info{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *info) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *info) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *info) Usage() string { | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func (cmd *info) Run(f *flag.FlagSet) error { | ||||
| 	client, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	mhas, err := cmd.HostAutoStartManager() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd.WriteResult(&infoResult{client, mhas}) | ||||
| } | ||||
| 
 | ||||
| type infoResult struct { | ||||
| 	client *vim25.Client | ||||
| 	mhas   *mo.HostAutoStartManager | ||||
| } | ||||
| 
 | ||||
| func (r *infoResult) MarshalJSON() ([]byte, error) { | ||||
| 	return json.Marshal(r.mhas) | ||||
| } | ||||
| 
 | ||||
| // vmPaths resolves the paths for the VMs in the result.
 | ||||
| func (r *infoResult) vmPaths() (map[string]string, error) { | ||||
| 	paths := make(map[string]string) | ||||
| 	for _, info := range r.mhas.Config.PowerInfo { | ||||
| 		mes, err := mo.Ancestors(context.TODO(), r.client, r.client.ServiceContent.PropertyCollector, info.Key) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		path := "" | ||||
| 		for _, me := range mes { | ||||
| 			// Skip root entity in building inventory path.
 | ||||
| 			if me.Parent == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			path += "/" + me.Name | ||||
| 		} | ||||
| 
 | ||||
| 		paths[info.Key.Value] = path | ||||
| 	} | ||||
| 
 | ||||
| 	return paths, nil | ||||
| } | ||||
| 
 | ||||
| func (r *infoResult) Write(w io.Writer) error { | ||||
| 	paths, err := r.vmPaths() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	fmt.Fprintf(tw, "VM") | ||||
| 	fmt.Fprintf(tw, "\tStartAction") | ||||
| 	fmt.Fprintf(tw, "\tStartDelay") | ||||
| 	fmt.Fprintf(tw, "\tStartOrder") | ||||
| 	fmt.Fprintf(tw, "\tStopAction") | ||||
| 	fmt.Fprintf(tw, "\tStopDelay") | ||||
| 	fmt.Fprintf(tw, "\tWaitForHeartbeat") | ||||
| 	fmt.Fprintf(tw, "\n") | ||||
| 
 | ||||
| 	for _, info := range r.mhas.Config.PowerInfo { | ||||
| 		fmt.Fprintf(tw, "%s", paths[info.Key.Value]) | ||||
| 		fmt.Fprintf(tw, "\t%s", info.StartAction) | ||||
| 		fmt.Fprintf(tw, "\t%d", info.StartDelay) | ||||
| 		fmt.Fprintf(tw, "\t%d", info.StartOrder) | ||||
| 		fmt.Fprintf(tw, "\t%s", info.StopAction) | ||||
| 		fmt.Fprintf(tw, "\t%d", info.StopDelay) | ||||
| 		fmt.Fprintf(tw, "\t%s", info.WaitForHeartbeat) | ||||
| 		fmt.Fprintf(tw, "\n") | ||||
| 	} | ||||
| 
 | ||||
| 	_ = tw.Flush() | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,53 @@ | |||
| /* | ||||
| 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 autostart | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| ) | ||||
| 
 | ||||
| type remove struct { | ||||
| 	*AutostartFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.autostart.remove", &remove{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *remove) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *remove) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *remove) Usage() string { | ||||
| 	return "VM..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *remove) Run(f *flag.FlagSet) error { | ||||
| 	var powerInfo = types.AutoStartPowerInfo{ | ||||
| 		StartAction:      "none", | ||||
| 		StartDelay:       -1, | ||||
| 		StartOrder:       -1, | ||||
| 		StopAction:       "none", | ||||
| 		StopDelay:        -1, | ||||
| 		WaitForHeartbeat: types.AutoStartWaitHeartbeatSettingSystemDefault, | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd.ReconfigureVMs(f.Args(), powerInfo) | ||||
| } | ||||
|  | @ -0,0 +1,149 @@ | |||
| /* | ||||
| 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 esxcli | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| ) | ||||
| 
 | ||||
| type Command struct { | ||||
| 	name []string | ||||
| 	args []string | ||||
| } | ||||
| 
 | ||||
| type CommandInfoItem struct { | ||||
| 	Name        string `xml:"name"` | ||||
| 	DisplayName string `xml:"displayName"` | ||||
| 	Help        string `xml:"help"` | ||||
| } | ||||
| 
 | ||||
| type CommandInfoParam struct { | ||||
| 	CommandInfoItem | ||||
| 	Aliases []string `xml:"aliases"` | ||||
| 	Flag    bool     `xml:"flag"` | ||||
| } | ||||
| 
 | ||||
| type CommandInfoHint struct { | ||||
| 	Key   string `xml:"key"` | ||||
| 	Value string `xml:"value"` | ||||
| } | ||||
| 
 | ||||
| type CommandInfoHints []CommandInfoHint | ||||
| 
 | ||||
| type CommandInfoMethod struct { | ||||
| 	CommandInfoItem | ||||
| 	Param []CommandInfoParam `xml:"param"` | ||||
| 	Hints CommandInfoHints   `xml:"hints"` | ||||
| } | ||||
| 
 | ||||
| type CommandInfo struct { | ||||
| 	CommandInfoItem | ||||
| 	Method []*CommandInfoMethod `xml:"method"` | ||||
| } | ||||
| 
 | ||||
| func NewCommand(args []string) *Command { | ||||
| 	c := &Command{} | ||||
| 
 | ||||
| 	for i, arg := range args { | ||||
| 		if strings.HasPrefix(arg, "-") { | ||||
| 			c.args = args[i:] | ||||
| 			break | ||||
| 		} else { | ||||
| 			c.name = append(c.name, arg) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| func (c *Command) Namespace() string { | ||||
| 	return strings.Join(c.name[:len(c.name)-1], ".") | ||||
| } | ||||
| 
 | ||||
| func (c *Command) Name() string { | ||||
| 	return c.name[len(c.name)-1] | ||||
| } | ||||
| 
 | ||||
| func (c *Command) Method() string { | ||||
| 	return "vim.EsxCLI." + strings.Join(c.name, ".") | ||||
| } | ||||
| 
 | ||||
| func (c *Command) Moid() string { | ||||
| 	return "ha-cli-handler-" + strings.Join(c.name[:len(c.name)-1], "-") | ||||
| } | ||||
| 
 | ||||
| // Parse generates a flag.FlagSet based on the given []CommandInfoParam and
 | ||||
| // returns arguments for use with methods.ExecuteSoap
 | ||||
| func (c *Command) Parse(params []CommandInfoParam) ([]types.ReflectManagedMethodExecuterSoapArgument, error) { | ||||
| 	flags := flag.NewFlagSet(strings.Join(c.name, " "), flag.ExitOnError) | ||||
| 	vals := make([]string, len(params)) | ||||
| 
 | ||||
| 	for i, p := range params { | ||||
| 		v := &vals[i] | ||||
| 		for _, a := range p.Aliases { | ||||
| 			a = strings.TrimPrefix(a[1:], "-") | ||||
| 			flags.StringVar(v, a, "", p.Help) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	err := flags.Parse(c.args) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	args := []types.ReflectManagedMethodExecuterSoapArgument{} | ||||
| 
 | ||||
| 	for i, p := range params { | ||||
| 		if vals[i] == "" { | ||||
| 			continue | ||||
| 		} | ||||
| 		args = append(args, c.Argument(p.Name, vals[i])) | ||||
| 	} | ||||
| 
 | ||||
| 	return args, nil | ||||
| } | ||||
| 
 | ||||
| func (c *Command) Argument(name string, val string) types.ReflectManagedMethodExecuterSoapArgument { | ||||
| 	return types.ReflectManagedMethodExecuterSoapArgument{ | ||||
| 		Name: name, | ||||
| 		Val:  fmt.Sprintf("<%s>%s</%s>", name, val, name), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (h CommandInfoHints) Formatter() string { | ||||
| 	for _, hint := range h { | ||||
| 		if hint.Key == "formatter" { | ||||
| 			return hint.Value | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return "simple" | ||||
| } | ||||
| 
 | ||||
| func (h CommandInfoHints) Fields() []string { | ||||
| 	for _, hint := range h { | ||||
| 		if strings.HasPrefix(hint.Key, "fields:") { | ||||
| 			return strings.Split(hint.Value, ",") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,143 @@ | |||
| /* | ||||
| 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 esxcli | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| ) | ||||
| 
 | ||||
| type esxcli struct { | ||||
| 	*flags.HostSystemFlag | ||||
| 
 | ||||
| 	hints bool | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.esxcli", &esxcli{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *esxcli) Usage() string { | ||||
| 	return "COMMAND [ARG]..." | ||||
| } | ||||
| 
 | ||||
| func (cmd *esxcli) Register(f *flag.FlagSet) { | ||||
| 	f.BoolVar(&cmd.hints, "hints", true, "Use command info hints when formatting output") | ||||
| } | ||||
| 
 | ||||
| func (cmd *esxcli) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *esxcli) Run(f *flag.FlagSet) error { | ||||
| 	c, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	host, err := cmd.HostSystem() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	e, err := NewExecutor(c, host) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	res, err := e.Run(f.Args()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(res.Values) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	var formatType string | ||||
| 	if cmd.hints { | ||||
| 		formatType = res.Info.Hints.Formatter() | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: OutputFlag / format options
 | ||||
| 	switch formatType { | ||||
| 	case "table": | ||||
| 		cmd.formatTable(res) | ||||
| 	default: | ||||
| 		cmd.formatSimple(res) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (cmd *esxcli) formatSimple(res *Response) { | ||||
| 	var keys []string | ||||
| 	for key := range res.Values[0] { | ||||
| 		keys = append(keys, key) | ||||
| 	} | ||||
| 	sort.Strings(keys) | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	for i, rv := range res.Values { | ||||
| 		if i > 0 { | ||||
| 			fmt.Fprintln(tw) | ||||
| 			_ = tw.Flush() | ||||
| 		} | ||||
| 		for _, key := range keys { | ||||
| 			fmt.Fprintf(tw, "%s:\t%s\n", key, strings.Join(rv[key], ", ")) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	_ = tw.Flush() | ||||
| } | ||||
| 
 | ||||
| func (cmd *esxcli) formatTable(res *Response) { | ||||
| 	fields := res.Info.Hints.Fields() | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, len(fields), 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	var hr []string | ||||
| 	for _, name := range fields { | ||||
| 		hr = append(hr, strings.Repeat("-", len(name))) | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Fprintln(tw, strings.Join(fields, "\t")) | ||||
| 	fmt.Fprintln(tw, strings.Join(hr, "\t")) | ||||
| 
 | ||||
| 	for _, vals := range res.Values { | ||||
| 		var row []string | ||||
| 
 | ||||
| 		for _, name := range fields { | ||||
| 			key := strings.Replace(name, " ", "", -1) | ||||
| 			if val, ok := vals[key]; ok { | ||||
| 				row = append(row, strings.Join(val, ", ")) | ||||
| 			} else { | ||||
| 				row = append(row, "") | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		fmt.Fprintln(tw, strings.Join(row, "\t")) | ||||
| 	} | ||||
| 
 | ||||
| 	_ = tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,166 @@ | |||
| /* | ||||
| 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 esxcli | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/vim25" | ||||
| 	"github.com/vmware/govmomi/vim25/methods" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"github.com/vmware/govmomi/vim25/xml" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type Executor struct { | ||||
| 	c    *vim25.Client | ||||
| 	host *object.HostSystem | ||||
| 	mme  *types.ReflectManagedMethodExecuter | ||||
| 	dtm  *types.InternalDynamicTypeManager | ||||
| 	info map[string]*CommandInfo | ||||
| } | ||||
| 
 | ||||
| func NewExecutor(c *vim25.Client, host *object.HostSystem) (*Executor, error) { | ||||
| 	e := &Executor{ | ||||
| 		c:    c, | ||||
| 		host: host, | ||||
| 		info: make(map[string]*CommandInfo), | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
| 		req := types.RetrieveManagedMethodExecuter{ | ||||
| 			This: host.Reference(), | ||||
| 		} | ||||
| 
 | ||||
| 		res, err := methods.RetrieveManagedMethodExecuter(context.TODO(), c, &req) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		e.mme = res.Returnval | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
| 		req := types.RetrieveDynamicTypeManager{ | ||||
| 			This: host.Reference(), | ||||
| 		} | ||||
| 
 | ||||
| 		res, err := methods.RetrieveDynamicTypeManager(context.TODO(), c, &req) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		e.dtm = res.Returnval | ||||
| 	} | ||||
| 
 | ||||
| 	return e, nil | ||||
| } | ||||
| 
 | ||||
| func (e *Executor) CommandInfo(c *Command) (*CommandInfoMethod, error) { | ||||
| 	ns := c.Namespace() | ||||
| 	var info *CommandInfo | ||||
| 	var ok bool | ||||
| 
 | ||||
| 	if info, ok = e.info[ns]; !ok { | ||||
| 		req := types.ExecuteSoap{ | ||||
| 			Moid:   "ha-dynamic-type-manager-local-cli-cliinfo", | ||||
| 			Method: "vim.CLIInfo.FetchCLIInfo", | ||||
| 			Argument: []types.ReflectManagedMethodExecuterSoapArgument{ | ||||
| 				c.Argument("typeName", "vim.EsxCLI."+ns), | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		info = new(CommandInfo) | ||||
| 		if err := e.Execute(&req, info); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		e.info[ns] = info | ||||
| 	} | ||||
| 
 | ||||
| 	name := c.Name() | ||||
| 	for _, method := range info.Method { | ||||
| 		if method.Name == name { | ||||
| 			return method, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, fmt.Errorf("method '%s' not found in name space '%s'", name, c.Namespace()) | ||||
| } | ||||
| 
 | ||||
| func (e *Executor) NewRequest(args []string) (*types.ExecuteSoap, *CommandInfoMethod, error) { | ||||
| 	c := NewCommand(args) | ||||
| 
 | ||||
| 	info, err := e.CommandInfo(c) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	sargs, err := c.Parse(info.Param) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	sreq := types.ExecuteSoap{ | ||||
| 		Moid:     c.Moid(), | ||||
| 		Method:   c.Method(), | ||||
| 		Argument: sargs, | ||||
| 	} | ||||
| 
 | ||||
| 	return &sreq, info, nil | ||||
| } | ||||
| 
 | ||||
| func (e *Executor) Execute(req *types.ExecuteSoap, res interface{}) error { | ||||
| 	req.This = e.mme.ManagedObjectReference | ||||
| 	req.Version = "urn:vim25/5.0" | ||||
| 
 | ||||
| 	x, err := methods.ExecuteSoap(context.TODO(), e.c, req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if x.Returnval != nil { | ||||
| 		if x.Returnval.Fault != nil { | ||||
| 			return errors.New(x.Returnval.Fault.FaultMsg) | ||||
| 		} | ||||
| 
 | ||||
| 		if err := xml.Unmarshal([]byte(x.Returnval.Response), res); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (e *Executor) Run(args []string) (*Response, error) { | ||||
| 	req, info, err := e.NewRequest(args) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	res := &Response{ | ||||
| 		Info: info, | ||||
| 	} | ||||
| 
 | ||||
| 	if err := e.Execute(req, res); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
							
								
								
									
										15
									
								
								vendor/github.com/vmware/govmomi/govc/host/esxcli/fixtures/network_vm_list.xml
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										15
									
								
								vendor/github.com/vmware/govmomi/govc/host/esxcli/fixtures/network_vm_list.xml
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,15 @@ | |||
| <obj xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:vim25" versionId="5.0" xsi:type="ArrayOfDataObject"> | ||||
|  <DataObject xsi:type="VimEsxCLInetworkvmlistVM"> | ||||
|   <Name>foo</Name> | ||||
|   <Networks>VM Network</Networks> | ||||
|   <Networks>dougm</Networks> | ||||
|   <NumPorts>2</NumPorts> | ||||
|   <WorldID>98842</WorldID> | ||||
|  </DataObject> | ||||
|  <DataObject xsi:type="VimEsxCLInetworkvmlistVM"> | ||||
|   <Name>bar</Name> | ||||
|   <Networks>VM Network</Networks> | ||||
|   <NumPorts>1</NumPorts> | ||||
|   <WorldID>236235</WorldID> | ||||
|  </DataObject> | ||||
| </obj> | ||||
							
								
								
									
										12
									
								
								vendor/github.com/vmware/govmomi/govc/host/esxcli/fixtures/network_vm_port_list.xml
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										12
									
								
								vendor/github.com/vmware/govmomi/govc/host/esxcli/fixtures/network_vm_port_list.xml
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,12 @@ | |||
| <obj xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:vim25" versionId="5.0" xsi:type="ArrayOfDataObject"> | ||||
|  <DataObject xsi:type="VimEsxCLInetworkvmportlistPort"> | ||||
|   <DVPortID></DVPortID> | ||||
|   <IPAddress>192.168.247.149</IPAddress> | ||||
|   <MACAddress>00:0c:29:12:b2:cf</MACAddress> | ||||
|   <PortID>33554438</PortID> | ||||
|   <Portgroup>VM Network</Portgroup> | ||||
|   <TeamUplink>vmnic0</TeamUplink> | ||||
|   <UplinkPortID>33554434</UplinkPortID> | ||||
|   <vSwitch>vSwitch0</vSwitch> | ||||
|  </DataObject> | ||||
| </obj> | ||||
							
								
								
									
										5
									
								
								vendor/github.com/vmware/govmomi/govc/host/esxcli/fixtures/system_hostname_get.xml
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										5
									
								
								vendor/github.com/vmware/govmomi/govc/host/esxcli/fixtures/system_hostname_get.xml
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,5 @@ | |||
| <obj xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:vim25" versionId="5.0" xsi:type="VimEsxCLIsystemhostnamegetFullyQualifiedHostName"> | ||||
|  <DomainName>localdomain</DomainName> | ||||
|  <FullyQualifiedDomainName>esxbox.localdomain</FullyQualifiedDomainName> | ||||
|  <HostName>esxbox</HostName> | ||||
| </obj> | ||||
|  | @ -0,0 +1,116 @@ | |||
| /* | ||||
| 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 esxcli | ||||
| 
 | ||||
| import ( | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/property" | ||||
| 	"github.com/vmware/govmomi/vim25" | ||||
| 	"github.com/vmware/govmomi/vim25/mo" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type hostInfo struct { | ||||
| 	*Executor | ||||
| 	wids map[string]string | ||||
| } | ||||
| 
 | ||||
| type GuestInfo struct { | ||||
| 	c     *vim25.Client | ||||
| 	hosts map[string]*hostInfo | ||||
| } | ||||
| 
 | ||||
| func NewGuestInfo(c *vim25.Client) *GuestInfo { | ||||
| 	return &GuestInfo{ | ||||
| 		c:     c, | ||||
| 		hosts: make(map[string]*hostInfo), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (g *GuestInfo) hostInfo(ref *types.ManagedObjectReference) (*hostInfo, error) { | ||||
| 	// cache exectuor and uuid -> worldid map
 | ||||
| 	if h, ok := g.hosts[ref.Value]; ok { | ||||
| 		return h, nil | ||||
| 	} | ||||
| 
 | ||||
| 	host := object.NewHostSystem(g.c, *ref) | ||||
| 
 | ||||
| 	e, err := NewExecutor(g.c, host) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	res, err := e.Run([]string{"vm", "process", "list"}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	ids := make(map[string]string, len(res.Values)) | ||||
| 
 | ||||
| 	for _, process := range res.Values { | ||||
| 		// Normalize uuid, esxcli and mo.VirtualMachine have different formats
 | ||||
| 		uuid := strings.Replace(process["UUID"][0], " ", "", -1) | ||||
| 		uuid = strings.Replace(uuid, "-", "", -1) | ||||
| 
 | ||||
| 		ids[uuid] = process["WorldID"][0] | ||||
| 	} | ||||
| 
 | ||||
| 	h := &hostInfo{e, ids} | ||||
| 	g.hosts[ref.Value] = h | ||||
| 
 | ||||
| 	return h, nil | ||||
| } | ||||
| 
 | ||||
| // IpAddress attempts to find the guest IP address using esxcli.
 | ||||
| // ESX hosts must be configured with the /Net/GuestIPHack enabled.
 | ||||
| // For example:
 | ||||
| // $ govc host.esxcli -- system settings advanced set -o /Net/GuestIPHack -i 1
 | ||||
| func (g *GuestInfo) IpAddress(vm *object.VirtualMachine) (string, error) { | ||||
| 	var mvm mo.VirtualMachine | ||||
| 
 | ||||
| 	pc := property.DefaultCollector(g.c) | ||||
| 	err := pc.RetrieveOne(context.TODO(), vm.Reference(), []string{"runtime.host", "config.uuid"}, &mvm) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	h, err := g.hostInfo(mvm.Runtime.Host) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	// Normalize uuid, esxcli and mo.VirtualMachine have different formats
 | ||||
| 	uuid := strings.Replace(mvm.Config.Uuid, "-", "", -1) | ||||
| 
 | ||||
| 	if wid, ok := h.wids[uuid]; ok { | ||||
| 		res, err := h.Run([]string{"network", "vm", "port", "list", "--world-id", wid}) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 
 | ||||
| 		if len(res.Values) == 1 { | ||||
| 			if ip, ok := res.Values[0]["IPAddress"]; ok { | ||||
| 				return ip[0], nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return "", nil | ||||
| } | ||||
|  | @ -0,0 +1,82 @@ | |||
| package esxcli | ||||
| 
 | ||||
| import ( | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/vim25/xml" | ||||
| ) | ||||
| 
 | ||||
| type Values map[string][]string | ||||
| 
 | ||||
| type Response struct { | ||||
| 	Info   *CommandInfoMethod | ||||
| 	Values []Values | ||||
| } | ||||
| 
 | ||||
| func (v Values) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { | ||||
| 	for { | ||||
| 		t, err := d.Token() | ||||
| 		if err != nil { | ||||
| 			if err == io.EOF { | ||||
| 				return nil | ||||
| 			} | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if s, ok := t.(xml.StartElement); ok { | ||||
| 			t, err = d.Token() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			key := s.Name.Local | ||||
| 			var val string | ||||
| 			if c, ok := t.(xml.CharData); ok { | ||||
| 				val = string(c) | ||||
| 			} | ||||
| 			v[key] = append(v[key], val) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r *Response) Type(start xml.StartElement) string { | ||||
| 	for _, a := range start.Attr { | ||||
| 		if a.Name.Local == "type" { | ||||
| 			return a.Value | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func (r *Response) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { | ||||
| 	stype := r.Type(start) | ||||
| 
 | ||||
| 	if stype != "ArrayOfDataObject" { | ||||
| 		v := Values{} | ||||
| 		if err := d.DecodeElement(&v, &start); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		r.Values = append(r.Values, v) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	for { | ||||
| 		t, err := d.Token() | ||||
| 		if err != nil { | ||||
| 			if err == io.EOF { | ||||
| 				return nil | ||||
| 			} | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if s, ok := t.(xml.StartElement); ok { | ||||
| 			if s.Name.Local == "DataObject" { | ||||
| 				v := Values{} | ||||
| 				if err := d.DecodeElement(&v, &s); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				r.Values = append(r.Values, v) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,129 @@ | |||
| /* | ||||
| 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 host | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/object" | ||||
| 	"github.com/vmware/govmomi/property" | ||||
| 	"github.com/vmware/govmomi/vim25/mo" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type info struct { | ||||
| 	*flags.ClientFlag | ||||
| 	*flags.OutputFlag | ||||
| 	*flags.HostSystemFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.info", &info{}) | ||||
| } | ||||
| 
 | ||||
| func (c *info) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (c *info) Process() error { return nil } | ||||
| 
 | ||||
| func (c *info) Run(f *flag.FlagSet) error { | ||||
| 	client, err := c.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var hosts []*object.HostSystem | ||||
| 
 | ||||
| 	// We could do without the -host flag, leaving it for compat
 | ||||
| 	host, err := c.HostSystemIfSpecified() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// Default only if there is a single host
 | ||||
| 	if host == nil && f.NArg() == 0 { | ||||
| 		host, err = c.HostSystem() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if host != nil { | ||||
| 		hosts = append(hosts, host) | ||||
| 	} else { | ||||
| 		hosts, err = c.HostSystems(f.Args()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var res infoResult | ||||
| 	var props []string | ||||
| 
 | ||||
| 	if c.OutputFlag.JSON { | ||||
| 		props = nil // Load everything
 | ||||
| 	} else { | ||||
| 		props = []string{"summary"} // Load summary
 | ||||
| 	} | ||||
| 
 | ||||
| 	for _, host := range hosts { | ||||
| 		var h mo.HostSystem | ||||
| 
 | ||||
| 		pc := property.DefaultCollector(client) | ||||
| 		err = pc.RetrieveOne(context.TODO(), host.Reference(), props, &h) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		res.HostSystems = append(res.HostSystems, h) | ||||
| 	} | ||||
| 
 | ||||
| 	return c.WriteResult(&res) | ||||
| } | ||||
| 
 | ||||
| type infoResult struct { | ||||
| 	HostSystems []mo.HostSystem | ||||
| } | ||||
| 
 | ||||
| func (r *infoResult) Write(w io.Writer) error { | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	for _, host := range r.HostSystems { | ||||
| 		s := host.Summary | ||||
| 		h := s.Hardware | ||||
| 		z := s.QuickStats | ||||
| 		ncpu := int(h.NumCpuPkgs * h.NumCpuCores) | ||||
| 		cpuUsage := 100 * float64(z.OverallCpuUsage) / float64(ncpu*h.CpuMhz) | ||||
| 		memUsage := 100 * float64(z.OverallMemoryUsage<<20) / float64(h.MemorySize) | ||||
| 
 | ||||
| 		fmt.Fprintf(tw, "Name:\t%s\n", s.Config.Name) | ||||
| 		fmt.Fprintf(tw, "  Manufacturer:\t%s\n", h.Vendor) | ||||
| 		fmt.Fprintf(tw, "  Logical CPUs:\t%d CPUs @ %dMHz\n", ncpu, h.CpuMhz) | ||||
| 		fmt.Fprintf(tw, "  Processor type:\t%s\n", h.CpuModel) | ||||
| 		fmt.Fprintf(tw, "  CPU usage:\t%d MHz (%.1f%%)\n", z.OverallCpuUsage, cpuUsage) | ||||
| 		fmt.Fprintf(tw, "  Memory:\t%dMB\n", h.MemorySize/(1024*1024)) | ||||
| 		fmt.Fprintf(tw, "  Memory usage:\t%d MB (%.1f%%)\n", z.OverallMemoryUsage, memUsage) | ||||
| 		fmt.Fprintf(tw, "  Boot time:\t%s\n", s.Runtime.BootTime) | ||||
| 	} | ||||
| 
 | ||||
| 	return tw.Flush() | ||||
| } | ||||
|  | @ -0,0 +1,58 @@ | |||
| /* | ||||
| 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 portgroup | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*flags.HostSystemFlag | ||||
| 
 | ||||
| 	spec types.HostPortGroupSpec | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.portgroup.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) { | ||||
| 	f.StringVar(&cmd.spec.VswitchName, "vswitch", "", "vSwitch Name") | ||||
| 	f.IntVar(&cmd.spec.VlanId, "vlan", 0, "VLAN ID") | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *add) Usage() string { | ||||
| 	return "NAME" | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	ns, err := cmd.HostNetworkSystem() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	cmd.spec.Name = f.Arg(0) | ||||
| 
 | ||||
| 	return ns.AddPortGroup(context.TODO(), cmd.spec) | ||||
| } | ||||
|  | @ -0,0 +1,50 @@ | |||
| /* | ||||
| 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 portgroup | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type remove struct { | ||||
| 	*flags.HostSystemFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.portgroup.remove", &remove{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *remove) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *remove) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *remove) Usage() string { | ||||
| 	return "NAME" | ||||
| } | ||||
| 
 | ||||
| func (cmd *remove) Run(f *flag.FlagSet) error { | ||||
| 	ns, err := cmd.HostNetworkSystem() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return ns.RemovePortGroup(context.TODO(), f.Arg(0)) | ||||
| } | ||||
|  | @ -0,0 +1,64 @@ | |||
| /* | ||||
| 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 vswitch | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/vim25/types" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type add struct { | ||||
| 	*flags.HostSystemFlag | ||||
| 
 | ||||
| 	nic  string | ||||
| 	spec types.HostVirtualSwitchSpec | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.vswitch.add", &add{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Register(f *flag.FlagSet) { | ||||
| 	f.IntVar(&cmd.spec.NumPorts, "ports", 128, "Number of ports") | ||||
| 	f.IntVar(&cmd.spec.Mtu, "mtu", 0, "MTU") | ||||
| 	f.StringVar(&cmd.nic, "nic", "", "Bridge nic device") | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *add) Usage() string { | ||||
| 	return "NAME" | ||||
| } | ||||
| 
 | ||||
| func (cmd *add) Run(f *flag.FlagSet) error { | ||||
| 	ns, err := cmd.HostNetworkSystem() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if cmd.nic != "" { | ||||
| 		cmd.spec.Bridge = &types.HostVirtualSwitchBondBridge{ | ||||
| 			NicDevice: []string{cmd.nic}, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return ns.AddVirtualSwitch(context.TODO(), f.Arg(0), &cmd.spec) | ||||
| } | ||||
|  | @ -0,0 +1,88 @@ | |||
| /* | ||||
| 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 vswitch | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"text/tabwriter" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"github.com/vmware/govmomi/property" | ||||
| 	"github.com/vmware/govmomi/vim25/mo" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type info struct { | ||||
| 	*flags.ClientFlag | ||||
| 	*flags.OutputFlag | ||||
| 	*flags.HostSystemFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.vswitch.info", &info{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *info) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *info) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *info) Run(f *flag.FlagSet) error { | ||||
| 	client, err := cmd.Client() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	ns, err := cmd.HostNetworkSystem() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var mns mo.HostNetworkSystem | ||||
| 
 | ||||
| 	pc := property.DefaultCollector(client) | ||||
| 	err = pc.RetrieveOne(context.TODO(), ns.Reference(), []string{"networkInfo.vswitch"}, &mns) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) | ||||
| 
 | ||||
| 	for i, s := range mns.NetworkInfo.Vswitch { | ||||
| 		if i > 0 { | ||||
| 			fmt.Fprintln(tw) | ||||
| 		} | ||||
| 		fmt.Fprintf(tw, "Name:\t%s\n", s.Name) | ||||
| 		fmt.Fprintf(tw, "Portgroup:\t%s\n", cmd.keys("key-vim.host.PortGroup-", s.Portgroup)) | ||||
| 		fmt.Fprintf(tw, "Pnic:\t%s\n", cmd.keys("key-vim.host.PhysicalNic-", s.Pnic)) | ||||
| 		fmt.Fprintf(tw, "MTU:\t%d\n", s.Mtu) | ||||
| 		fmt.Fprintf(tw, "Ports:\t%d\n", s.NumPorts) | ||||
| 		fmt.Fprintf(tw, "Ports Available:\t%d\n", s.NumPortsAvailable) | ||||
| 	} | ||||
| 
 | ||||
| 	return tw.Flush() | ||||
| } | ||||
| 
 | ||||
| func (cmd *info) keys(key string, vals []string) string { | ||||
| 	for i, val := range vals { | ||||
| 		vals[i] = strings.TrimPrefix(val, key) | ||||
| 	} | ||||
| 	return strings.Join(vals, ", ") | ||||
| } | ||||
|  | @ -0,0 +1,50 @@ | |||
| /* | ||||
| 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 vswitch | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 
 | ||||
| 	"github.com/vmware/govmomi/govc/cli" | ||||
| 	"github.com/vmware/govmomi/govc/flags" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
| type remove struct { | ||||
| 	*flags.HostSystemFlag | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	cli.Register("host.vswitch.remove", &remove{}) | ||||
| } | ||||
| 
 | ||||
| func (cmd *remove) Register(f *flag.FlagSet) {} | ||||
| 
 | ||||
| func (cmd *remove) Process() error { return nil } | ||||
| 
 | ||||
| func (cmd *remove) Usage() string { | ||||
| 	return "NAME" | ||||
| } | ||||
| 
 | ||||
| func (cmd *remove) Run(f *flag.FlagSet) error { | ||||
| 	ns, err := cmd.HostNetworkSystem() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return ns.RemoveVirtualSwitch(context.TODO(), f.Arg(0)) | ||||
| } | ||||
|  | @ -0,0 +1,97 @@ | |||
| /* | ||||
| 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 importx | ||||
| 
 | ||||
| import ( | ||||
| 	"archive/tar" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| ) | ||||
| 
 | ||||
| type Archive interface { | ||||
| 	Open(string) (io.ReadCloser, int64, error) | ||||
| } | ||||
| 
 | ||||
| type TapeArchive struct { | ||||
| 	path string | ||||
| } | ||||
| 
 | ||||
| type TapeArchiveEntry struct { | ||||
| 	io.Reader | ||||
| 	f *os.File | ||||
| } | ||||
| 
 | ||||
| func (t *TapeArchiveEntry) Close() error { | ||||
| 	return t.f.Close() | ||||
| } | ||||
| 
 | ||||
| func (t *TapeArchive) Open(name string) (io.ReadCloser, int64, error) { | ||||
| 	f, err := os.Open(t.path) | ||||
| 	if err != nil { | ||||
| 		return nil, 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	r := tar.NewReader(f) | ||||
| 
 | ||||
| 	for { | ||||
| 		h, err := r.Next() | ||||
| 		if err == io.EOF { | ||||
| 			break | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, 0, err | ||||
| 		} | ||||
| 
 | ||||
| 		matched, err := filepath.Match(name, path.Base(h.Name)) | ||||
| 		if err != nil { | ||||
| 			return nil, 0, err | ||||
| 		} | ||||
| 
 | ||||
| 		if matched { | ||||
| 			return &TapeArchiveEntry{r, f}, h.Size, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	_ = f.Close() | ||||
| 
 | ||||
| 	return nil, 0, os.ErrNotExist | ||||
| } | ||||
| 
 | ||||
| type FileArchive struct { | ||||
| 	path string | ||||
| } | ||||
| 
 | ||||
| func (t *FileArchive) Open(name string) (io.ReadCloser, int64, error) { | ||||
| 	fpath := name | ||||
| 	if name != t.path { | ||||
| 		fpath = filepath.Join(filepath.Dir(t.path), name) | ||||
| 	} | ||||
| 
 | ||||
| 	s, err := os.Stat(fpath) | ||||
| 	if err != nil { | ||||
| 		return nil, 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	f, err := os.Open(fpath) | ||||
| 	if err != nil { | ||||
| 		return nil, 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	return f, s.Size(), nil | ||||
| } | ||||
|  | @ -0,0 +1,59 @@ | |||
| /* | ||||
| 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 importx | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path" | ||||
| ) | ||||
| 
 | ||||
| type importable struct { | ||||
| 	localPath  string | ||||
| 	remotePath string | ||||
| } | ||||
| 
 | ||||
| func (i importable) Ext() string { | ||||
| 	return path.Ext(i.localPath) | ||||
| } | ||||
| 
 | ||||
| func (i importable) Base() string { | ||||
| 	return path.Base(i.localPath) | ||||
| } | ||||
| 
 | ||||
| func (i importable) BaseClean() string { | ||||
| 	b := i.Base() | ||||
| 	e := i.Ext() | ||||
| 	return b[:len(b)-len(e)] | ||||
| } | ||||
| 
 | ||||
| func (i importable) RemoteSrcVMDK() string { | ||||
| 	file := fmt.Sprintf("%s-src.vmdk", i.BaseClean()) | ||||
| 	return i.toRemotePath(file) | ||||
| } | ||||
| 
 | ||||
| func (i importable) RemoteDstVMDK() string { | ||||
| 	file := fmt.Sprintf("%s.vmdk", i.BaseClean()) | ||||
| 	return i.toRemotePath(file) | ||||
| } | ||||
| 
 | ||||
| func (i importable) toRemotePath(p string) string { | ||||
| 	if i.remotePath == "" { | ||||
| 		return p | ||||
| 	} | ||||
| 
 | ||||
| 	return path.Join(i.remotePath, p) | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue