fission 0.1.0
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/.gitignore +4 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +51 -0
- data/Rakefile +11 -0
- data/bin/fission +7 -0
- data/fission.gemspec +23 -0
- data/lib/fission.rb +28 -0
- data/lib/fission/cli.rb +59 -0
- data/lib/fission/command.rb +15 -0
- data/lib/fission/command/clone.rb +57 -0
- data/lib/fission/config.rb +26 -0
- data/lib/fission/core_ext/class.rb +5 -0
- data/lib/fission/core_ext/object.rb +112 -0
- data/lib/fission/ui.rb +18 -0
- data/lib/fission/version.rb +3 -0
- data/lib/fission/vm.rb +62 -0
- data/spec/fission/cli_spec.rb +63 -0
- data/spec/fission/command/clone_spec.rb +90 -0
- data/spec/fission/command_spec.rb +26 -0
- data/spec/fission/config_spec.rb +30 -0
- data/spec/fission/ui_spec.rb +26 -0
- data/spec/fission/vm_spec.rb +107 -0
- data/spec/fission_spec.rb +15 -0
- data/spec/spec_helper.rb +20 -0
- metadata +110 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2@fission --create
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2011 Thomas Bishop, bishop.thomas@gmail.com
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Fission
|
2
|
+
|
3
|
+
## Intro
|
4
|
+
Fission is a simple command line tool for cloning of VMware Fusion VMs.
|
5
|
+
|
6
|
+
|
7
|
+
## Config
|
8
|
+
By default, fission will use the default VMware Fusion VM directory
|
9
|
+
(~/Documents/Virtual Machines.localized/) when cloning. If you want to use a
|
10
|
+
different directory, you can set this in a config file.
|
11
|
+
|
12
|
+
The config file needs to be in yaml format and live at '~/.fissionrc'
|
13
|
+
|
14
|
+
$cat ~/.fissionrc
|
15
|
+
---
|
16
|
+
vm_dir: "/vm"
|
17
|
+
|
18
|
+
|
19
|
+
## Install
|
20
|
+
gem install fission
|
21
|
+
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
### Clone
|
25
|
+
fission clone existing_vm new_vm
|
26
|
+
|
27
|
+
### Help
|
28
|
+
fission -h
|
29
|
+
|
30
|
+
or just
|
31
|
+
|
32
|
+
fission
|
33
|
+
|
34
|
+
|
35
|
+
## Other Notable Info
|
36
|
+
As of now, VMware Fusion doesn't provide an easy, out of
|
37
|
+
the box, way to modify the personality (hostname, ip, etc.) of a VM. Because of
|
38
|
+
this, a clone created by fission is an _exact_ copy of the original (including
|
39
|
+
hostname, ip address, etc.). Most likely, this isn't what you want.
|
40
|
+
|
41
|
+
One approach is to create a VM which will act as a template. Create the VM with
|
42
|
+
the desired install method (ideally with easy install) and settings, but do not
|
43
|
+
power on the VM. You can create clones from this VM and when you power it on,
|
44
|
+
it will start the OS install process (and assign a new ip, etc.)
|
45
|
+
|
46
|
+
|
47
|
+
## Contribute
|
48
|
+
* Fork the project
|
49
|
+
* Make your feature addition or bug fix (with tests) in a topic branch
|
50
|
+
* Bonus points for not mucking with the gemspec or version
|
51
|
+
* Send a pull request and I'll get it integrated
|
data/Rakefile
ADDED
data/bin/fission
ADDED
data/fission.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "fission/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "fission"
|
7
|
+
s.version = Fission::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Tommy Bishop']
|
10
|
+
s.email = ['bishop.thomas@gmail.com']
|
11
|
+
s.homepage = "https://github.com/thbishop/fission"
|
12
|
+
s.summary = %q{Tool to clone VMware fusion VMs}
|
13
|
+
s.description = %q{A simple utility to create VMware Fusion VM clones}
|
14
|
+
|
15
|
+
s.rubyforge_project = "fission"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.add_development_dependency 'rspec', '~> 2.6.0'
|
22
|
+
s.add_development_dependency 'fakefs', '~> 0.3.2'
|
23
|
+
end
|
data/lib/fission.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'optparse'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
7
|
+
|
8
|
+
require 'fission/cli'
|
9
|
+
require 'fission/command'
|
10
|
+
require 'fission/command/clone'
|
11
|
+
require 'fission/config'
|
12
|
+
require 'fission/core_ext/class'
|
13
|
+
require 'fission/core_ext/object'
|
14
|
+
require 'fission/ui'
|
15
|
+
require 'fission/vm'
|
16
|
+
require 'fission/version'
|
17
|
+
|
18
|
+
module Fission
|
19
|
+
extend self
|
20
|
+
|
21
|
+
def config
|
22
|
+
@config ||= Fission::Config.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def ui
|
26
|
+
@ui ||= Fission::UI.new
|
27
|
+
end
|
28
|
+
end
|
data/lib/fission/cli.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module Fission
|
2
|
+
class CLI
|
3
|
+
def self.execute(args=ARGV)
|
4
|
+
optparse = OptionParser.new do |opts|
|
5
|
+
opts.banner = "\nUsage: fission [options] COMMAND [arguments]"
|
6
|
+
|
7
|
+
opts.on_head('-v', '--version', 'Output the version of fission') do
|
8
|
+
Fission.ui.output Fission::VERSION
|
9
|
+
exit(0)
|
10
|
+
end
|
11
|
+
|
12
|
+
opts.on_head('-h', '--help', 'Displays this message') do
|
13
|
+
show_all_help(optparse)
|
14
|
+
exit(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.define_tail do
|
18
|
+
commands_banner
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
begin
|
24
|
+
optparse.order! args
|
25
|
+
rescue OptionParser::InvalidOption => e
|
26
|
+
Fission.ui.output e
|
27
|
+
show_all_help(optparse)
|
28
|
+
exit(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
case args.first
|
32
|
+
when 'clone'
|
33
|
+
@command = Fission::Command::Clone.new args.drop 1
|
34
|
+
@command.execute
|
35
|
+
else
|
36
|
+
show_all_help(optparse)
|
37
|
+
exit(0)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def self.commands_banner
|
44
|
+
text = "\nCommands:\n"
|
45
|
+
Fission::Command.descendants.each do |command_klass|
|
46
|
+
text << (command_klass.send :help)
|
47
|
+
text << "\n\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
text
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.show_all_help(options)
|
54
|
+
Fission.ui.output options
|
55
|
+
Fission.ui.output commands_banner
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Fission
|
2
|
+
class Command
|
3
|
+
class Clone < Command
|
4
|
+
|
5
|
+
def initialize(args=[])
|
6
|
+
super
|
7
|
+
@options.start = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute
|
11
|
+
unless args.count > 1
|
12
|
+
Fission.ui.output self.class.help
|
13
|
+
Fission.ui.output ""
|
14
|
+
Fission.ui.output_and_exit "Incorrect arguments for clone command", 1
|
15
|
+
end
|
16
|
+
|
17
|
+
source_vm = @args.first
|
18
|
+
target_vm = @args[1]
|
19
|
+
|
20
|
+
unless Fission::VM.exists? source_vm
|
21
|
+
Fission.ui.output_and_exit "Unable to find the source vm #{source_vm} (#{Fission::VM.path(source_vm)})", 1
|
22
|
+
end
|
23
|
+
|
24
|
+
if Fission::VM.exists? target_vm
|
25
|
+
Fission::ui.output_and_exit "The target vm #{target_vm} already exists", 1
|
26
|
+
end
|
27
|
+
|
28
|
+
clone_options = option_parser
|
29
|
+
clone_options.parse! @args
|
30
|
+
|
31
|
+
Fission::VM.clone source_vm, target_vm
|
32
|
+
|
33
|
+
Fission.ui.output ''
|
34
|
+
Fission.ui.output 'Clone complete!'
|
35
|
+
|
36
|
+
if @options.start
|
37
|
+
Fission.ui.output "Starting '#{target_vm}'"
|
38
|
+
@vm = Fission::VM.new target_vm
|
39
|
+
@vm.start
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def option_parser
|
44
|
+
optparse = OptionParser.new do |opts|
|
45
|
+
opts.banner = "\nclone usage: fission clone source_vm target_vm [options]"
|
46
|
+
|
47
|
+
opts.on '--start', 'Start the VM after cloning' do
|
48
|
+
@options.start = true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
optparse
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Fission
|
2
|
+
class Config
|
3
|
+
attr_accessor :attributes
|
4
|
+
|
5
|
+
CONF_FILE = File.expand_path '~/.fissionrc'
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@attributes = {}
|
9
|
+
load_from_file
|
10
|
+
|
11
|
+
if @attributes['vm_dir'].blank?
|
12
|
+
@attributes['vm_dir'] = File.expand_path('~/Documents/Virtual Machines.localized/')
|
13
|
+
end
|
14
|
+
|
15
|
+
@attributes['vmrun_bin'] = '/Library/Application Support/VMware Fusion/vmrun'
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def load_from_file
|
20
|
+
if File.file?(CONF_FILE)
|
21
|
+
@attributes.merge!(YAML.load_file(CONF_FILE))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# this is from active_support
|
2
|
+
# github.com/rails/rails/activesupport
|
3
|
+
#
|
4
|
+
class Object
|
5
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
6
|
+
# For example, "", " ", +nil+, [], and {} are blank.
|
7
|
+
#
|
8
|
+
# This simplifies:
|
9
|
+
#
|
10
|
+
# if !address.nil? && !address.empty?
|
11
|
+
#
|
12
|
+
# ...to:
|
13
|
+
#
|
14
|
+
# if !address.blank?
|
15
|
+
def blank?
|
16
|
+
respond_to?(:empty?) ? empty? : !self
|
17
|
+
end
|
18
|
+
|
19
|
+
# An object is present if it's not <tt>blank?</tt>.
|
20
|
+
def present?
|
21
|
+
!blank?
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns object if it's <tt>present?</tt> otherwise returns +nil+.
|
25
|
+
# <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
|
26
|
+
#
|
27
|
+
# This is handy for any representation of objects where blank is the same
|
28
|
+
# as not present at all. For example, this simplifies a common check for
|
29
|
+
# HTTP POST/query parameters:
|
30
|
+
#
|
31
|
+
# state = params[:state] if params[:state].present?
|
32
|
+
# country = params[:country] if params[:country].present?
|
33
|
+
# region = state || country || 'US'
|
34
|
+
#
|
35
|
+
# ...becomes:
|
36
|
+
#
|
37
|
+
# region = params[:state].presence || params[:country].presence || 'US'
|
38
|
+
def presence
|
39
|
+
self if present?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class NilClass
|
44
|
+
# +nil+ is blank:
|
45
|
+
#
|
46
|
+
# nil.blank? # => true
|
47
|
+
#
|
48
|
+
def blank?
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class FalseClass
|
54
|
+
# +false+ is blank:
|
55
|
+
#
|
56
|
+
# false.blank? # => true
|
57
|
+
#
|
58
|
+
def blank?
|
59
|
+
true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class TrueClass
|
64
|
+
# +true+ is not blank:
|
65
|
+
#
|
66
|
+
# true.blank? # => false
|
67
|
+
#
|
68
|
+
def blank?
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Array
|
74
|
+
# An array is blank if it's empty:
|
75
|
+
#
|
76
|
+
# [].blank? # => true
|
77
|
+
# [1,2,3].blank? # => false
|
78
|
+
#
|
79
|
+
alias_method :blank?, :empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
class Hash
|
83
|
+
# A hash is blank if it's empty:
|
84
|
+
#
|
85
|
+
# {}.blank? # => true
|
86
|
+
# {:key => 'value'}.blank? # => false
|
87
|
+
#
|
88
|
+
alias_method :blank?, :empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
class String
|
92
|
+
# A string is blank if it's empty or contains whitespaces only:
|
93
|
+
#
|
94
|
+
# "".blank? # => true
|
95
|
+
# " ".blank? # => true
|
96
|
+
# " something here ".blank? # => false
|
97
|
+
#
|
98
|
+
def blank?
|
99
|
+
self !~ /\S/
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class Numeric #:nodoc:
|
104
|
+
# No number is blank:
|
105
|
+
#
|
106
|
+
# 1.blank? # => false
|
107
|
+
# 0.blank? # => false
|
108
|
+
#
|
109
|
+
def blank?
|
110
|
+
false
|
111
|
+
end
|
112
|
+
end
|
data/lib/fission/ui.rb
ADDED
data/lib/fission/vm.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
module Fission
|
2
|
+
class VM
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(name)
|
6
|
+
@name = name
|
7
|
+
end
|
8
|
+
|
9
|
+
def start
|
10
|
+
command = "#{Fission.config.attributes['vmrun_bin'].gsub(' ', '\ ' )} -T fusion start #{conf_file.gsub ' ', '\ '} gui 2>&1"
|
11
|
+
output = `#{command}`
|
12
|
+
|
13
|
+
if $?.exitstatus == 0
|
14
|
+
Fission.ui.output "VM started"
|
15
|
+
else
|
16
|
+
Fission.ui.output "There was a problem starting the VM. The error was:\n#{output}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def conf_file
|
21
|
+
File.join self.class.path(@name), "#{@name}.vmx"
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.exists?(vm_name)
|
25
|
+
File.directory? path(vm_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.path(vm_name)
|
29
|
+
File.join Fission.config.attributes['vm_dir'], "#{vm_name}.vmwarevm"
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.clone(source_vm, target_vm)
|
33
|
+
Fission.ui.output "Cloning #{source_vm} to #{target_vm}"
|
34
|
+
FileUtils.cp_r path(source_vm), path(target_vm)
|
35
|
+
|
36
|
+
Fission.ui.output "Configuring #{target_vm}"
|
37
|
+
rename_vm_files source_vm, target_vm
|
38
|
+
update_config source_vm, target_vm
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def self.rename_vm_files(from, to)
|
43
|
+
files_to_rename(from, to).each do |file|
|
44
|
+
FileUtils.mv File.join(path(to), file), File.join(path(to), file.gsub(from, to))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.files_to_rename(from, to)
|
49
|
+
Dir.entries(path(to)).select { |f| f.include?(from) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.update_config(from, to)
|
53
|
+
['.vmdk', '.vmx', '.vmxf'].each do |ext|
|
54
|
+
file = File.join path(to), "#{to}#{ext}"
|
55
|
+
text = File.read file
|
56
|
+
text.gsub! from, to
|
57
|
+
File.open(file, 'w'){ |f| f.print text }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.expand_path('../../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe Fission::CLI do
|
4
|
+
before :each do
|
5
|
+
@string_io = StringIO.new
|
6
|
+
Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'execute' do
|
10
|
+
|
11
|
+
describe 'with no arguments' do
|
12
|
+
it 'should output the usage info' do
|
13
|
+
lambda {
|
14
|
+
Fission::CLI.execute []
|
15
|
+
}.should raise_error SystemExit
|
16
|
+
|
17
|
+
@string_io.string.should match /Usage/
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '-v or --version' do
|
22
|
+
['-v', '--version'].each do |arg|
|
23
|
+
it "should output the version with #{arg}" do
|
24
|
+
lambda {
|
25
|
+
Fission::CLI.execute [arg]
|
26
|
+
}.should raise_error SystemExit
|
27
|
+
|
28
|
+
@string_io.string.should match /#{Fission::VERSION}/
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '-h or --help' do
|
36
|
+
['-h', '--help'].each do |arg|
|
37
|
+
it "should output the usage info with #{arg}" do
|
38
|
+
lambda {
|
39
|
+
Fission::CLI.execute [arg]
|
40
|
+
}.should raise_error SystemExit
|
41
|
+
|
42
|
+
@string_io.string.should match /Usage/
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'clone' do
|
49
|
+
before :each do
|
50
|
+
@clone_mock = mock('clone_mock')
|
51
|
+
Fission::Command::Clone.stub!(:help).and_return('')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should try to clone the vm" do
|
55
|
+
@clone_mock.should_receive(:execute)
|
56
|
+
Fission::Command::Clone.should_receive(:new).with(['foo', 'bar']).and_return(@clone_mock)
|
57
|
+
|
58
|
+
Fission::CLI.execute ['clone', 'foo', 'bar']
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe Fission::Command::Clone do
|
4
|
+
before :all do
|
5
|
+
@vm_info = ['foo', 'bar']
|
6
|
+
end
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@string_io = StringIO.new
|
10
|
+
Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'execute' do
|
14
|
+
[ [], ['foo'] ].each do |args|
|
15
|
+
it "should output an error and the help when #{args.count} arguments are passed in" do
|
16
|
+
Fission::Command::Clone.should_receive(:help)
|
17
|
+
|
18
|
+
lambda {
|
19
|
+
command = Fission::Command::Clone.new args
|
20
|
+
command.execute
|
21
|
+
}.should raise_error SystemExit
|
22
|
+
|
23
|
+
@string_io.string.should match /Incorrect arguments for clone command/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should output an error and exit if it can't find the source vm" do
|
28
|
+
Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(false)
|
29
|
+
Fission::VM.should_not_receive(:exists?).with(@vm_info[1])
|
30
|
+
|
31
|
+
lambda {
|
32
|
+
command = Fission::Command::Clone.new @vm_info
|
33
|
+
command.execute
|
34
|
+
}.should raise_error SystemExit
|
35
|
+
|
36
|
+
@string_io.string.should match /Unable to find the source vm #{@vm_info.first}/
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it "should output an error and exit if the target vm already exists" do
|
41
|
+
@vm_info.each do |vm|
|
42
|
+
Fission::VM.should_receive(:exists?).with(vm).and_return(true)
|
43
|
+
end
|
44
|
+
|
45
|
+
lambda {
|
46
|
+
command = Fission::Command::Clone.new @vm_info
|
47
|
+
command.execute
|
48
|
+
}.should raise_error SystemExit
|
49
|
+
|
50
|
+
@string_io.string.should match /The target vm #{@vm_info[1]} already exists/
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should try to clone the vm if the source vm exists and the target vm does not' do
|
54
|
+
Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(true)
|
55
|
+
Fission::VM.should_receive(:exists?).with(@vm_info[1]).and_return(false)
|
56
|
+
Fission::VM.should_receive(:clone).with(@vm_info.first, @vm_info[1])
|
57
|
+
command = Fission::Command::Clone.new @vm_info
|
58
|
+
command.execute
|
59
|
+
|
60
|
+
@string_io.string.should match /Clone complete/
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'with --start' do
|
64
|
+
it 'should try to clone the vm and start it' do
|
65
|
+
@vm_mock = mock('vm_mock')
|
66
|
+
Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(true)
|
67
|
+
Fission::VM.should_receive(:exists?).with(@vm_info[1]).and_return(false)
|
68
|
+
Fission::VM.should_receive(:clone).with(@vm_info.first, @vm_info[1])
|
69
|
+
|
70
|
+
@vm_mock.should_receive(:start)
|
71
|
+
Fission::VM.should_receive(:new).with(@vm_info[1]).and_return(@vm_mock)
|
72
|
+
|
73
|
+
command = Fission::Command::Clone.new @vm_info << '--start'
|
74
|
+
command.execute
|
75
|
+
|
76
|
+
@string_io.string.should match /Clone complete/
|
77
|
+
@string_io.string.should match /Starting '#{@vm_info[1]}'/
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'help' do
|
84
|
+
it 'should output info for this command' do
|
85
|
+
output = Fission::Command::Clone.help
|
86
|
+
|
87
|
+
output.should match /clone source_vm target_vm/
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('../../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe Fission::Command do
|
4
|
+
|
5
|
+
describe 'new' do
|
6
|
+
it 'should set options variable as an open struct' do
|
7
|
+
@command = Fission::Command.new
|
8
|
+
@command.options.should be_kind_of OpenStruct
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should set the args variable' do
|
12
|
+
@command = Fission::Command.new ['foo', 'bar']
|
13
|
+
@command.args.should == ['foo', 'bar']
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'help' do
|
18
|
+
it 'should call option_parser on a new instance' do
|
19
|
+
@new_instance_mock = mock('new_instance')
|
20
|
+
@new_instance_mock.should_receive(:option_parser).and_return('foo')
|
21
|
+
Fission::Command.should_receive(:new).and_return(@new_instance_mock)
|
22
|
+
Fission::Command.help.should == 'foo'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path('../../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe Fission::Config do
|
4
|
+
describe "init" do
|
5
|
+
it "should use the fusion default dir for vm_dir" do
|
6
|
+
FakeFS do
|
7
|
+
@config = Fission::Config.new
|
8
|
+
@config.attributes['vm_dir'].should == File.expand_path('~/Documents/Virtual Machines.localized/')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should use the fusion default for vmrun_bin' do
|
13
|
+
FakeFS do
|
14
|
+
@config = Fission::Config.new
|
15
|
+
@config.attributes['vmrun_bin'].should == '/Library/Application Support/VMware Fusion/vmrun'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should use the user specified dir in ~/.fissionrc" do
|
20
|
+
FakeFS do
|
21
|
+
File.open('~/.fissionrc', 'w') { |f| f.puts YAML.dump({ 'vm_dir' => '/var/tmp/foo' })}
|
22
|
+
|
23
|
+
@config = Fission::Config.new
|
24
|
+
@config.attributes['vm_dir'].should == '/var/tmp/foo'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('../../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe Fission::UI do
|
4
|
+
describe 'output' do
|
5
|
+
it 'should show the desired text' do
|
6
|
+
output = capturing_output do
|
7
|
+
Fission::UI.new.output "foo bar\nbaz blah"
|
8
|
+
end
|
9
|
+
|
10
|
+
output.should == "foo bar\nbaz blah\n"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'output_and_exit' do
|
15
|
+
it 'should show the desired text and exit with the desired exit code' do
|
16
|
+
Fission::UI.any_instance.should_receive(:exit).and_return(1)
|
17
|
+
|
18
|
+
output = capturing_output do
|
19
|
+
Fission::UI.new.output_and_exit "foo bar\nbaz blah", 1
|
20
|
+
end
|
21
|
+
|
22
|
+
output.should == "foo bar\nbaz blah\n"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require File.expand_path('../../spec_helper.rb', __FILE__)
|
2
|
+
|
3
|
+
describe Fission::VM do
|
4
|
+
before :each do
|
5
|
+
@string_io = StringIO.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'new' do
|
9
|
+
it 'should set the vm name' do
|
10
|
+
Fission::VM.new('foo').name.should == 'foo'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'start' do
|
15
|
+
it 'should output that it was successful' do
|
16
|
+
Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
|
17
|
+
@vm = Fission::VM.new('foo')
|
18
|
+
@vm.should_receive(:`).with("#{Fission.config.attributes['vmrun_bin'].gsub ' ', '\ '} -T fusion start #{(File.join(Fission::VM.path('foo'), 'foo.vmx')).gsub ' ', '\ '} gui 2>&1").and_return("it's all good")
|
19
|
+
@vm.start
|
20
|
+
|
21
|
+
@string_io.string.should match /VM started/
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'it should output that it was unsuccessful' do
|
25
|
+
$?.should_receive(:exitstatus).and_return(1)
|
26
|
+
Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
|
27
|
+
@vm = Fission::VM.new('foo')
|
28
|
+
@vm.should_receive(:`).with("#{Fission.config.attributes['vmrun_bin'].gsub ' ', '\ '} -T fusion start #{(File.join(Fission::VM.path('foo'), 'foo.vmx')).gsub ' ', '\ '} gui 2>&1").and_return("it blew up")
|
29
|
+
@vm.start
|
30
|
+
|
31
|
+
@string_io.string.should match /There was a problem starting the VM.+it blew up.+/m
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'conf_file' do
|
36
|
+
it 'should return the path to the conf file' do
|
37
|
+
Fission::VM.new('foo').conf_file.should == File.join(Fission.config.attributes['vm_dir'], 'foo.vmwarevm', 'foo.vmx')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "self.path" do
|
42
|
+
it "should return the path of the vm" do
|
43
|
+
vm_path = File.join(Fission.config.attributes['vm_dir'], 'foo.vmwarevm').gsub '\\', ''
|
44
|
+
Fission::VM.path('foo').should == vm_path
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "self.exists?" do
|
49
|
+
it "should return true if the vm exists" do
|
50
|
+
FakeFS do
|
51
|
+
FileUtils.mkdir_p(Fission::VM.path('foo'))
|
52
|
+
Fission::VM.exists?('foo').should == true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should return false if the vm does not exist' do
|
57
|
+
FakeFS do
|
58
|
+
FileUtils.rm_r(Fission::VM.path('foo'))
|
59
|
+
Fission::VM.exists?('foo').should == false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
describe "self.clone" do
|
66
|
+
before :each do
|
67
|
+
Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should clone the vm to the target' do
|
71
|
+
source_vm = 'foo'
|
72
|
+
target_vm = 'bar'
|
73
|
+
vm_files = [ '.vmx',
|
74
|
+
'.vmxf',
|
75
|
+
'.vmdk',
|
76
|
+
'-s001.vmdk',
|
77
|
+
'-s002.vmdk',
|
78
|
+
'.vmsd' ]
|
79
|
+
|
80
|
+
FakeFS do
|
81
|
+
FileUtils.mkdir_p Fission::VM.path('foo')
|
82
|
+
|
83
|
+
vm_files.each do |file|
|
84
|
+
FileUtils.touch File.join(Fission::VM.path('foo'), "#{source_vm}#{file}")
|
85
|
+
end
|
86
|
+
|
87
|
+
File.open(File.join(Fission::VM.path('foo'), 'foo.vmx'), 'w') { |f| f.write 'foo.vmdk'}
|
88
|
+
|
89
|
+
Fission::VM.clone source_vm, target_vm
|
90
|
+
|
91
|
+
File.directory?(Fission::VM.path('bar')).should == true
|
92
|
+
|
93
|
+
vm_files.each do |file|
|
94
|
+
File.file?(File.join(Fission::VM.path('bar'), "#{target_vm}#{file}")).should == true
|
95
|
+
end
|
96
|
+
|
97
|
+
conf_file = File.read File.join(Fission::VM.path('bar'), 'bar.vmx')
|
98
|
+
conf_file.should == 'bar.vmdk'
|
99
|
+
end
|
100
|
+
|
101
|
+
@string_io.string.should match /Cloning #{source_vm} to #{target_vm}/
|
102
|
+
@string_io.string.should match /Configuring #{target_vm}/
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fission do
|
4
|
+
describe "config" do
|
5
|
+
it "should load a config object" do
|
6
|
+
Fission.config.should be_a Fission::Config
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "ui" do
|
11
|
+
it "should load a ui object" do
|
12
|
+
Fission.ui.should be_a Fission::UI
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'fission'
|
3
|
+
require 'fakefs/safe'
|
4
|
+
|
5
|
+
# Helper to capture our stdout
|
6
|
+
# Example
|
7
|
+
# output = capturing_output do
|
8
|
+
# lambda {
|
9
|
+
# Erector.new(["--version"])
|
10
|
+
# }.should raise_error(SystemExit)
|
11
|
+
# end
|
12
|
+
# output.should == Erector::VERSION + "\n"
|
13
|
+
def capturing_output
|
14
|
+
output = StringIO.new
|
15
|
+
$stdout = output
|
16
|
+
yield
|
17
|
+
output.string
|
18
|
+
ensure
|
19
|
+
$stdout = STDOUT
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fission
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tommy Bishop
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-18 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.6.0
|
24
|
+
type: :development
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: fakefs
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.3.2
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
description: A simple utility to create VMware Fusion VM clones
|
38
|
+
email:
|
39
|
+
- bishop.thomas@gmail.com
|
40
|
+
executables:
|
41
|
+
- fission
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
files:
|
47
|
+
- .gitignore
|
48
|
+
- .rspec
|
49
|
+
- .rvmrc
|
50
|
+
- CHANGELOG.md
|
51
|
+
- Gemfile
|
52
|
+
- LICENSE
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- bin/fission
|
56
|
+
- fission.gemspec
|
57
|
+
- lib/fission.rb
|
58
|
+
- lib/fission/cli.rb
|
59
|
+
- lib/fission/command.rb
|
60
|
+
- lib/fission/command/clone.rb
|
61
|
+
- lib/fission/config.rb
|
62
|
+
- lib/fission/core_ext/class.rb
|
63
|
+
- lib/fission/core_ext/object.rb
|
64
|
+
- lib/fission/ui.rb
|
65
|
+
- lib/fission/version.rb
|
66
|
+
- lib/fission/vm.rb
|
67
|
+
- spec/fission/cli_spec.rb
|
68
|
+
- spec/fission/command/clone_spec.rb
|
69
|
+
- spec/fission/command_spec.rb
|
70
|
+
- spec/fission/config_spec.rb
|
71
|
+
- spec/fission/ui_spec.rb
|
72
|
+
- spec/fission/vm_spec.rb
|
73
|
+
- spec/fission_spec.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
homepage: https://github.com/thbishop/fission
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project: fission
|
98
|
+
rubygems_version: 1.8.2
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Tool to clone VMware fusion VMs
|
102
|
+
test_files:
|
103
|
+
- spec/fission/cli_spec.rb
|
104
|
+
- spec/fission/command/clone_spec.rb
|
105
|
+
- spec/fission/command_spec.rb
|
106
|
+
- spec/fission/config_spec.rb
|
107
|
+
- spec/fission/ui_spec.rb
|
108
|
+
- spec/fission/vm_spec.rb
|
109
|
+
- spec/fission_spec.rb
|
110
|
+
- spec/spec_helper.rb
|