cloudstack_cloner 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +36 -0
- data/Rakefile +1 -0
- data/bin/cloudstack_cloner +5 -0
- data/cloudstack_cloner.gemspec +26 -0
- data/lib/cloudstack_cloner/cli.rb +48 -0
- data/lib/cloudstack_cloner/helper.rb +135 -0
- data/lib/cloudstack_cloner/option_resolver.rb +185 -0
- data/lib/cloudstack_cloner/version.rb +3 -0
- data/lib/cloudstack_cloner.rb +5 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 60dd8f4ce7db03e2c028187255f2e92868e67de6
|
4
|
+
data.tar.gz: e2dbeb3fcfdd1016bebca529754f0f442cf3a9c8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 82a48a9715c7ca16483a81cd81afd713165c0f8c13621e811c57f10a28a78cede4d20faae6ef3b50f734962b93fb31962712106a3955becaacd50cb7386feffc
|
7
|
+
data.tar.gz: 9ddcc880e8c8edc4503ab70691f289c6e5a5ceaaa880460c146c4d5a6a1b84d3a9e34f455bbfc938d4154a1f8ad4850cac8de56193075799a8585b666f3c13a7
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 niwo
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# CloudstackCloner
|
2
|
+
|
3
|
+
Automated CloudStack VM cloning and copying and attaching of existing data disks.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'cloudstack_cloner'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install cloudstack_cloner
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
|
24
|
+
### Example
|
25
|
+
|
26
|
+
```bash
|
27
|
+
cloudstack_cloner clone --virtual_machine test01 --clone-name test-clone --project Playground --data-volumes test -e prod --offering 2cpu_2gb
|
28
|
+
```
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
1. Fork it ( https://github.com/[my-github-username]/cloudstack_cloner/fork )
|
33
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
34
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
35
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
36
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cloudstack_cloner/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cloudstack_cloner"
|
8
|
+
spec.version = CloudstackCloner::VERSION
|
9
|
+
spec.authors = ["niwo"]
|
10
|
+
spec.email = ["nik.wolfgramm@gmail.com"]
|
11
|
+
spec.summary = %q{Automated CloudStack VM cloning}
|
12
|
+
spec.description = %q{Automated CloudStack VM cloning}
|
13
|
+
spec.homepage = "https://github.com/swisstxt/cloudstack_cloner"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
|
24
|
+
spec.add_dependency('thor', '~> 0.19.1')
|
25
|
+
spec.add_dependency('cloudstack_client', '~> 1.0.4')
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module CloudstackCloner
|
4
|
+
class Cli < Thor
|
5
|
+
include Thor::Actions
|
6
|
+
include CloudstackCloner::OptionResolver
|
7
|
+
include CloudstackCloner::Helper
|
8
|
+
|
9
|
+
package_name "cloudstack_cloner"
|
10
|
+
|
11
|
+
class_option :config_file,
|
12
|
+
default: File.join(Dir.home, '.cloudstack-cli.yml'),
|
13
|
+
aliases: '-c',
|
14
|
+
desc: 'Location of your cloudstack-cli configuration file'
|
15
|
+
|
16
|
+
class_option :env,
|
17
|
+
aliases: '-e',
|
18
|
+
desc: 'Environment to use'
|
19
|
+
|
20
|
+
desc "version", "Print cloudstack-cloner version number"
|
21
|
+
def version
|
22
|
+
say "cloudstack-cloner version #{CloudstackCloner::VERSION}"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "clone", "Clone a virtual machine"
|
26
|
+
option :virtual_machine,
|
27
|
+
desc: "name of the vm to clone",
|
28
|
+
required: true
|
29
|
+
option :project,
|
30
|
+
desc: "name of project"
|
31
|
+
option :clone_name,
|
32
|
+
desc: "name of the new vm",
|
33
|
+
required: true
|
34
|
+
option :offering,
|
35
|
+
desc: "name of the compute offering for the new vm"
|
36
|
+
option :data_volumes,
|
37
|
+
desc: "names of data volumes to attach",
|
38
|
+
type: :array
|
39
|
+
def clone
|
40
|
+
opts = options.dup
|
41
|
+
opts = resolve_project(opts)
|
42
|
+
opts = resolve_virtual_machine(opts)
|
43
|
+
opts = resolve_compute_offering(opts)
|
44
|
+
clone_vm(opts)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "cloudstack_cloner/option_resolver"
|
3
|
+
|
4
|
+
module CloudstackCloner
|
5
|
+
module Helper
|
6
|
+
|
7
|
+
def clone_vm(opts)
|
8
|
+
vm = client.list_virtual_machines(
|
9
|
+
opts.merge(listall: true, name: opts[:virtual_machine])
|
10
|
+
).first
|
11
|
+
|
12
|
+
if vm["state"] == "Running"
|
13
|
+
say "Failure: ", :red
|
14
|
+
say "VM #{vm["name"]} has to be stopped in order to create a template."
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
|
18
|
+
data_volumes = opts[:data_volumes].map do |disk|
|
19
|
+
unless volume = client.list_volumes(
|
20
|
+
name: disk,
|
21
|
+
listall: true,
|
22
|
+
type: "DATADISK",
|
23
|
+
project_id: opts[:project_id]
|
24
|
+
).first
|
25
|
+
say "Failure: ", :red
|
26
|
+
say "Volume #{disk} not found."
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
volume
|
30
|
+
end
|
31
|
+
|
32
|
+
volume = client.list_volumes(opts.merge(listall: true, type: "root")).first
|
33
|
+
|
34
|
+
templ_name = "#{vm["name"]}-#{Time.now.strftime("%F")}"
|
35
|
+
|
36
|
+
if template = client.list_templates(
|
37
|
+
name: templ_name,
|
38
|
+
listall: true,
|
39
|
+
projectid: opts[:project_id],
|
40
|
+
templatefilter: "self"
|
41
|
+
).first
|
42
|
+
say "Template #{templ_name} already exists.", :green
|
43
|
+
else
|
44
|
+
say "Create template from volume #{volume["name"]} ", :yellow
|
45
|
+
template = client.create_template(
|
46
|
+
name: templ_name,
|
47
|
+
displaytext: templ_name,
|
48
|
+
ostypeid: vm["guestosid"],
|
49
|
+
volumeid: volume["id"]
|
50
|
+
)["template"]
|
51
|
+
say " [OK]", :green
|
52
|
+
end
|
53
|
+
|
54
|
+
say "Creating VM from template #{template["name"]} ", :yellow
|
55
|
+
clone = client.deploy_virtual_machine(
|
56
|
+
name: opts[:clone_name],
|
57
|
+
displaytext: opts[:clone_name],
|
58
|
+
templateid: template["id"],
|
59
|
+
serviceofferingid: opts[:service_offering_id] || vm["serviceofferingid"],
|
60
|
+
networkids: vm["networkids"],
|
61
|
+
zoneid: vm["zoneid"],
|
62
|
+
projectid: opts[:project_id]
|
63
|
+
)["virtualmachine"]
|
64
|
+
say " [OK]", :green
|
65
|
+
|
66
|
+
|
67
|
+
data_volumes.each do |volume|
|
68
|
+
say "Creating snapshot for volume #{volume["name"]} ", :yellow
|
69
|
+
snapshot = client.create_snapshot(volumeid: volume["id"])["snapshot"]
|
70
|
+
say " [OK]", :green
|
71
|
+
|
72
|
+
say "Creating clone of volume #{volume["name"]} ", :yellow
|
73
|
+
volume = client.create_volume(
|
74
|
+
name: "#{volume["name"]}_#{opts[:clone_name]}",
|
75
|
+
snapshot_id: snapshot["id"],
|
76
|
+
projectid: opts[:project_id]
|
77
|
+
)["volume"]
|
78
|
+
say " [OK]", :green
|
79
|
+
|
80
|
+
say "Attach clone of volume #{volume["name"]} to VM #{clone["name"]} ", :yellow
|
81
|
+
client.attach_volume(
|
82
|
+
id: volume["id"],
|
83
|
+
virtualmachineid: clone["id"]
|
84
|
+
)
|
85
|
+
say " [OK]", :green
|
86
|
+
|
87
|
+
say "Delete snapshot of volume #{volume["name"]} ", :yellow
|
88
|
+
volume = client.delete_snapshot(id: snapshot["id"])
|
89
|
+
say " [OK]", :green
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def client
|
97
|
+
@config ||= load_configuration(options[:config_file], options[:env]).first
|
98
|
+
@client ||= CloudstackClient::Client.new(
|
99
|
+
@config[:url],
|
100
|
+
@config[:api_key],
|
101
|
+
@config[:secret_key],
|
102
|
+
options
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def load_configuration(config_file, env)
|
107
|
+
unless File.exists?(config_file)
|
108
|
+
puts "Configuration file #{config_file} not found."
|
109
|
+
puts "Please run 'cloudstack-cli environment add' to create one."
|
110
|
+
exit 1
|
111
|
+
end
|
112
|
+
|
113
|
+
begin
|
114
|
+
config = YAML::load(IO.read(config_file))
|
115
|
+
rescue
|
116
|
+
puts "Can't load configuration from file #{config_file}."
|
117
|
+
exit 1
|
118
|
+
end
|
119
|
+
|
120
|
+
if env ||= config[:default]
|
121
|
+
unless config = config[env]
|
122
|
+
puts "Can't find environment #{env}."
|
123
|
+
exit 1
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
unless config.key?(:url) && config.key?(:api_key) && config.key?(:secret_key)
|
128
|
+
puts "The environment #{env || '\'-\''} contains no valid data."
|
129
|
+
exit 1
|
130
|
+
end
|
131
|
+
return config, env
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
module CloudstackCloner
|
2
|
+
module OptionResolver
|
3
|
+
|
4
|
+
def vm_options_to_params(options = options)
|
5
|
+
resolve_zone(options)
|
6
|
+
resolve_project(options)
|
7
|
+
resolve_compute_offering(options)
|
8
|
+
resolve_template(options)
|
9
|
+
resolve_disk_offering(options)
|
10
|
+
resolve_iso(options)
|
11
|
+
unless options[:template_id]
|
12
|
+
say "Error: Template or ISO is required.", :red
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
resolve_networks(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def resolve_zone(options = options)
|
19
|
+
if options[:zone]
|
20
|
+
zones = client.list_zones
|
21
|
+
zone = zones.find {|z| z['name'] == options[:zone] }
|
22
|
+
if !zone
|
23
|
+
msg = options[:zone] ? "Zone '#{options[:zone]}' is invalid." : "No zone found."
|
24
|
+
say "Error: #{msg}", :red
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
options[:zone_id] = zone['id']
|
28
|
+
end
|
29
|
+
options
|
30
|
+
end
|
31
|
+
|
32
|
+
def resolve_domain(options = options)
|
33
|
+
if options[:domain]
|
34
|
+
if domain = client.list_domains(name: options[:domain]).first
|
35
|
+
options[:domain_id] = domain['id']
|
36
|
+
else
|
37
|
+
say "Error: Domain #{options[:domain]} not found.", :red
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
options
|
42
|
+
end
|
43
|
+
|
44
|
+
def resolve_project(options = options)
|
45
|
+
if options[:project]
|
46
|
+
if %w(ALL -1).include? options[:project]
|
47
|
+
options[:project_id] = "-1"
|
48
|
+
elsif project = client.list_projects(name: options[:project], listall: true).first
|
49
|
+
options[:project_id] = project['id']
|
50
|
+
else
|
51
|
+
say "Error: Project #{options[:project]} not found.", :red
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
options
|
56
|
+
end
|
57
|
+
|
58
|
+
def resolve_account(options = options)
|
59
|
+
if options[:account]
|
60
|
+
if account = client.list_accounts(name: options[:account], listall: true).first
|
61
|
+
options[:account_id] = account['id']
|
62
|
+
options[:domain_id] = account['domainid']
|
63
|
+
else
|
64
|
+
say "Error: Account #{options[:account]} not found.", :red
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
options
|
69
|
+
end
|
70
|
+
|
71
|
+
def resolve_networks(options = options)
|
72
|
+
networks = []
|
73
|
+
available_networks = network = client.list_networks(
|
74
|
+
zone_id: options[:zone_id],
|
75
|
+
project_id: options[:project_id]
|
76
|
+
)
|
77
|
+
if options[:networks]
|
78
|
+
options[:networks].each do |name|
|
79
|
+
unless network = available_networks.find { |n| n['name'] == name }
|
80
|
+
say "Error: Network '#{name}' not found.", :red
|
81
|
+
exit 1
|
82
|
+
end
|
83
|
+
networks << network['id'] rescue nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
networks.compact!
|
87
|
+
if networks.empty?
|
88
|
+
#unless default_network = client.list_networks(project_id: options[:project_id]).find {
|
89
|
+
# |n| n['isdefault'] == true }
|
90
|
+
unless default_network = client.list_networks(project_id: options[:project_id]).first
|
91
|
+
say "Error: No default network found.", :red
|
92
|
+
exit 1
|
93
|
+
end
|
94
|
+
networks << available_networks.first['id'] rescue nil
|
95
|
+
end
|
96
|
+
options[:network_ids] = networks.join(',')
|
97
|
+
options
|
98
|
+
end
|
99
|
+
|
100
|
+
def resolve_iso(options = options)
|
101
|
+
if options[:iso]
|
102
|
+
unless iso = client.list_isos(
|
103
|
+
name: options[:iso],
|
104
|
+
project_id: options[:project_id]
|
105
|
+
).first
|
106
|
+
say "Error: Iso '#{options[:iso]}' is invalid.", :red
|
107
|
+
exit 1
|
108
|
+
end
|
109
|
+
unless options[:diskoffering_id]
|
110
|
+
say "Error: a disk offering is required when using iso.", :red
|
111
|
+
exit 1
|
112
|
+
end
|
113
|
+
options[:template_id] = iso['id']
|
114
|
+
options['hypervisor'] = (options[:hypervisor] || 'vmware')
|
115
|
+
end
|
116
|
+
options
|
117
|
+
end
|
118
|
+
|
119
|
+
def resolve_template(options = options)
|
120
|
+
if options[:template]
|
121
|
+
if template = client.list_templates(
|
122
|
+
name: options[:template],
|
123
|
+
template_filter: "executable",
|
124
|
+
project_id: options[:project_id]
|
125
|
+
).first
|
126
|
+
options[:template_id] = template['id']
|
127
|
+
else
|
128
|
+
say "Error: Template #{options[:template]} not found.", :red
|
129
|
+
exit 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
options
|
133
|
+
end
|
134
|
+
|
135
|
+
def resolve_compute_offering(options = options)
|
136
|
+
if options[:offering]
|
137
|
+
if offering = client.list_service_offerings(name: options[:offering]).first
|
138
|
+
options[:service_offering_id] = offering['id']
|
139
|
+
else
|
140
|
+
say "Error: Offering #{options[:offering]} not found.", :red
|
141
|
+
exit 1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
options
|
145
|
+
end
|
146
|
+
|
147
|
+
def resolve_disk_offering(options = options)
|
148
|
+
if options[:disk_offering]
|
149
|
+
unless disk_offering = client.list_disk_offerings(name: options[:disk_offering]).first
|
150
|
+
say "Error: Disk offering '#{options[:disk_offering]}' not found.", :red
|
151
|
+
exit 1
|
152
|
+
end
|
153
|
+
options[:disk_offering_id] = disk_offering['id']
|
154
|
+
end
|
155
|
+
options
|
156
|
+
end
|
157
|
+
|
158
|
+
def resolve_virtual_machine(options = options.dup)
|
159
|
+
if options[:virtual_machine]
|
160
|
+
args = { name: options[:virtual_machine], listall: true }
|
161
|
+
args[:project_id] = options[:project_id]
|
162
|
+
unless vm = client.list_virtual_machines(args).first
|
163
|
+
say "Error: VM '#{options[:virtual_machine]}' not found.", :red
|
164
|
+
exit 1
|
165
|
+
end
|
166
|
+
options[:virtual_machine_id] = vm['id']
|
167
|
+
end
|
168
|
+
options
|
169
|
+
end
|
170
|
+
|
171
|
+
def resolve_snapshot(options = options)
|
172
|
+
if options[:snapshot]
|
173
|
+
args = { name: options[:snapshot], listall: true }
|
174
|
+
args[:project_id] = options[:project_id]
|
175
|
+
unless snapshot = client.list_snapshots(args).first
|
176
|
+
say "Error: Snapshot '#{options[:snapshot]}' not found.", :red
|
177
|
+
exit 1
|
178
|
+
end
|
179
|
+
options[:snapshot_id] = snapshot['id']
|
180
|
+
end
|
181
|
+
options
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudstack_cloner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- niwo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.19.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.19.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: cloudstack_client
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.4
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.4
|
69
|
+
description: Automated CloudStack VM cloning
|
70
|
+
email:
|
71
|
+
- nik.wolfgramm@gmail.com
|
72
|
+
executables:
|
73
|
+
- cloudstack_cloner
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- bin/cloudstack_cloner
|
83
|
+
- cloudstack_cloner.gemspec
|
84
|
+
- lib/cloudstack_cloner.rb
|
85
|
+
- lib/cloudstack_cloner/cli.rb
|
86
|
+
- lib/cloudstack_cloner/helper.rb
|
87
|
+
- lib/cloudstack_cloner/option_resolver.rb
|
88
|
+
- lib/cloudstack_cloner/version.rb
|
89
|
+
homepage: https://github.com/swisstxt/cloudstack_cloner
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.2.2
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: Automated CloudStack VM cloning
|
113
|
+
test_files: []
|