knife-xenserver 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 0.1.0 - 2012/04/04
2
+
3
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ ![BVox](http://bvox.net/images/logo-bvox-big.png)
2
+ # knife-xenserver
3
+
4
+ Provision virtual machines with Citrix XenServer and Opscode Chef.
5
+
6
+ ## Upgrading knife-xenserver
7
+
8
+ When upgrading knife-xenserver, it's very important to remove older knife-xenserver versions
9
+
10
+ gem update knife-xenserver
11
+ gem clean knife-xenserver
12
+
13
+ ## Usage
14
+
15
+ knife xenserver --help
16
+
17
+ ## Examples
18
+
19
+ List all the VMs
20
+
21
+ knife xenserver vm list --xenserver-host fooserver \
22
+ --xenserver-username root \
23
+ --xenserver-password secret
24
+
25
+
26
+ List custom templates
27
+
28
+ knife xenserver template list --xenserver-host fooserver \
29
+ --xenserver-username root \
30
+ --xenserver-password secret
31
+
32
+ Include built-in templates too
33
+
34
+ knife xenserver template list --xenserver-host fooserver \
35
+ --xenserver-username root \
36
+ --xenserver-password secret \
37
+ --include-builtin
38
+
39
+ Create a new template from a VHD file (PV by default, use --hvm otherwise)
40
+
41
+ knife xenserver template create --vm-name ubuntu-precise-amd64 \
42
+ --vm-disk ubuntu-precise.vhd \
43
+ --vm-memory 512 \
44
+ --vm-networks 'Integration-VLAN' \
45
+ --storage-repository 'Local storage' \
46
+ --xenserver-password changeme \
47
+ --xenserver-host 10.0.0.2
48
+
49
+
50
+ Create a VM from template ed089e35-fb49-f555-4e20-9b7f3db8df2d and bootstrap it using the 'root' user and password 'secret'. The VM is created without VIFs, inherited VIFs from template are removed by default (use --keep-template-networks to avoid that)
51
+
52
+ knife xenserver vm create --vm-template ed089e35-fb49-f555-4e20-9b7f3db8df2d \
53
+ --vm-name foobar --ssh-user root \
54
+ --ssh-password secret
55
+
56
+ Create a VM from template and add two custom VIFs in networks 'Integration-VLAN' and 'Another-VLAN', with MAC address 11:22:33:44:55:66 for the first VIF
57
+
58
+ knife xenserver vm create --vm-template ed089e35-fb49-f555-4e20-9b7f3db8df2d \
59
+ --vm-name foobar --ssh-user root \
60
+ --ssh-password secret \
61
+ --vm-networks 'Integration-VLAN,Another-VLAN' \
62
+ --mac-addresses 11:22:33:44:55:66
63
+
64
+ List hypervisor networks
65
+
66
+ knife xenserver network list
67
+
68
+ ## Sample .chef/knife.rb config
69
+
70
+ knife[:xenserver_password] = "secret"
71
+ knife[:xenserver_username] = "root"
72
+ knife[:xenserver_host] = "xenserver-real"
73
+
74
+
75
+ # Building the rubygem
76
+
77
+ gem build knife-xenserver.gemspec
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "knife-xenserver/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "knife-xenserver"
7
+ s.version = Knife::XenServer::VERSION
8
+ s.has_rdoc = true
9
+ s.authors = ["Sergio Rubio"]
10
+ s.email = ["rubiojr@frameos.org","rubiojr@frameos.org"]
11
+ s.homepage = "http://github.com/rubiojr/knife-xenserver"
12
+ s.summary = "XenServer Support for Chef's Knife Command"
13
+ s.description = s.summary
14
+ s.extra_rdoc_files = ["README.md", "LICENSE" ]
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.add_dependency "terminal-table"
20
+ s.add_dependency "chef", ">= 0.10"
21
+ s.add_dependency "fog", ">= 1.4"
22
+ ## Fog 1.3.1 deps. We'll need to remove them
23
+ # when using fog upstream
24
+ s.add_dependency('colored')
25
+ s.add_dependency('alchemist')
26
+ s.add_dependency('uuidtools')
27
+ s.require_paths = ["lib"]
28
+ end
@@ -0,0 +1,94 @@
1
+ #
2
+ # Author:: Sergio Rubio (<rubiojr@bvox.net>)
3
+ # Copyright:: BVox S.L. (c) 2012
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife'
20
+ $: << File.dirname(__FILE__) + "/../../../vendor/fog/lib/"
21
+ require 'fog'
22
+ require 'colored'
23
+
24
+ class Chef
25
+ class Knife
26
+ module XenserverBase
27
+
28
+ def self.included(includer)
29
+ includer.class_eval do
30
+
31
+ deps do
32
+ require 'net/ssh/multi'
33
+ require 'readline'
34
+ require 'chef/json_compat'
35
+ require 'terminal-table/import'
36
+ require 'alchemist'
37
+ end
38
+
39
+ option :xenserver_password,
40
+ :long => "--xenserver-password PASSWORD",
41
+ :description => "Your XenServer password"
42
+
43
+ option :xenserver_username,
44
+ :long => "--xenserver-username USERNAME",
45
+ :default => "root",
46
+ :description => "Your XenServer username (default 'root')"
47
+
48
+ option :xenserver_host,
49
+ :long => "--xenserver-host ADDRESS",
50
+ :description => "Your XenServer host address"
51
+ end
52
+ end
53
+
54
+ def connection
55
+ if not @connection
56
+ host = config[:xenserver_host] || Chef::Config[:knife][:xenserver_host]
57
+ username = config[:xenserver_username] || Chef::Config[:knife][:xenserver_username]
58
+ password = config[:xenserver_password] || Chef::Config[:knife][:xenserver_password]
59
+ ui.info "Connecting to XenServer host #{host.yellow}..."
60
+ begin
61
+ @connection = Fog::Compute.new({
62
+ :provider => 'XenServer',
63
+ :xenserver_url => host,
64
+ :xenserver_username => username,
65
+ :xenserver_password => password,
66
+ })
67
+ rescue SocketError => e
68
+ ui.error "Error connecting to the hypervisor: #{host}"
69
+ exit 1
70
+ rescue Fog::XenServer::InvalidLogin => e
71
+ ui.error "Error connecting to the hypervisor: #{host}"
72
+ ui.error "Check the username and password."
73
+ exit
74
+ rescue => e
75
+ ui.error "Error connecting to the hypervisor"
76
+ ui.error "#{e.class} #{e.message}"
77
+ exit 1
78
+ end
79
+
80
+ else
81
+ @connection
82
+ end
83
+ end
84
+
85
+ def locate_config_value(key)
86
+ key = key.to_sym
87
+ Chef::Config[:knife][key] || config[key]
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+
94
+
@@ -0,0 +1,43 @@
1
+ #
2
+ # Author:: Sergio Rubio (<rubiojr@bvox.net>)
3
+ # Copyright:: Copyright (c) 2012 BVox S.L.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife/xenserver_base'
20
+
21
+ class Chef
22
+ class Knife
23
+ class XenserverNetworkList < Knife
24
+
25
+ include Knife::XenserverBase
26
+
27
+ banner "knife xenserver network list"
28
+
29
+ def run
30
+ networks = connection.networks
31
+ table = table do |t|
32
+ t.headings = %w{NETWORK_NAME VIFs PIFs BRIDGE}
33
+ networks.each do |net|
34
+ pifs = net.pifs.map { |p| p.device }
35
+ t << [net.name, net.__vifs.size, pifs.join(","), net.bridge]
36
+ end
37
+ end
38
+ puts table if !networks.empty?
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,216 @@
1
+ #
2
+ # Author:: Sergio Rubio (<rubiojr@bvox.net>)
3
+ # Copyright:: Copyright (c) 2012 BVox S.L.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife/xenserver_base'
20
+ require 'net/scp'
21
+ require 'uuidtools'
22
+
23
+ class Chef
24
+ class Knife
25
+ class XenserverTemplateCreate < Knife
26
+
27
+ include Knife::XenserverBase
28
+
29
+ banner "knife xenserver template create"
30
+
31
+ option :hvm,
32
+ :long => "--hvm",
33
+ :description => "Use HVM (default is PV)",
34
+ :boolean => false,
35
+ :proc => Proc.new { true }
36
+
37
+ option :vm_name,
38
+ :long => "--vm-name NAME",
39
+ :description => "The template name"
40
+
41
+ option :vm_tags,
42
+ :long => "--vm-tags tag1[,tag2..]",
43
+ :description => "Comma separated list of tags"
44
+
45
+ option :vm_disk,
46
+ :long => "--vm-disk DISK",
47
+ :description => "The disk file to use"
48
+
49
+ option :vm_template,
50
+ :long => "--vm-template NAME",
51
+ :description => "The Virtual Machine to clone (TODO)"
52
+
53
+ option :vm_memory,
54
+ :long => "--vm-memory AMOUNT",
55
+ :description => "The memory limits of the Virtual Machine",
56
+ :default => '512'
57
+
58
+ option :storage_repository,
59
+ :long => "--storage-repository",
60
+ :description => "The storage repository to use",
61
+ :default => 'Local storage'
62
+
63
+ option :vm_networks,
64
+ :short => "-N network[,network..]",
65
+ :long => "--vm-networks",
66
+ :description => "Network where nic is attached to"
67
+
68
+ option :mac_addresses,
69
+ :short => "-M mac[,mac..]",
70
+ :long => "--mac-addresses",
71
+ :description => "Mac address list",
72
+ :default => nil
73
+
74
+ def run
75
+ source = config[:vm_disk]
76
+ vm_name = config[:vm_name]
77
+ host = config[:xenserver_host] || Chef::Config[:knife][:xenserver_host]
78
+ user = config[:xenserver_username] || Chef::Config[:knife][:xenserver_username]
79
+ password = config[:xenserver_password] || Chef::Config[:knife][:xenserver_password]
80
+ if host.nil?
81
+ ui.error "Invalid Xen host. Use #{'--xenserver-host'.red.bold} argument."
82
+ exit 1
83
+ end
84
+ if user.nil?
85
+ ui.error "Invalid Xen username. Use #{'--xenserver-username'.red.bold} argument."
86
+ exit 1
87
+ end
88
+ if password.nil?
89
+ ui.error "Invalid Xen password. Use #{'--xenserver-password'.red.bold} argument."
90
+ exit 1
91
+ end
92
+
93
+ if vm_name.nil?
94
+ ui.error "Invalid name for the template. Use #{'--vm-name'.red.bold} argument."
95
+ exit 1
96
+ end
97
+
98
+ if source.nil? or not File.exist?(source)
99
+ ui.error "Invalid source disk #{(source || '').bold}."
100
+ ui.error "#{'--vm-disk'.red.bold} argument is mandatory" \
101
+ if source.nil?
102
+ exit 1
103
+ end
104
+ if source !~ /\.vhd$/
105
+ ui.error "Invalid source disk #{source.red.bold}. I need a VHD file."
106
+ exit 1
107
+ end
108
+
109
+ # Create the VM but do not start/provision it
110
+ if config[:hvm]
111
+ ui.info "HVM".yellow + " template selected"
112
+ pv_bootloader = 'eliloader'
113
+ hvm_boot_policy = 'BIOS order'
114
+ pv_args = ''
115
+ else
116
+ ui.info "PV".yellow + " template selected"
117
+ pv_bootloader = 'pygrub'
118
+ hvm_boot_policy = ''
119
+ pv_args = '-- console=hvc0'
120
+ end
121
+
122
+ ui.info "Creating VM #{vm_name.yellow} on #{host.yellow}..."
123
+
124
+ # We will create the VDI in this SR
125
+ sr = connection.storage_repositories.find { |sr| sr.name == config[:storage_repository] }
126
+ # Upload and replace the VDI with our template
127
+ uuid = UUIDTools::UUID.random_create.to_s
128
+ dest = "/var/run/sr-mount/#{sr.uuid}/#{uuid}.vhd"
129
+ Net::SSH.start(host, user, :password => password) do |ssh|
130
+ puts "Uploading file #{File.basename(source).yellow}..."
131
+ puts "Destination SR #{sr.name.yellow}"
132
+ ssh.scp.upload!(source, dest) do |ch, name, sent, total|
133
+ p = (sent.to_f * 100 / total.to_f).to_i.to_s
134
+ print "\rProgress: #{p.yellow.bold}% completed"
135
+ end
136
+ end
137
+
138
+ sr.scan
139
+ # Create a ~8GB VDI in storage repository 'Local Storage'
140
+ #vdi = connection.vdis.create :name => "#{vm_name}-disk1",
141
+ # :storage_repository => sr,
142
+ # :description => "#{vm_name}-disk1",
143
+ # :virtual_size => '8589934592' # ~8GB in bytes
144
+
145
+ vdi = nil
146
+ sr.vdis.each do |v|
147
+ if v.uuid == uuid
148
+ v.set_attribute 'name_label', "#{vm_name}-template"
149
+ vdi = v
150
+ break
151
+ end
152
+ end
153
+
154
+ mem = (config[:vm_memory].to_i * 1024 * 1024).to_s
155
+ vm = connection.servers.new :name => "#{vm_name}",
156
+ :affinity => connection.hosts.first,
157
+ :other_config => {},
158
+ :pv_bootloader => pv_bootloader,
159
+ :hvm_boot_policy => hvm_boot_policy,
160
+ :pv_args => pv_args,
161
+ :memory_static_max => mem,
162
+ :memory_static_min => mem,
163
+ :memory_dynamic_max => mem,
164
+ :memory_dynamic_min => mem
165
+ vm.save
166
+ if config[:vm_tags]
167
+ vm.set_attribute 'tags', config[:vm_tags].split(',')
168
+ end
169
+
170
+ if config[:vm_networks]
171
+ create_nics(config[:vm_networks], config[:mac_addresses], vm)
172
+ end
173
+ # Add the required VBD to the VM
174
+ connection.vbds.create :server => vm, :vdi => vdi
175
+ puts "\nDone."
176
+
177
+ end
178
+
179
+ def create_nics(networks, macs, vm)
180
+ net_arr = networks.split(/,/).map { |x| { :network => x } }
181
+ nics = []
182
+ if macs
183
+ mac_arr = macs.split(/,/)
184
+ nics = net_arr.each_index { |x| net_arr[x][:mac_address] = mac_arr[x] if mac_arr[x] and !mac_arr[x].empty? }
185
+ else
186
+ nics = net_arr
187
+ end
188
+ networks = connection.networks
189
+ highest_device = 0
190
+ vm.vifs.each { |vif| highest_device = vif.device.to_i if vif.device.to_i > highest_device }
191
+ nic_count = 0
192
+ nics.each do |n|
193
+ net = networks.find { |net| net.name == n[:network] }
194
+ if net.nil?
195
+ ui.error "Network #{n[:network]} not found"
196
+ exit 1
197
+ end
198
+ nic_count += 1
199
+ c = {
200
+ 'MAC_autogenerated' => n[:mac_address].nil? ? 'True':'False',
201
+ 'VM' => vm.reference,
202
+ 'network' => net.reference,
203
+ 'MAC' => n[:mac_address] || '',
204
+ 'device' => (highest_device + nic_count).to_s,
205
+ 'MTU' => '0',
206
+ 'other_config' => {},
207
+ 'qos_algorithm_type' => 'ratelimit',
208
+ 'qos_algorithm_params' => {}
209
+ }
210
+ connection.create_vif_custom c
211
+ end
212
+ end
213
+
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,65 @@
1
+ #
2
+ # Author:: Sergio Rubio (<rubiojr@bvox.net>)
3
+ # Copyright:: Copyright (c) 2012 BVox S.L.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife/xenserver_base'
20
+
21
+ class Chef
22
+ class Knife
23
+ class XenserverTemplateList < Knife
24
+
25
+ include Knife::XenserverBase
26
+
27
+ banner "knife xenserver template list"
28
+
29
+ option :include_builtin,
30
+ :long => "--include-builtin",
31
+ :description => "Include built-in templates",
32
+ :boolean => true,
33
+ :proc => Proc.new { true }
34
+
35
+ def run
36
+ $stdout.sync = true
37
+ templates = connection.servers.custom_templates || []
38
+ table = table do |t|
39
+ t.headings = %w{NAME MEMORY GUEST_TOOLS NETWORKS}
40
+ if templates.empty? and !config[:include_builtin]
41
+ ui.warn "No custom templates found. Use --include-builtin to list them all."
42
+ end
43
+ if config[:include_builtin]
44
+ templates += connection.servers.builtin_templates
45
+ end
46
+ templates.each do |vm|
47
+ networks = []
48
+ vm.vifs.each do |vif|
49
+ name = vif.network.name
50
+ if name.size > 20
51
+ name = name[0..16] + '...'
52
+ end
53
+ networks << name
54
+ end
55
+ networks = networks.join("\n")
56
+ mem = vm.memory_static_max.to_i.bytes.to.megabytes.round
57
+ t << ["#{vm.name}\n #{ui.color('uuid: ', :yellow)}#{vm.uuid}", mem, vm.tools_installed?, networks]
58
+ end
59
+ end
60
+ puts table if !templates.empty?
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,322 @@
1
+ #
2
+ # Author:: Sergio Rubio (<rubiojr@bvox.net>)
3
+ # Copyright:: Copyright (c) 2012 BVox S.L.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife/xenserver_base'
20
+ require 'singleton'
21
+
22
+ class Chef
23
+ class Knife
24
+ class XenserverVmCreate < Knife
25
+
26
+ include Knife::XenserverBase
27
+
28
+ deps do
29
+ require 'readline'
30
+ require 'alchemist'
31
+ require 'chef/json_compat'
32
+ require 'chef/knife/bootstrap'
33
+ Chef::Knife::Bootstrap.load_deps
34
+ end
35
+
36
+ banner "knife xenserver vm create (options)"
37
+
38
+ option :vm_template,
39
+ :long => "--vm-template NAME",
40
+ :description => "The Virtual Machine Template to use"
41
+
42
+ option :vm_name,
43
+ :long => "--vm-name NAME",
44
+ :description => "The Virtual Machine name"
45
+
46
+ option :vm_tags,
47
+ :long => "--vm-tags tag1[,tag2..]",
48
+ :description => "Comma separated list of tags"
49
+
50
+ option :chef_node_name,
51
+ :short => "-N NAME",
52
+ :long => "--node-name NAME",
53
+ :description => "The Chef node name for your new node"
54
+
55
+ option :vm_memory,
56
+ :long => "--vm-memory AMOUNT",
57
+ :description => "The memory limits of the Virtual Machine",
58
+ :default => '512'
59
+
60
+ option :vm_cpus,
61
+ :long => "--vm-cpus AMOUNT",
62
+ :description => "The VCPUs of the Virtual Machine",
63
+ :default => '1'
64
+
65
+ option :bootstrap_version,
66
+ :long => "--bootstrap-version VERSION",
67
+ :description => "The version of Chef to install",
68
+ :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
69
+
70
+ option :distro,
71
+ :short => "-d DISTRO",
72
+ :long => "--distro DISTRO",
73
+ :description => "Bootstrap a distro using a template; default is 'ubuntu10.04-gems'",
74
+ :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
75
+ :default => "ubuntu10.04-gems"
76
+
77
+ option :template_file,
78
+ :long => "--template-file TEMPLATE",
79
+ :description => "Full path to location of template to use",
80
+ :proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
81
+ :default => false
82
+
83
+ option :run_list,
84
+ :short => "-r RUN_LIST",
85
+ :long => "--run-list RUN_LIST",
86
+ :description => "Comma separated list of roles/recipes to apply",
87
+ :proc => lambda { |o| o.split(/[\s,]+/) },
88
+ :default => []
89
+
90
+ option :ssh_user,
91
+ :short => "-x USERNAME",
92
+ :long => "--ssh-user USERNAME",
93
+ :description => "The ssh username; default is 'root'",
94
+ :default => "root"
95
+
96
+ option :ssh_password,
97
+ :short => "-P PASSWORD",
98
+ :long => "--ssh-password PASSWORD",
99
+ :description => "The ssh password"
100
+
101
+ option :identity_file,
102
+ :short => "-i IDENTITY_FILE",
103
+ :long => "--identity-file IDENTITY_FILE",
104
+ :description => "The SSH identity file used for authentication"
105
+
106
+ option :no_host_key_verify,
107
+ :long => "--no-host-key-verify",
108
+ :description => "Disable host key verification",
109
+ :boolean => true,
110
+ :default => false,
111
+ :proc => Proc.new { true }
112
+
113
+ option :skip_bootstrap,
114
+ :long => "--skip-bootstrap",
115
+ :description => "Skip bootstrap process (Deploy only mode)",
116
+ :boolean => true,
117
+ :default => false,
118
+ :proc => Proc.new { true }
119
+
120
+ option :keep_template_networks,
121
+ :long => "--keep-template-networks",
122
+ :description => "Do no remove template inherited networks (VIFs)",
123
+ :boolean => true,
124
+ :default => false,
125
+ :proc => Proc.new { true }
126
+
127
+ option :batch,
128
+ :long => "--batch script.yml",
129
+ :description => "Use a batch file to deploy multiple VMs",
130
+ :default => nil
131
+
132
+ option :vm_networks,
133
+ :short => "-N network[,network..]",
134
+ :long => "--vm-networks",
135
+ :description => "Network where nic is attached to"
136
+
137
+ option :mac_addresses,
138
+ :short => "-M mac[,mac..]",
139
+ :long => "--mac-addresses",
140
+ :description => "Mac address list",
141
+ :default => nil
142
+
143
+ def tcp_test_ssh(hostname)
144
+ tcp_socket = TCPSocket.new(hostname, 22)
145
+ readable = IO.select([tcp_socket], nil, nil, 5)
146
+ if readable
147
+ Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
148
+ yield
149
+ true
150
+ else
151
+ false
152
+ end
153
+ rescue Errno::ETIMEDOUT, Errno::EPERM
154
+ false
155
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH
156
+ sleep 2
157
+ false
158
+ ensure
159
+ tcp_socket && tcp_socket.close
160
+ end
161
+
162
+ def run
163
+ $stdout.sync = true
164
+
165
+ unless config[:vm_template]
166
+ ui.error("You have not provided a valid template name. (--vm-template)")
167
+ exit 1
168
+ end
169
+
170
+ vm_name = config[:vm_name]
171
+ if not vm_name
172
+ ui.error("Invalid Virtual Machine name (--vm-name)")
173
+ exit 1
174
+ end
175
+
176
+ template = connection.servers.templates.find do |s|
177
+ (s.name == config[:vm_template]) or (s.uuid == config[:vm_template])
178
+ end
179
+
180
+ if template.nil?
181
+ ui.error "Template #{config[:vm_template]} not found."
182
+ exit 1
183
+ end
184
+
185
+ puts "Creating VM #{config[:vm_name].yellow}..."
186
+ puts "Using template #{template.name.yellow} [uuid: #{template.uuid}]..."
187
+
188
+ vm = connection.servers.new :name => config[:vm_name],
189
+ :template_name => config[:vm_template]
190
+ vm.save :auto_start => false
191
+ if not config[:keep_template_networks]
192
+ vm.vifs.each do |vif|
193
+ vif.destroy
194
+ end
195
+ vm.reload
196
+ end
197
+ if config[:vm_networks]
198
+ create_nics(config[:vm_networks], config[:mac_addresses], vm)
199
+ end
200
+ mem = (config[:vm_memory].to_i * 1024 * 1024).to_s
201
+ vm.set_attribute 'memory_limits', mem, mem, mem, mem
202
+ vm.set_attribute 'VCPUs_max', config[:vm_cpus]
203
+ vm.set_attribute 'VCPUs_at_startup', config[:vm_cpus]
204
+ if config[:vm_tags]
205
+ vm.set_attribute 'tags', config[:vm_tags].split(',')
206
+ end
207
+ vm.provision
208
+ vm.start
209
+ vm.reload
210
+
211
+ puts "#{ui.color("VM Name", :cyan)}: #{vm.name}"
212
+ puts "#{ui.color("VM Memory", :cyan)}: #{vm.memory_static_max.to_i.bytes.to.megabytes.round} MB"
213
+
214
+ if !config[:skip_bootstrap]
215
+ # wait for it to be ready to do stuff
216
+ print "\n#{ui.color("Waiting server... ", :magenta)}"
217
+ timeout = 180
218
+ found = connection.servers.all.find { |v| v.name == vm.name }
219
+ servers = connection.servers
220
+ loop do
221
+ begin
222
+ vm.refresh
223
+ if not vm.guest_metrics.nil? and not vm.guest_metrics.networks.empty?
224
+ networks = []
225
+ vm.guest_metrics.networks.each do |k,v|
226
+ networks << v
227
+ end
228
+ networks = networks.join(",")
229
+ puts
230
+ puts "\n#{ui.color("Server IPs:", :cyan)} #{networks}"
231
+ break
232
+ end
233
+ rescue Fog::Errors::Error
234
+ print "\r#{ui.color('Waiting a valid IP', :magenta)}..." + "." * (100 - timeout)
235
+ end
236
+ sleep 1
237
+ timeout -= 1
238
+ if timeout == 0
239
+ puts
240
+ ui.error "Timeout trying to reach the VM. Couldn't find the IP address."
241
+ exit 1
242
+ end
243
+ end
244
+ print "\n#{ui.color("Waiting for sshd... ", :magenta)}"
245
+ vm.guest_metrics.networks.each do |k,v|
246
+ print "\nTrying to #{'SSH'.yellow} to #{v.yellow}... "
247
+ print(".") until tcp_test_ssh(v) do
248
+ sleep @initial_sleep_delay ||= 10; puts(" done")
249
+ @ssh_ip = v
250
+ end
251
+ break if @ssh_ip
252
+ end
253
+
254
+ bootstrap_for_node(vm).run
255
+ puts "\n"
256
+ puts "#{ui.color("Name", :cyan)}: #{vm.name}"
257
+ puts "#{ui.color("IP Address", :cyan)}: #{@ssh_ip}"
258
+ puts "#{ui.color("Environment", :cyan)}: #{config[:environment] || '_default'}"
259
+ puts "#{ui.color("Run List", :cyan)}: #{config[:run_list].join(', ')}"
260
+ puts "#{ui.color("Done!", :green)}"
261
+ else
262
+ ui.warn "Skipping bootstrapping as requested."
263
+ end
264
+
265
+ end
266
+
267
+ def bootstrap_for_node(vm)
268
+ bootstrap = Chef::Knife::Bootstrap.new
269
+ bootstrap.name_args = [@ssh_ip]
270
+ bootstrap.config[:run_list] = config[:run_list]
271
+ bootstrap.config[:ssh_user] = config[:ssh_user]
272
+ bootstrap.config[:identity_file] = config[:identity_file]
273
+ bootstrap.config[:chef_node_name] = config[:chef_node_name] || vm.name
274
+ bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
275
+ bootstrap.config[:distro] = locate_config_value(:distro)
276
+ # bootstrap will run as root...sudo (by default) also messes up Ohai on CentOS boxes
277
+ bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
278
+ bootstrap.config[:template_file] = locate_config_value(:template_file)
279
+ bootstrap.config[:environment] = config[:environment]
280
+ bootstrap.config[:no_host_key_verify] = config[:no_host_key_verify]
281
+ bootstrap.config[:ssh_password] = config[:ssh_password]
282
+ bootstrap
283
+ end
284
+
285
+ def create_nics(networks, macs, vm)
286
+ net_arr = networks.split(/,/).map { |x| { :network => x } }
287
+ nics = []
288
+ if macs
289
+ mac_arr = macs.split(/,/)
290
+ nics = net_arr.each_index { |x| net_arr[x][:mac_address] = mac_arr[x] if mac_arr[x] and !mac_arr[x].empty? }
291
+ else
292
+ nics = net_arr
293
+ end
294
+ networks = connection.networks
295
+ highest_device = -1
296
+ vm.vifs.each { |vif| highest_device = vif.device.to_i if vif.device.to_i > highest_device }
297
+ nic_count = 0
298
+ nics.each do |n|
299
+ net = networks.find { |net| net.name == n[:network] }
300
+ if net.nil?
301
+ ui.error "Network #{n[:network]} not found"
302
+ exit 1
303
+ end
304
+ nic_count += 1
305
+ c = {
306
+ 'MAC_autogenerated' => n[:mac_address].nil? ? 'True':'False',
307
+ 'VM' => vm.reference,
308
+ 'network' => net.reference,
309
+ 'MAC' => n[:mac_address] || '',
310
+ 'device' => (highest_device + nic_count).to_s,
311
+ 'MTU' => '0',
312
+ 'other_config' => {},
313
+ 'qos_algorithm_type' => 'ratelimit',
314
+ 'qos_algorithm_params' => {}
315
+ }
316
+ connection.create_vif_custom c
317
+ end
318
+ end
319
+
320
+ end
321
+ end
322
+ end
@@ -0,0 +1,55 @@
1
+ #
2
+ # Author:: Sergio Rubio (<rubiojr@frameos.org>)
3
+ # Copyright:: Copyright (c) 2011 Sergio Rubio
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife/xenserver_base'
20
+
21
+ class Chef
22
+ class Knife
23
+ class XenserverVmDelete < Knife
24
+
25
+ include Knife::XenserverBase
26
+
27
+ banner "knife xenserver vm delete VM_NAME [VM_NAME] (options)"
28
+
29
+ option :force_delete,
30
+ :long => "--force-delete NO",
31
+ :default => 'no',
32
+ :description => "Do not confirm VM deletion when yes"
33
+
34
+ def run
35
+ deleted = []
36
+ connection.servers.each do |vm|
37
+ @name_args.each do |vm_name|
38
+ if (vm_name == vm.name) or (vm_name == vm.uuid)
39
+ if config[:force_delete] =~ /(no|NO|false|FALSE)/
40
+ confirm("Do you really want to #{'delete'.bold.red} this virtual machine #{vm.name.bold.red}")
41
+ end
42
+ vm.destroy
43
+ deleted << vm_name
44
+ ui.info("#{'Deleted'.yellow} virtual machine #{vm.name.yellow} [uuid: #{vm.uuid}]")
45
+ end
46
+ end
47
+ end
48
+ @name_args.each do |vm_name|
49
+ ui.warn "Virtual Machine #{vm_name} not found" if not deleted.include?(vm_name)
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,60 @@
1
+ #
2
+ # Author:: Sergio Rubio (<rubiojr@bvox.net>)
3
+ # Copyright:: Copyright (c) 2012 BVox S.L.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife/xenserver_base'
20
+
21
+ class Chef
22
+ class Knife
23
+ class XenserverVmList < Knife
24
+
25
+ include Knife::XenserverBase
26
+
27
+ banner "knife xenserver vm list (options)"
28
+
29
+ def run
30
+ $stdout.sync = true
31
+ vm_table = table do |t|
32
+ t.headings = %w{NAME MEM POWER TOOLS NETWORKS IPs}
33
+ connection.servers.each do |vm|
34
+ if vm.tools_installed?
35
+ ips = []
36
+ vm.guest_metrics.networks.each do |k,v|
37
+ ips << v
38
+ end
39
+ ips = ips.join("\n")
40
+ else
41
+ ips = "unknown"
42
+ end
43
+ networks = []
44
+ vm.vifs.each do |vif|
45
+ name = vif.network.name
46
+ if name.size > 20
47
+ name = name[0..16] + '...'
48
+ end
49
+ networks << name
50
+ end
51
+ networks = networks.join("\n")
52
+ mem = vm.memory_static_max.to_i.bytes.to.megabytes.round
53
+ t << ["#{vm.uuid}\n #{ui.color('name: ', :yellow)}#{vm.name.ljust(32)}", mem, vm.power_state, vm.tools_installed?, networks,ips]
54
+ end
55
+ end
56
+ puts vm_table if connection.servers.size > 0
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,6 @@
1
+ module Knife
2
+ module XenServer
3
+ VERSION = "1.0.1"
4
+ MAJOR, MINOR, TINY = VERSION.split('.')
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: knife-xenserver
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sergio Rubio
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: terminal-table
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: chef
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0.10'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0.10'
46
+ - !ruby/object:Gem::Dependency
47
+ name: fog
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '1.4'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ - !ruby/object:Gem::Dependency
63
+ name: colored
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: alchemist
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: uuidtools
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: XenServer Support for Chef's Knife Command
111
+ email:
112
+ - rubiojr@frameos.org
113
+ - rubiojr@frameos.org
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files:
117
+ - README.md
118
+ - LICENSE
119
+ files:
120
+ - .gitignore
121
+ - CHANGELOG.md
122
+ - LICENSE
123
+ - README.md
124
+ - knife-xenserver.gemspec
125
+ - lib/chef/knife/xenserver_base.rb
126
+ - lib/chef/knife/xenserver_network_list.rb
127
+ - lib/chef/knife/xenserver_template_create.rb
128
+ - lib/chef/knife/xenserver_template_list.rb
129
+ - lib/chef/knife/xenserver_vm_create.rb
130
+ - lib/chef/knife/xenserver_vm_delete.rb
131
+ - lib/chef/knife/xenserver_vm_list.rb
132
+ - lib/knife-xenserver/version.rb
133
+ homepage: http://github.com/rubiojr/knife-xenserver
134
+ licenses: []
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ! '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 1.8.24
154
+ signing_key:
155
+ specification_version: 3
156
+ summary: XenServer Support for Chef's Knife Command
157
+ test_files: []