vmesh 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitattributes +1 -0
- data/.gitignore +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +62 -0
- data/LICENSE.txt +21 -0
- data/README.md +175 -0
- data/README.rdoc +6 -0
- data/Rakefile +44 -0
- data/bin/vmesh +130 -0
- data/features/step_definitions/vmesh.create_steps.rb +9 -0
- data/features/step_definitions/vmesh.power_steps.rb +3 -0
- data/features/step_definitions/vmesh_steps.rb +9 -0
- data/features/support/env.rb +15 -0
- data/features/vmesh.create.feature +14 -0
- data/features/vmesh.feature +18 -0
- data/features/vmesh.power.feature +12 -0
- data/lib/vmesh/commands/create.rb +65 -0
- data/lib/vmesh/commands/create_helpers.rb +6 -0
- data/lib/vmesh/commands/list.rb +39 -0
- data/lib/vmesh/commands/power.rb +19 -0
- data/lib/vmesh/commands/revert.rb +16 -0
- data/lib/vmesh/create.rb +11 -0
- data/lib/vmesh/custom_spec.rb +25 -0
- data/lib/vmesh/datacenter.rb +42 -0
- data/lib/vmesh/datastore.rb +47 -0
- data/lib/vmesh/list.rb +4 -0
- data/lib/vmesh/logger.rb +14 -0
- data/lib/vmesh/machine.rb +67 -0
- data/lib/vmesh/server_defaults.rb +25 -0
- data/lib/vmesh/version.rb +3 -0
- data/lib/vmesh/vsphere.rb +88 -0
- data/lib/vmesh.rb +20 -0
- data/test/create_test.rb +45 -0
- data/test/datastore_test.rb +44 -0
- data/test/machine_test.rb +93 -0
- data/test/power_test.rb +33 -0
- data/test/test_helper.rb +22 -0
- data/test/vsphere_test.rb +44 -0
- data/vendor/cache/rbvmomi-1.8.2.gem +0 -0
- data/vmesh.gemspec +30 -0
- data/vmesh.rdoc +5 -0
- metadata +240 -0
data/.gitattributes
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* eol=lf
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
vmesh (0.1.3)
|
5
|
+
gli (= 2.9.0)
|
6
|
+
highline (~> 1.6)
|
7
|
+
logger (= 1.2.8)
|
8
|
+
nokogiri (~> 1.6)
|
9
|
+
rbvmomi (= 1.8.2)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
aruba (0.5.4)
|
15
|
+
childprocess (>= 0.3.6)
|
16
|
+
cucumber (>= 1.1.1)
|
17
|
+
rspec-expectations (>= 2.7.0)
|
18
|
+
builder (3.2.2)
|
19
|
+
childprocess (0.5.1)
|
20
|
+
ffi (~> 1.0, >= 1.0.11)
|
21
|
+
cucumber (1.3.13)
|
22
|
+
builder (>= 2.1.2)
|
23
|
+
diff-lcs (>= 1.1.3)
|
24
|
+
gherkin (~> 2.12)
|
25
|
+
multi_json (>= 1.7.5, < 2.0)
|
26
|
+
multi_test (>= 0.1.1)
|
27
|
+
diff-lcs (1.2.5)
|
28
|
+
ffi (1.9.3)
|
29
|
+
gherkin (2.12.2)
|
30
|
+
multi_json (~> 1.3)
|
31
|
+
gli (2.9.0)
|
32
|
+
highline (1.6.21)
|
33
|
+
json (1.8.1)
|
34
|
+
logger (1.2.8)
|
35
|
+
metaclass (0.0.4)
|
36
|
+
mini_portile (0.6.0)
|
37
|
+
mocha (1.0.0)
|
38
|
+
metaclass (~> 0.0.1)
|
39
|
+
multi_json (1.10.0)
|
40
|
+
multi_test (0.1.1)
|
41
|
+
nokogiri (1.6.3.1)
|
42
|
+
mini_portile (= 0.6.0)
|
43
|
+
rake (10.3.1)
|
44
|
+
rbvmomi (1.8.2)
|
45
|
+
builder
|
46
|
+
nokogiri (>= 1.4.1)
|
47
|
+
trollop
|
48
|
+
rdoc (4.1.1)
|
49
|
+
json (~> 1.4)
|
50
|
+
rspec-expectations (2.14.5)
|
51
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
52
|
+
trollop (2.0)
|
53
|
+
|
54
|
+
PLATFORMS
|
55
|
+
ruby
|
56
|
+
|
57
|
+
DEPENDENCIES
|
58
|
+
aruba (= 0.5.4)
|
59
|
+
mocha (= 1.0.0)
|
60
|
+
rake (= 10.3.1)
|
61
|
+
rdoc (= 4.1.1)
|
62
|
+
vmesh!
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) [year] [fullname]
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
# Command suite for VMWare
|
2
|
+
|
3
|
+
## What is Vmesh?
|
4
|
+
|
5
|
+
Vmesh is a Command Suite (think git) to make managing VMWare components easier and possible without leaving your local machine.
|
6
|
+
|
7
|
+
##THIS IS ALPHA!
|
8
|
+
|
9
|
+
Vmesh is currently Alpha, hence the 0-dot version; it is susceptible to methods, classes and modules being renamed, added or deleted.
|
10
|
+
|
11
|
+
## Setup
|
12
|
+
|
13
|
+
Install the gem
|
14
|
+
|
15
|
+
```
|
16
|
+
gem install vmesh
|
17
|
+
```
|
18
|
+
|
19
|
+
You can now start using it, e.g. list top level dirs
|
20
|
+
```
|
21
|
+
vmesh --datacenter=my.datacenter.com --host=my.vcenter.host.com ls
|
22
|
+
```
|
23
|
+
|
24
|
+
#### I don't want to type my connection config every time
|
25
|
+
|
26
|
+
Vmesh can save config so you don't have to type it each time, use initconfig with an alias like so
|
27
|
+
|
28
|
+
```
|
29
|
+
vmesh my_alias --datacenter=my.datacenter.com --host=my.vcenter.host.com initconfig
|
30
|
+
```
|
31
|
+
|
32
|
+
Commands are now as easy as
|
33
|
+
|
34
|
+
```
|
35
|
+
vmesh my_alias ls
|
36
|
+
```
|
37
|
+
|
38
|
+
#### How to setup cloning servers
|
39
|
+
|
40
|
+
Define the image types, their relevant template and any custom specs by editing the `server_defaults.rb` file
|
41
|
+
|
42
|
+
```
|
43
|
+
lib/vmesh/server_defaults.rb
|
44
|
+
```
|
45
|
+
|
46
|
+
e.g. an entry similar to
|
47
|
+
```
|
48
|
+
:linux => {
|
49
|
+
:name => 'Templates/CENTOS_6',
|
50
|
+
:spec => 'Linux No Prompt'
|
51
|
+
},
|
52
|
+
```
|
53
|
+
|
54
|
+
then to create a server named `vmlinux01` cloned from `'Templates/CENTOS_6'` template using a custom spec called `Linux No Prompt`
|
55
|
+
|
56
|
+
```
|
57
|
+
vmesh create vmlinux01 linux
|
58
|
+
```
|
59
|
+
|
60
|
+
#### AMG It complains about vtypes and stuff
|
61
|
+
|
62
|
+
* There is (or at least was?) an Rbvmomi hack required for nokogiri breaking change in 1.6.1, I'm still trying to figure the best way around this...
|
63
|
+
|
64
|
+
* https://github.com/vmware/rbvmomi/pull/32
|
65
|
+
|
66
|
+
|
67
|
+
## Usage
|
68
|
+
|
69
|
+
### Help
|
70
|
+
|
71
|
+
Get help
|
72
|
+
|
73
|
+
```
|
74
|
+
vmesh --help
|
75
|
+
```
|
76
|
+
|
77
|
+
Help on a specific command
|
78
|
+
|
79
|
+
```
|
80
|
+
vmesh create --help
|
81
|
+
```
|
82
|
+
|
83
|
+
### Create or clone
|
84
|
+
|
85
|
+
###### IP Handling
|
86
|
+
For multiple servers vmesh automatically increments the IP Address, e.g.
|
87
|
+
```
|
88
|
+
vmesh create vmweb01,vmweb02 linux --ip_address='192.168.0.10'
|
89
|
+
```
|
90
|
+
will create the following servers
|
91
|
+
|| server name || ip ||
|
92
|
+
| vmweb01 | 192.168.0.10 |
|
93
|
+
| vmweb02 | 192.168.0.11 |
|
94
|
+
|
95
|
+
Of course you can just comma separate the IPs too
|
96
|
+
```
|
97
|
+
vmesh create vmweb01,vmweb02 linux --ip_address='192.168.0.10','192.168.0.11'
|
98
|
+
```
|
99
|
+
|
100
|
+
###### How vmesh deals with datastores
|
101
|
+
When specifying datastore vmesh will use a datastore matching name exactly, if it doesn't find a match it will gets all datastores with this string in their name then uses the one with the most free space.
|
102
|
+
|
103
|
+
```
|
104
|
+
vmesh create my_vm_name2 windows12 [--ip_address='<ip_address>'] --datastore='SEARCH_STRING' [--folder='DESTINATION_FOLDER']
|
105
|
+
```
|
106
|
+
e.g. for the above, if datastores exist with names FIRST_SEARCH_STRING, ANOTHER_SEARCH_STRING it will find both (as they both contain "SEARCH_STRING") then use the one with the most free space.
|
107
|
+
|
108
|
+
### Power
|
109
|
+
|
110
|
+
To change the power state of a VM
|
111
|
+
|
112
|
+
```
|
113
|
+
vmesh power 'folder/machine_name' on
|
114
|
+
```
|
115
|
+
|
116
|
+
```
|
117
|
+
vmesh power 'folder/machine_name' off
|
118
|
+
```
|
119
|
+
|
120
|
+
##### Deleting a VM can be done with the command
|
121
|
+
|
122
|
+
```
|
123
|
+
vmesh power 'folder/machine_name' destroy
|
124
|
+
```
|
125
|
+
|
126
|
+
### List
|
127
|
+
|
128
|
+
_Note_ you can use `ls`, `dir` or `list`
|
129
|
+
|
130
|
+
List vms and directories at the top level
|
131
|
+
|
132
|
+
```
|
133
|
+
vmesh ls
|
134
|
+
```
|
135
|
+
|
136
|
+
List recursively
|
137
|
+
|
138
|
+
```
|
139
|
+
vmesh ls -r
|
140
|
+
```
|
141
|
+
|
142
|
+
List directories only
|
143
|
+
|
144
|
+
```
|
145
|
+
vmesh ls -d
|
146
|
+
```
|
147
|
+
|
148
|
+
## TODOs
|
149
|
+
|
150
|
+
* Sort out problem with upstream rbvmomi/nogokiri
|
151
|
+
|
152
|
+
* Related bug here https://github.com/nsidc/vagrant-vsphere/issues/28
|
153
|
+
|
154
|
+
* Create
|
155
|
+
|
156
|
+
* Don't create new vm if less than 10% space
|
157
|
+
|
158
|
+
* Power
|
159
|
+
|
160
|
+
* Query & display state after operation completes
|
161
|
+
|
162
|
+
* General
|
163
|
+
|
164
|
+
* Performance enhancements would be nice
|
165
|
+
|
166
|
+
* Server defaults in external configuration, e.g. Symlink to config/shared/ or etcd
|
167
|
+
|
168
|
+
* Vmesh everything else :-)
|
169
|
+
|
170
|
+
|
171
|
+
## Copyright
|
172
|
+
|
173
|
+
Copyright (c) 2014 Kurt Gardiner. See LICENSE.txt for further details.
|
174
|
+
|
175
|
+
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubygems/package_task'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'cucumber'
|
6
|
+
require 'cucumber/rake/task'
|
7
|
+
Rake::RDocTask.new do |rd|
|
8
|
+
rd.main = "README.rdoc"
|
9
|
+
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
10
|
+
rd.title = 'Your application title'
|
11
|
+
end
|
12
|
+
|
13
|
+
spec = eval(File.read('vmesh.gemspec'))
|
14
|
+
|
15
|
+
Gem::PackageTask.new(spec) do |pkg|
|
16
|
+
end
|
17
|
+
CUKE_RESULTS = 'results.html'
|
18
|
+
CLEAN << CUKE_RESULTS
|
19
|
+
desc 'Run features'
|
20
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
21
|
+
opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
|
22
|
+
opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
|
23
|
+
t.cucumber_opts = opts
|
24
|
+
t.fork = false
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Run features tagged as work-in-progress (@wip)'
|
28
|
+
Cucumber::Rake::Task.new('features:wip') do |t|
|
29
|
+
tag_opts = ' --tags ~@pending'
|
30
|
+
tag_opts = ' --tags @wip'
|
31
|
+
t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
|
32
|
+
t.fork = false
|
33
|
+
end
|
34
|
+
|
35
|
+
task :cucumber => :features
|
36
|
+
task 'cucumber:wip' => 'features:wip'
|
37
|
+
task :wip => 'features:wip'
|
38
|
+
require 'rake/testtask'
|
39
|
+
Rake::TestTask.new do |t|
|
40
|
+
t.libs << "test"
|
41
|
+
t.test_files = FileList['test/*_test.rb']
|
42
|
+
end
|
43
|
+
|
44
|
+
task :default => [:test,:features]
|
data/bin/vmesh
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'gli'
|
3
|
+
begin # XXX: Remove this begin/rescue before distributing your app
|
4
|
+
require 'vmesh'
|
5
|
+
require 'logger'
|
6
|
+
require 'highline/import'
|
7
|
+
|
8
|
+
rescue LoadError
|
9
|
+
STDERR.puts "In development, you need to use `bundle exec bin/vmesh` to run your app"
|
10
|
+
STDERR.puts "At install-time, RubyGems will make sure lib, etc. are in the load path"
|
11
|
+
STDERR.puts "Feel free to remove this message from bin/vmesh now"
|
12
|
+
exit 64
|
13
|
+
end
|
14
|
+
|
15
|
+
include GLI::App
|
16
|
+
|
17
|
+
version Vmesh::VERSION
|
18
|
+
Vmesh.logger = Logger.new(STDOUT)
|
19
|
+
@logger = Vmesh.logger
|
20
|
+
|
21
|
+
|
22
|
+
config_filename = '.vmesh.rc'
|
23
|
+
|
24
|
+
def check_migrate
|
25
|
+
Dir.glob(File.join(File.expand_path(ENV['HOME']),'.mesh.*.rc')).each do |mesh_file|
|
26
|
+
new_name = mesh_file.gsub('.mesh','.vmesh')
|
27
|
+
Vmesh.logger.info "Migrating #{mesh_file} from #{File.basename(mesh_file)} to #{new_name}"
|
28
|
+
File.rename mesh_file, new_name
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
check_migrate
|
33
|
+
|
34
|
+
if ARGV.count >= 2
|
35
|
+
host_alias = ARGV[0]
|
36
|
+
init_config = (ARGV.last == 'initconfig')
|
37
|
+
if init_config or File.exist? File.join(File.expand_path(ENV['HOME']),".vmesh.#{host_alias}.rc")
|
38
|
+
config_filename = ".vmesh.#{host_alias}.rc"
|
39
|
+
Vmesh.logger.info "Using host specific config file ~/.vmesh.#{host_alias}.rc"
|
40
|
+
ARGV.shift
|
41
|
+
else
|
42
|
+
Vmesh.logger.info "No site specific config file found, using default ~/#{config_filename}."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
config_file config_filename
|
47
|
+
|
48
|
+
program_desc 'VMWare VSphere command suite interface'
|
49
|
+
program_long_desc 'A command suite to allow users to manage VMWare virtual machines remotely via the command line'
|
50
|
+
|
51
|
+
desc 'Ignore SSL Certificate errors in connection'
|
52
|
+
switch [:insecure]
|
53
|
+
|
54
|
+
desc 'VCenter username'
|
55
|
+
arg_name 'user'
|
56
|
+
flag [:u,:user]
|
57
|
+
|
58
|
+
desc 'VCenter password'
|
59
|
+
arg_name 'password'
|
60
|
+
flag [:p,:password]
|
61
|
+
|
62
|
+
desc 'VCenter host'
|
63
|
+
arg_name 'vcenter host'
|
64
|
+
flag [:h,:host]
|
65
|
+
|
66
|
+
desc 'Datacenter'
|
67
|
+
arg_name 'datacenter'
|
68
|
+
flag [:d,:datacenter]
|
69
|
+
|
70
|
+
desc 'VCenter Resource Pool'
|
71
|
+
arg_name 'vcenter resource pool'
|
72
|
+
flag [:r,:resource_pool]
|
73
|
+
|
74
|
+
commands_from 'vmesh/commands'
|
75
|
+
|
76
|
+
desc 'TODO Describe destroy here'
|
77
|
+
arg_name 'Describe arguments to destroy here'
|
78
|
+
command :destroy do |c|
|
79
|
+
c.action do |global_options,options,args|
|
80
|
+
puts "destroy command ran"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
desc 'TODO Describe run here'
|
85
|
+
arg_name 'Describe arguments to run here'
|
86
|
+
command :run do |c|
|
87
|
+
c.action do |global_options,options,args|
|
88
|
+
puts "run command ran"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
desc 'TODO Describe info here'
|
93
|
+
arg_name 'Describe arguments to info here'
|
94
|
+
command :info do |c|
|
95
|
+
c.action do |global_options,options,args|
|
96
|
+
puts "info command ran"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
pre do |global,command,options,args|
|
101
|
+
# Pre logic here
|
102
|
+
# Return true to proceed; false to abort and not call the
|
103
|
+
# chosen command
|
104
|
+
# Use skips_pre before a command to skip this block
|
105
|
+
# on that command only
|
106
|
+
if global[:user].to_s == ''
|
107
|
+
not_so_secret_username = ask("Enter Username please:") {|q| q.echo = true}
|
108
|
+
global['u'] = global[:u] = global['user'] = global[:user] = not_so_secret_username
|
109
|
+
end
|
110
|
+
|
111
|
+
if global[:password].to_s == ''
|
112
|
+
the_super_secret_password = ask("Enter Password for #{global[:user]} please:") {|q| q.echo = false}
|
113
|
+
global['p'] = global[:p] = global['password'] = global[:password] = the_super_secret_password
|
114
|
+
end
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
post do |global,command,options,args|
|
119
|
+
# Post logic here
|
120
|
+
# Use skips_post before a command to skip this
|
121
|
+
# block on that command only
|
122
|
+
end
|
123
|
+
|
124
|
+
on_error do |exception|
|
125
|
+
# Error logic here
|
126
|
+
# return false to skip default error handling
|
127
|
+
true
|
128
|
+
end
|
129
|
+
|
130
|
+
exit run(ARGV)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'aruba/cucumber'
|
2
|
+
|
3
|
+
ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
4
|
+
LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
|
5
|
+
|
6
|
+
Before do
|
7
|
+
# Using "announce" causes massive warnings on 1.9.2
|
8
|
+
@puts = true
|
9
|
+
@original_rubylib = ENV['RUBYLIB']
|
10
|
+
ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
After do
|
14
|
+
ENV['RUBYLIB'] = @original_rubylib
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Feature: Create a new VM
|
2
|
+
In order to provision new infrastructure
|
3
|
+
I want to be able to create new templated VMs
|
4
|
+
So I have consistent easily created VMs
|
5
|
+
|
6
|
+
Scenario: Create with no arguments
|
7
|
+
When I create with no arguments
|
8
|
+
Then the exit status should be 1
|
9
|
+
|
10
|
+
Scenario: Create with unknown vm type
|
11
|
+
When I create with "unknown" template and name "anything"
|
12
|
+
Then the exit status should be 1
|
13
|
+
And the stderr should contain "unknown machine type"
|
14
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: My bootstrapped app kinda works
|
2
|
+
In order to get going on coding my awesome app
|
3
|
+
I want to have aruba and cucumber setup
|
4
|
+
So I don't have to do it myself
|
5
|
+
|
6
|
+
Scenario: vmesh just runs
|
7
|
+
When I get help for "vmesh"
|
8
|
+
Then the exit status should be 0
|
9
|
+
|
10
|
+
|
11
|
+
Scenario: vmesh create just runs
|
12
|
+
When I get help for "vmesh create"
|
13
|
+
Then the exit status should be 0
|
14
|
+
|
15
|
+
Scenario: vmesh power just runs
|
16
|
+
When I get help for "vmesh power"
|
17
|
+
Then the exit status should be 0
|
18
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Feature: Change Power State of a VM
|
2
|
+
In order to manage servers
|
3
|
+
I want to be able to change the power state of VMs
|
4
|
+
So I can easily manage these servers
|
5
|
+
|
6
|
+
Scenario: Power with no arguments
|
7
|
+
When I power with no arguments
|
8
|
+
Then the exit status should be 1
|
9
|
+
|
10
|
+
Scenario: Power vm into an unknown state
|
11
|
+
When I power machine "vmfrozen01" into state "unfrozed"
|
12
|
+
Then the exit status should be 1
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
desc 'create a new virtual machine'
|
4
|
+
arg_name 'folder/name[,folder/name_of_second_machine] type'
|
5
|
+
|
6
|
+
command :create do |c|
|
7
|
+
c.desc 'Destination datastore, full or partial match'
|
8
|
+
c.long_desc 'Destination datastore, full or partial match, partial match will use datastore including the string with the greatest free space'
|
9
|
+
c.flag [:s, :datastore]
|
10
|
+
|
11
|
+
c.desc 'Destination folder where not supplied with name'
|
12
|
+
c.long_desc 'Destination folder for the vm(s), will be ignored for any vms with a folder supplied as part of the name'
|
13
|
+
c.flag [:f, :folder]
|
14
|
+
|
15
|
+
# This wasn't working for what-ever reason, no error, just no effect
|
16
|
+
#c.desc 'Number of CPUs'
|
17
|
+
#c.long_desc 'Number of CPUs'
|
18
|
+
#c.flag [:c, :cpus]
|
19
|
+
#
|
20
|
+
#c.desc 'MB of RAM'
|
21
|
+
#c.long_desc 'MB of RAM'
|
22
|
+
#c.flag [:r, :ramMB]
|
23
|
+
|
24
|
+
c.desc 'Destination Machine IP Address'
|
25
|
+
c.long_desc 'Destination machine IP Address, when creating multiple vms ips will be calculated by incrementing this value'
|
26
|
+
c.flag :ip_address
|
27
|
+
c.action do |global_options,options,args|
|
28
|
+
|
29
|
+
ARGV.size >= 2 or abort "must specify VM target name and VM type"
|
30
|
+
vm_targets = ARGV.shift
|
31
|
+
vm_type = ARGV.shift
|
32
|
+
@logger.debug "Create invoked to create #{vm_targets} of type #{vm_type}\n\t#{global_options[:host]}\n\t#{options}\n\t#{args}."
|
33
|
+
Vmesh::template.has_key? vm_type.to_sym or raise "unknown machine type #{vm_type}, known types are #{Vmesh::template.keys.to_s}"
|
34
|
+
|
35
|
+
ip_address = options[:ip_address]
|
36
|
+
machine_options = {}
|
37
|
+
vm_manager = Vmesh::VSphere.new global_options
|
38
|
+
#default_vm_folder = vm_manager.get_folder(options[:folder]) if options[:folder]
|
39
|
+
default_vm_folder = options[:folder] || '/'
|
40
|
+
vm_targets.split(',').each do |vm_target|
|
41
|
+
machine_options[:ip_address] = ip_address if ip_address.to_s != ''
|
42
|
+
machine_options[:datastore] = options[:datastore] if options[:datastore].to_s != ''
|
43
|
+
machine_options[:memoryMB] = options[:ramMB] if options[:ramMB].to_s != ''
|
44
|
+
machine_options[:numCPUs] = options[:cpus] if options[:cpus].to_s != ''
|
45
|
+
new_vm = vm_manager.clone_machine(vm_type, vm_target, default_vm_folder, machine_options)
|
46
|
+
Vmesh.logger.info "#{vm_type}, #{vm_target}, #{machine_options}"
|
47
|
+
ip_address = IPAddr.new(ip_address).succ.to_s if ip_address.to_s != ''
|
48
|
+
Vmesh.logger.warn "Check #{vm_target}, nil vm returned..." if new_vm.nil?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module Vmesh
|
54
|
+
def self.parse_vm_target(vm_target)
|
55
|
+
vm_details = vm_target.match(/(.+)\/(.+)/)
|
56
|
+
vm = Hash.new
|
57
|
+
vm[:folder] = '/'
|
58
|
+
vm[:name] = vm_target
|
59
|
+
if vm_details
|
60
|
+
vm[:folder] = vm_details[1]
|
61
|
+
vm[:name] = vm_details[2]
|
62
|
+
end
|
63
|
+
vm
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
desc 'list directory contents'
|
3
|
+
arg_name '[dir]'
|
4
|
+
|
5
|
+
command [:list,:ls,:dir] do |c|
|
6
|
+
c.desc 'list directory entries instead of contents, and do not dereference symbolic links'
|
7
|
+
c.switch [:d, :directory]
|
8
|
+
|
9
|
+
c.desc 'list recursively'
|
10
|
+
c.switch [:r, :recursive]
|
11
|
+
|
12
|
+
c.action do |global_options,options,args|
|
13
|
+
pwd = ARGV.shift if ARGV.any?
|
14
|
+
vm_manager = Vmesh::VSphere.new global_options
|
15
|
+
show_directories_only = options[:directory]
|
16
|
+
folder = pwd.nil? ? vm_manager.vm_root_folder : vm_manager.get_folder(pwd)
|
17
|
+
raise "Folder #{pwd} not found, exiting" if folder.to_s == ''
|
18
|
+
Vmesh::logger.debug "Searching folder #{folder.name}."
|
19
|
+
Vmesh::list_under folder,show_directories_only,options[:recursive],"/#{folder.name}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Vmesh
|
24
|
+
def self.list_under(folder, show_directories_only, recurse = false, currently_in = '')
|
25
|
+
currently_in = '' if currently_in == '/vm'
|
26
|
+
folder.childEntity.each do |x|
|
27
|
+
name = x.to_s.split('(').first
|
28
|
+
case name
|
29
|
+
when "Folder"
|
30
|
+
puts "#{currently_in}/#{x.name}/" #if show_directories_only
|
31
|
+
list_under(x, show_directories_only, recurse, "#{currently_in}/#{x.name}" ) if recurse
|
32
|
+
when "VirtualMachine"
|
33
|
+
puts "#{currently_in}/#{x.name}" unless show_directories_only
|
34
|
+
else
|
35
|
+
puts "# Unrecognized Entity " + x.to_s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
desc 'change the power state of the vm'
|
3
|
+
arg_name 'vm_name [on|off|reset|suspend|destroy]'
|
4
|
+
|
5
|
+
command :power do |c|
|
6
|
+
c.action do |global_options,options,args|
|
7
|
+
ARGV.size >= 2 or abort "must specify VM and a desired state."
|
8
|
+
vm_target = ARGV.shift
|
9
|
+
desired_state = ARGV.shift
|
10
|
+
abort "Invalid desired state #{desired_state}, valid ones are #{Vmesh::Machine::valid_states}." unless Vmesh::Machine::valid_states.include? desired_state
|
11
|
+
@logger.debug "Power invoked for #{vm_target} with desired state #{desired_state}\n\t#{global_options[:host]}\n\t#{options}\n\t#{args}."
|
12
|
+
|
13
|
+
vm_manager = Vmesh::VSphere.new global_options
|
14
|
+
vm = vm_manager.get_machine(vm_target, global_options[:datacenter])
|
15
|
+
Vmesh::logger.debug "Got vm #{vm.name}"
|
16
|
+
|
17
|
+
vm.power desired_state
|
18
|
+
end
|
19
|
+
end
|