cloudstack_cloner 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60dd8f4ce7db03e2c028187255f2e92868e67de6
4
- data.tar.gz: e2dbeb3fcfdd1016bebca529754f0f442cf3a9c8
3
+ metadata.gz: 416bf2f75c671c268cfd99cae1b6c2b7dae9ae2a
4
+ data.tar.gz: a4a4f82678ba62f2dea7a6ae1afc9e784825f27e
5
5
  SHA512:
6
- metadata.gz: 82a48a9715c7ca16483a81cd81afd713165c0f8c13621e811c57f10a28a78cede4d20faae6ef3b50f734962b93fb31962712106a3955becaacd50cb7386feffc
7
- data.tar.gz: 9ddcc880e8c8edc4503ab70691f289c6e5a5ceaaa880460c146c4d5a6a1b84d3a9e34f455bbfc938d4154a1f8ad4850cac8de56193075799a8585b666f3c13a7
6
+ metadata.gz: bbd4513764adb7d27d2303950818fd8aa26d44b47b9ca35ae5a02dd3da44d7736fd85924ad84520a9c9ab8fa7e20f1e5ca55949aa665bd1eb58fcebe4705c785
7
+ data.tar.gz: 647842bf094b20eec1f197ea4e4ae660b0be85439d3b244410524bbcfc629c541ed6d6d424c16bc013ead2a0bc43ebb85b918654a16cbe4a1eff38f6e5a5b47d
data/README.md CHANGED
@@ -1,30 +1,32 @@
1
1
  # CloudstackCloner
2
2
 
3
- Automated CloudStack VM cloning and copying and attaching of existing data disks.
3
+ [![Gem Version](https://badge.fury.io/rb/cloudstack_cloner.png)](http://badge.fury.io/rb/cloudstack_cloner)
4
+
5
+ Automated CloudStack VM cloning and copying/attaching of existing data disks.
6
+ CloudstackCloner uses [cloudstack_client](https://github.com/niwo/cloudstack_client) for CloudStack API communication.
4
7
 
5
8
  ## Installation
6
9
 
7
- Add this line to your application's Gemfile:
10
+ Install the Gem:
8
11
 
9
- ```ruby
10
- gem 'cloudstack_cloner'
12
+ ```bash
13
+ $ gem install cloudstack_cloner
11
14
  ```
12
15
 
13
- And then execute:
14
-
15
- $ bundle
16
-
17
- Or install it yourself as:
16
+ ## Configuration
18
17
 
19
- $ gem install cloudstack_cloner
18
+ A [cloudstack-cli](https://github.com/niwo/cloudstack-cli) style configuration file is used for setting up URL, keys and secrets of your CloudStack API connection.
20
19
 
21
20
  ## Usage
22
21
 
22
+ ### Preconditions
23
+ * The machine to be cloned has to be in "Stopped" state.
24
+ * The data disks to be copied have to be in state "Ready".
23
25
 
24
26
  ### Example
25
27
 
26
28
  ```bash
27
- cloudstack_cloner clone --virtual_machine test01 --clone-name test-clone --project Playground --data-volumes test -e prod --offering 2cpu_2gb
29
+ $ cloudstack_cloner clone --virtual_machine test01 --clone-name test-clone --project Playground --data-volumes test-volume --offering 2cpu_2gb
28
30
  ```
29
31
 
30
32
  ## Contributing
@@ -24,21 +24,20 @@ module CloudstackCloner
24
24
 
25
25
  desc "clone", "Clone a virtual machine"
26
26
  option :virtual_machine,
27
- desc: "name of the vm to clone",
27
+ desc: "Name of the vm to clone",
28
28
  required: true
29
29
  option :project,
30
- desc: "name of project"
30
+ desc: "Name of project"
31
31
  option :clone_name,
32
- desc: "name of the new vm",
32
+ desc: "Name of the new vm",
33
33
  required: true
34
34
  option :offering,
35
- desc: "name of the compute offering for the new vm"
35
+ desc: "Name of the compute offering for the new vm"
36
36
  option :data_volumes,
37
- desc: "names of data volumes to attach",
37
+ desc: "Names of data volumes to attach, separated by space",
38
38
  type: :array
39
39
  def clone
40
- opts = options.dup
41
- opts = resolve_project(opts)
40
+ opts = resolve_project(options.dup)
42
41
  opts = resolve_virtual_machine(opts)
43
42
  opts = resolve_compute_offering(opts)
44
43
  clone_vm(opts)
@@ -9,8 +9,16 @@ module CloudstackCloner
9
9
  opts.merge(listall: true, name: opts[:virtual_machine])
10
10
  ).first
11
11
 
12
+ if client.list_virtual_machines(
13
+ opts.merge(listall: true, name: opts[:clone_name])
14
+ ).size > 0
15
+ say_log "Failure: ", :red
16
+ say "VM with name #{opts[:clone_name]} already exists."
17
+ exit 1
18
+ end
19
+
12
20
  if vm["state"] == "Running"
13
- say "Failure: ", :red
21
+ say_log "Failure: ", :red
14
22
  say "VM #{vm["name"]} has to be stopped in order to create a template."
15
23
  exit 1
16
24
  end
@@ -22,7 +30,7 @@ module CloudstackCloner
22
30
  type: "DATADISK",
23
31
  project_id: opts[:project_id]
24
32
  ).first
25
- say "Failure: ", :red
33
+ say_log "Failure: ", :red
26
34
  say "Volume #{disk} not found."
27
35
  exit 1
28
36
  end
@@ -30,7 +38,6 @@ module CloudstackCloner
30
38
  end
31
39
 
32
40
  volume = client.list_volumes(opts.merge(listall: true, type: "root")).first
33
-
34
41
  templ_name = "#{vm["name"]}-#{Time.now.strftime("%F")}"
35
42
 
36
43
  if template = client.list_templates(
@@ -39,9 +46,9 @@ module CloudstackCloner
39
46
  projectid: opts[:project_id],
40
47
  templatefilter: "self"
41
48
  ).first
42
- say "Template #{templ_name} already exists.", :green
49
+ say_log "Template #{templ_name} already exists.", :green
43
50
  else
44
- say "Create template from volume #{volume["name"]} ", :yellow
51
+ say_log "Create template from volume #{volume["name"]} ", :yellow
45
52
  template = client.create_template(
46
53
  name: templ_name,
47
54
  displaytext: templ_name,
@@ -51,7 +58,7 @@ module CloudstackCloner
51
58
  say " [OK]", :green
52
59
  end
53
60
 
54
- say "Creating VM from template #{template["name"]} ", :yellow
61
+ say_log "Creating VM from template #{template["name"]} ", :yellow
55
62
  clone = client.deploy_virtual_machine(
56
63
  name: opts[:clone_name],
57
64
  displaytext: opts[:clone_name],
@@ -65,11 +72,11 @@ module CloudstackCloner
65
72
 
66
73
 
67
74
  data_volumes.each do |volume|
68
- say "Creating snapshot for volume #{volume["name"]} ", :yellow
75
+ say_log "Creating snapshot for volume #{volume["name"]} ", :yellow
69
76
  snapshot = client.create_snapshot(volumeid: volume["id"])["snapshot"]
70
77
  say " [OK]", :green
71
78
 
72
- say "Creating clone of volume #{volume["name"]} ", :yellow
79
+ say_log "Creating clone of volume #{volume["name"]} ", :yellow
73
80
  volume = client.create_volume(
74
81
  name: "#{volume["name"]}_#{opts[:clone_name]}",
75
82
  snapshot_id: snapshot["id"],
@@ -77,14 +84,14 @@ module CloudstackCloner
77
84
  )["volume"]
78
85
  say " [OK]", :green
79
86
 
80
- say "Attach clone of volume #{volume["name"]} to VM #{clone["name"]} ", :yellow
87
+ say_log "Attach clone of volume #{volume["name"]} to VM #{clone["name"]} ", :yellow
81
88
  client.attach_volume(
82
89
  id: volume["id"],
83
90
  virtualmachineid: clone["id"]
84
91
  )
85
92
  say " [OK]", :green
86
93
 
87
- say "Delete snapshot of volume #{volume["name"]} ", :yellow
94
+ say_log "Delete snapshot of volume #{volume["name"]} ", :yellow
88
95
  volume = client.delete_snapshot(id: snapshot["id"])
89
96
  say " [OK]", :green
90
97
  end
@@ -93,6 +100,11 @@ module CloudstackCloner
93
100
 
94
101
  private
95
102
 
103
+ def say_log(message, color = nil)
104
+ say "[#{Time.new.strftime("%F-%X")}] - "
105
+ say "#{message}", color
106
+ end
107
+
96
108
  def client
97
109
  @config ||= load_configuration(options[:config_file], options[:env]).first
98
110
  @client ||= CloudstackClient::Client.new(
@@ -1,81 +1,67 @@
1
1
  module CloudstackCloner
2
2
  module OptionResolver
3
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]
4
+ def resolve_zone(opts)
5
+ if opts[:zone]
20
6
  zones = client.list_zones
21
- zone = zones.find {|z| z['name'] == options[:zone] }
7
+ zone = zones.find {|z| z['name'] == opts[:zone] }
22
8
  if !zone
23
- msg = options[:zone] ? "Zone '#{options[:zone]}' is invalid." : "No zone found."
9
+ msg = opts[:zone] ? "Zone '#{opts[:zone]}' is invalid." : "No zone found."
24
10
  say "Error: #{msg}", :red
25
11
  exit 1
26
12
  end
27
- options[:zone_id] = zone['id']
13
+ opts[:zone_id] = zone['id']
28
14
  end
29
- options
15
+ opts
30
16
  end
31
17
 
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']
18
+ def resolve_domain(opts)
19
+ if opts[:domain]
20
+ if domain = client.list_domains(name: opts[:domain]).first
21
+ opts[:domain_id] = domain['id']
36
22
  else
37
- say "Error: Domain #{options[:domain]} not found.", :red
23
+ say "Error: Domain #{opts[:domain]} not found.", :red
38
24
  exit 1
39
25
  end
40
26
  end
41
- options
27
+ opts
42
28
  end
43
29
 
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']
30
+ def resolve_project(opts)
31
+ if opts[:project]
32
+ if %w(ALL -1).include? opts[:project]
33
+ opts[:project_id] = "-1"
34
+ elsif project = client.list_projects(name: opts[:project], listall: true).first
35
+ opts[:project_id] = project['id']
50
36
  else
51
- say "Error: Project #{options[:project]} not found.", :red
37
+ say "Error: Project #{opts[:project]} not found.", :red
52
38
  exit 1
53
39
  end
54
40
  end
55
- options
41
+ opts
56
42
  end
57
43
 
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']
44
+ def resolve_account(opts)
45
+ if opts[:account]
46
+ if account = client.list_accounts(name: opts[:account], listall: true).first
47
+ opts[:account_id] = account['id']
48
+ opts[:domain_id] = account['domainid']
63
49
  else
64
- say "Error: Account #{options[:account]} not found.", :red
50
+ say "Error: Account #{opts[:account]} not found.", :red
65
51
  exit 1
66
52
  end
67
53
  end
68
- options
54
+ opts
69
55
  end
70
56
 
71
- def resolve_networks(options = options)
57
+ def resolve_networks(opts)
72
58
  networks = []
73
59
  available_networks = network = client.list_networks(
74
- zone_id: options[:zone_id],
75
- project_id: options[:project_id]
60
+ zone_id: opts[:zone_id],
61
+ project_id: opts[:project_id]
76
62
  )
77
- if options[:networks]
78
- options[:networks].each do |name|
63
+ if opts[:networks]
64
+ opts[:networks].each do |name|
79
65
  unless network = available_networks.find { |n| n['name'] == name }
80
66
  say "Error: Network '#{name}' not found.", :red
81
67
  exit 1
@@ -85,100 +71,81 @@ module CloudstackCloner
85
71
  end
86
72
  networks.compact!
87
73
  if networks.empty?
88
- #unless default_network = client.list_networks(project_id: options[:project_id]).find {
74
+ #unless default_network = client.list_networks(project_id: opts[:project_id]).find {
89
75
  # |n| n['isdefault'] == true }
90
- unless default_network = client.list_networks(project_id: options[:project_id]).first
76
+ unless default_network = client.list_networks(project_id: opts[:project_id]).first
91
77
  say "Error: No default network found.", :red
92
78
  exit 1
93
79
  end
94
80
  networks << available_networks.first['id'] rescue nil
95
81
  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
82
+ opts[:network_ids] = networks.join(',')
83
+ opts
117
84
  end
118
85
 
119
- def resolve_template(options = options)
120
- if options[:template]
86
+ def resolve_template(opts)
87
+ if opts[:template]
121
88
  if template = client.list_templates(
122
- name: options[:template],
89
+ name: opts[:template],
123
90
  template_filter: "executable",
124
- project_id: options[:project_id]
91
+ project_id: opts[:project_id]
125
92
  ).first
126
- options[:template_id] = template['id']
93
+ opts[:template_id] = template['id']
127
94
  else
128
- say "Error: Template #{options[:template]} not found.", :red
95
+ say "Error: Template #{opts[:template]} not found.", :red
129
96
  exit 1
130
97
  end
131
98
  end
132
- options
99
+ opts
133
100
  end
134
101
 
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']
102
+ def resolve_compute_offering(opts)
103
+ if opts[:offering]
104
+ if offering = client.list_service_offerings(name: opts[:offering]).first
105
+ opts[:service_offering_id] = offering['id']
139
106
  else
140
- say "Error: Offering #{options[:offering]} not found.", :red
107
+ say "Error: Offering #{opts[:offering]} not found.", :red
141
108
  exit 1
142
109
  end
143
110
  end
144
- options
111
+ opts
145
112
  end
146
113
 
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
114
+ def resolve_disk_offering(opts)
115
+ if opts[:disk_offering]
116
+ unless disk_offering = client.list_disk_offerings(name: opts[:disk_offering]).first
117
+ say "Error: Disk offering '#{opts[:disk_offering]}' not found.", :red
151
118
  exit 1
152
119
  end
153
- options[:disk_offering_id] = disk_offering['id']
120
+ opts[:disk_offering_id] = disk_offering['id']
154
121
  end
155
- options
122
+ opts
156
123
  end
157
124
 
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]
125
+ def resolve_virtual_machine(opts)
126
+ if opts[:virtual_machine]
127
+ args = { name: opts[:virtual_machine], listall: true }
128
+ args[:project_id] = opts[:project_id]
162
129
  unless vm = client.list_virtual_machines(args).first
163
- say "Error: VM '#{options[:virtual_machine]}' not found.", :red
130
+ say "Error: VM '#{opts[:virtual_machine]}' not found.", :red
164
131
  exit 1
165
132
  end
166
- options[:virtual_machine_id] = vm['id']
133
+ opts[:virtual_machine_id] = vm['id']
167
134
  end
168
- options
135
+ opts
169
136
  end
170
137
 
171
- def resolve_snapshot(options = options)
172
- if options[:snapshot]
173
- args = { name: options[:snapshot], listall: true }
174
- args[:project_id] = options[:project_id]
138
+ def resolve_snapshot(opts)
139
+ if opts[:snapshot]
140
+ args = { name: opts[:snapshot], listall: true }
141
+ args[:project_id] = opts[:project_id]
175
142
  unless snapshot = client.list_snapshots(args).first
176
- say "Error: Snapshot '#{options[:snapshot]}' not found.", :red
143
+ say "Error: Snapshot '#{opts[:snapshot]}' not found.", :red
177
144
  exit 1
178
145
  end
179
- options[:snapshot_id] = snapshot['id']
146
+ opts[:snapshot_id] = snapshot['id']
180
147
  end
181
- options
148
+ opts
182
149
  end
183
150
 
184
151
  end
@@ -1,3 +1,3 @@
1
1
  module CloudstackCloner
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudstack_cloner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - niwo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-16 00:00:00.000000000 Z
11
+ date: 2015-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  version: '0'
107
107
  requirements: []
108
108
  rubyforge_project:
109
- rubygems_version: 2.2.2
109
+ rubygems_version: 2.4.5
110
110
  signing_key:
111
111
  specification_version: 4
112
112
  summary: Automated CloudStack VM cloning