knife-rackspace-cluster 0.0.2
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/lib/chef/knife/rax_cluster_base.rb +152 -0
- data/lib/chef/knife/rax_cluster_build.rb +220 -0
- data/lib/chef/knife/rax_cluster_change.rb +95 -0
- data/lib/chef/knife/rax_cluster_create.rb +212 -0
- data/lib/chef/knife/rax_cluster_delete.rb +76 -0
- data/lib/chef/knife/rax_cluster_expand.rb +104 -0
- data/lib/chef/knife/rax_cluster_list.rb +56 -0
- data/lib/chef/knife/super_rax.rb +126 -0
- metadata +82 -0
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
#require 'chef/knife/rackspace/rackspace_base'
|
3
|
+
#require 'chef/knife/rackspafce/rackspace_server_create'
|
4
|
+
|
5
|
+
|
6
|
+
# Make sure you subclass from Chef::Knife
|
7
|
+
|
8
|
+
class Chef
|
9
|
+
class Knife
|
10
|
+
|
11
|
+
|
12
|
+
module RaxClusterBase
|
13
|
+
|
14
|
+
def self.included(includer)
|
15
|
+
includer.class_eval do
|
16
|
+
|
17
|
+
deps do
|
18
|
+
|
19
|
+
require "net/https"
|
20
|
+
require 'net/http'
|
21
|
+
require "uri"
|
22
|
+
requie 'json'
|
23
|
+
#require 'chef/shef/ext'
|
24
|
+
#require 'rubygems'
|
25
|
+
#require 'chef/knife/rackspace_server_create'
|
26
|
+
#require 'json'
|
27
|
+
require 'fog'
|
28
|
+
#require "thread"
|
29
|
+
#require 'net/ssh/multi'
|
30
|
+
require 'readline'
|
31
|
+
require 'chef/knife/bootstrap'
|
32
|
+
require 'chef/json_compat'
|
33
|
+
|
34
|
+
Chef::Knife::Bootstrap.load_deps
|
35
|
+
#include Knife::RackspaceBase
|
36
|
+
end
|
37
|
+
#option :rax_cluster_auth,
|
38
|
+
# :short => "-auth auth_url_for_cluster",
|
39
|
+
# :long => "--rackspace-api-url url",
|
40
|
+
# :description => "Specify the URL to auth for creation of LB's, i.e. (https:////identity.api.rackspacecloud.com/v1.1)",
|
41
|
+
# :proc => Proc.new { |key| Chef::Config[:knife][:rax_cluster_auth] = key }
|
42
|
+
|
43
|
+
#option :rackspace_api_key,
|
44
|
+
# :short => "-K KEY",
|
45
|
+
# :long => "--rackspace-api-key KEY",
|
46
|
+
# :description => "Your rackspace API key",
|
47
|
+
# :proc => Proc.new { |key| Chef::Config[:knife][:rackspace_api_key] = key }
|
48
|
+
#
|
49
|
+
#option :rackspace_username,
|
50
|
+
# :short => "-A USERNAME",
|
51
|
+
# :long => "--rackspace-username USERNAME",
|
52
|
+
# :description => "Your rackspace API username",
|
53
|
+
# :proc => Proc.new { |username| Chef::Config[:knife][:rackspace_username] = username }
|
54
|
+
#
|
55
|
+
#option :rackspace_version,
|
56
|
+
# :long => '--rackspace-version VERSION',
|
57
|
+
# :description => 'Rackspace Cloud Servers API version',
|
58
|
+
# :default => "v1",
|
59
|
+
# :proc => Proc.new { |version| Chef::Config[:knife][:rackspace_version] = version }
|
60
|
+
#
|
61
|
+
#option :rackspace_api_auth_url,
|
62
|
+
# :long => "--rackspace-api-auth-url URL",
|
63
|
+
# :description => "Your rackspace API auth url",
|
64
|
+
# :default => "auth.api.rackspacecloud.com",
|
65
|
+
# :proc => Proc.new { |url| Chef::Config[:knife][:rackspace_api_auth_url] = url },
|
66
|
+
# :default => "https://identity.api.rackspacecloud.com/v1.1/auth"
|
67
|
+
#
|
68
|
+
#option :rackspace_endpoint,
|
69
|
+
# :long => "--rackspace-endpoint URL",
|
70
|
+
# :description => "Your rackspace API endpoint",
|
71
|
+
# :default => "https://dfw.servers.api.rackspacecloud.com/v2",
|
72
|
+
# :proc => Proc.new { |url| Chef::Config[:knife][:rackspace_endpoint] = url }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def populate_environment
|
76
|
+
self.setup_environment_vars{
|
77
|
+
rackspace_username = Chef::Config[:knife][:rackspace_username]
|
78
|
+
rackspace_password = Chef::Config[:knife][:rackspace_password]
|
79
|
+
rackspace_endpoint = Chef::Config[:knife][:rackspace_auth_url]
|
80
|
+
@headers = {"x-auth-user" => rackspace_username, "x-auth-key" => rackspace_password,
|
81
|
+
"auth_url" => rackspace_endpoint,
|
82
|
+
"content-type" => "application/json", "Accept" => "application/json"}
|
83
|
+
#@rax_endpoint = Chef::Config[:knife][:narciss_url] + "/" + Chef::Config[:knife][:narciss_version] + "/"
|
84
|
+
#if rackspace_username_set
|
85
|
+
# @rackspace_username = rackspace_username
|
86
|
+
#end
|
87
|
+
#if rackspace_password_set
|
88
|
+
# @rackspace_password = rackspace_password
|
89
|
+
#end
|
90
|
+
#if rackspace_tenant_set
|
91
|
+
# @rackspace_tenant = rackspace_tenant
|
92
|
+
#end
|
93
|
+
#if rackspace_endpoint_set
|
94
|
+
# @rackspace_endpoint = rackspace_endpoint
|
95
|
+
#end
|
96
|
+
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
def make_web_call(httpVerb,uri,headers=nil, request_content=nil)
|
101
|
+
verbs =
|
102
|
+
{"get" => "Net::HTTP::Get.new(uri.request_uri, headers)",
|
103
|
+
"head" => "Net::HTTP::Head.new(uri.request_uri, headers)",
|
104
|
+
"put" => "Net::HTTP::Put.new(uri.request_uri, headers)",
|
105
|
+
"delete" => "Net::HTTP::Delete.new(uri.request_uri, headers)",
|
106
|
+
"post" => "Net::HTTP::Post.new(uri.request_uri, headers)"
|
107
|
+
}
|
108
|
+
#Get to work boy! This is Ruby!
|
109
|
+
uri = URI.parse(uri)
|
110
|
+
|
111
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
112
|
+
#if uri.host =~ /https/
|
113
|
+
http.use_ssl = true
|
114
|
+
#end
|
115
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
116
|
+
request = eval verbs[httpVerb]
|
117
|
+
if httpVerb == 'post' or httpVerb == 'put'
|
118
|
+
request.body = request_content
|
119
|
+
end
|
120
|
+
response = http.request(request)
|
121
|
+
if not ('200'..'204').include? response.code
|
122
|
+
puts "Error making web call"
|
123
|
+
puts "Response code : #{response.code}"
|
124
|
+
puts "Response body : #{response.body}"
|
125
|
+
#puts "Response Headers : #{response.headers}"
|
126
|
+
end
|
127
|
+
return response
|
128
|
+
|
129
|
+
end
|
130
|
+
#Just used for lbaas since fog doesn't allow meta data on LB's
|
131
|
+
def authenticate(auth_url='https://identity.api.rackspacecloud.com/v1.1/auth',username=Chef::Config[:knife][:rackspace_api_username] ,password=Chef::Config[:knife][:rackspace_api_key])
|
132
|
+
auth_json = {
|
133
|
+
"credentials" => {
|
134
|
+
"username" => username,
|
135
|
+
"key" => password
|
136
|
+
}
|
137
|
+
}
|
138
|
+
headers = {"Content-Type" => "application/json"}
|
139
|
+
auth_data = make_web_call('post', auth_url, headers, auth_json.to_json)
|
140
|
+
lb_data = JSON.parse(auth_data.body)
|
141
|
+
lb_returned = {'auth_token' => lb_data['auth']['token']['id'], 'lb_urls' => lb_data['auth']['serviceCatalog']['cloudLoadBalancers'] }
|
142
|
+
return lb_returned
|
143
|
+
end
|
144
|
+
def msg_pair(label, value, color=:cyan)
|
145
|
+
if value && !value.to_s.empty?
|
146
|
+
puts "#{ui.color(label, color)}: #{value}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
|
2
|
+
require 'chef/knife/rackspace_server_create'
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class RaxClusterBuild < RackspaceServerCreate
|
6
|
+
|
7
|
+
include Knife::RackspaceBase
|
8
|
+
|
9
|
+
deps do
|
10
|
+
require 'fog'
|
11
|
+
require 'readline'
|
12
|
+
require 'chef/json_compat'
|
13
|
+
require 'chef/knife/bootstrap'
|
14
|
+
Chef::Knife::Bootstrap.load_deps
|
15
|
+
end
|
16
|
+
|
17
|
+
banner "knife rackspace server create (options)"
|
18
|
+
|
19
|
+
option :flavor,
|
20
|
+
:short => "-f FLAVOR",
|
21
|
+
:long => "--flavor FLAVOR",
|
22
|
+
:description => "The flavor of server; default is 2 (512 MB)",
|
23
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:flavor] = f.to_i },
|
24
|
+
:default => 2
|
25
|
+
|
26
|
+
option :image,
|
27
|
+
:short => "-I IMAGE",
|
28
|
+
:long => "--image IMAGE",
|
29
|
+
:description => "The image of the server",
|
30
|
+
:proc => Proc.new { |i| Chef::Config[:knife][:image] = i.to_s }
|
31
|
+
|
32
|
+
option :server_name,
|
33
|
+
:short => "-S NAME",
|
34
|
+
:long => "--server-name NAME",
|
35
|
+
:description => "The server name"
|
36
|
+
|
37
|
+
option :chef_node_name,
|
38
|
+
:short => "-N NAME",
|
39
|
+
:long => "--node-name NAME",
|
40
|
+
:description => "The Chef node name for your new node"
|
41
|
+
|
42
|
+
option :private_network,
|
43
|
+
:long => "--private-network",
|
44
|
+
:description => "Use the private IP for bootstrapping rather than the public IP",
|
45
|
+
:boolean => true,
|
46
|
+
:default => false
|
47
|
+
|
48
|
+
option :ssh_user,
|
49
|
+
:short => "-x USERNAME",
|
50
|
+
:long => "--ssh-user USERNAME",
|
51
|
+
:description => "The ssh username; default is 'root'",
|
52
|
+
:default => "root"
|
53
|
+
|
54
|
+
option :ssh_password,
|
55
|
+
:short => "-P PASSWORD",
|
56
|
+
:long => "--ssh-password PASSWORD",
|
57
|
+
:description => "The ssh password"
|
58
|
+
|
59
|
+
option :identity_file,
|
60
|
+
:short => "-i IDENTITY_FILE",
|
61
|
+
:long => "--identity-file IDENTITY_FILE",
|
62
|
+
:description => "The SSH identity file used for authentication"
|
63
|
+
|
64
|
+
option :prerelease,
|
65
|
+
:long => "--prerelease",
|
66
|
+
:description => "Install the pre-release chef gems"
|
67
|
+
|
68
|
+
option :bootstrap_version,
|
69
|
+
:long => "--bootstrap-version VERSION",
|
70
|
+
:description => "The version of Chef to install",
|
71
|
+
:proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
|
72
|
+
|
73
|
+
option :distro,
|
74
|
+
:short => "-d DISTRO",
|
75
|
+
:long => "--distro DISTRO",
|
76
|
+
:description => "Bootstrap a distro using a template; default is 'chef-full'",
|
77
|
+
:proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
|
78
|
+
:default => "chef-full"
|
79
|
+
|
80
|
+
option :template_file,
|
81
|
+
:long => "--template-file TEMPLATE",
|
82
|
+
:description => "Full path to location of template to use",
|
83
|
+
:proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
|
84
|
+
:default => false
|
85
|
+
|
86
|
+
option :run_list,
|
87
|
+
:short => "-r RUN_LIST",
|
88
|
+
:long => "--run-list RUN_LIST",
|
89
|
+
:description => "Comma separated list of roles/recipes to apply",
|
90
|
+
:proc => lambda { |o| o.split(/[\s,]+/) },
|
91
|
+
:default => []
|
92
|
+
|
93
|
+
option :first_boot_attributes,
|
94
|
+
:short => "-j JSON_ATTRIBS",
|
95
|
+
:long => "--json-attributes",
|
96
|
+
:description => "A JSON string to be added to the first run of chef-client",
|
97
|
+
:proc => lambda { |o| JSON.parse(o) },
|
98
|
+
:default => {}
|
99
|
+
|
100
|
+
option :rackspace_metadata,
|
101
|
+
:short => "-M JSON",
|
102
|
+
:long => "--rackspace-metadata JSON",
|
103
|
+
:description => "JSON string version of metadata hash to be supplied with the server create call",
|
104
|
+
:proc => Proc.new { |m| Chef::Config[:knife][:rackspace_metadata] = JSON.parse(m) },
|
105
|
+
:default => ""
|
106
|
+
|
107
|
+
option :host_key_verify,
|
108
|
+
:long => "--[no-]host-key-verify",
|
109
|
+
:description => "Verify host key, enabled by default",
|
110
|
+
:boolean => true,
|
111
|
+
:default => true
|
112
|
+
|
113
|
+
def tcp_test_ssh(hostname)
|
114
|
+
tcp_socket = TCPSocket.new(hostname, 22)
|
115
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
116
|
+
if readable
|
117
|
+
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
|
118
|
+
yield
|
119
|
+
true
|
120
|
+
else
|
121
|
+
false
|
122
|
+
end
|
123
|
+
rescue Errno::ETIMEDOUT
|
124
|
+
false
|
125
|
+
rescue Errno::EPERM
|
126
|
+
false
|
127
|
+
rescue Errno::ECONNREFUSED
|
128
|
+
sleep 2
|
129
|
+
false
|
130
|
+
rescue Errno::EHOSTUNREACH
|
131
|
+
sleep 2
|
132
|
+
false
|
133
|
+
ensure
|
134
|
+
tcp_socket && tcp_socket.close
|
135
|
+
end
|
136
|
+
|
137
|
+
def run
|
138
|
+
$stdout.sync = true
|
139
|
+
|
140
|
+
unless Chef::Config[:knife][:image]
|
141
|
+
ui.error("You have not provided a valid image value. Please note the short option for this value recently changed from '-i' to '-I'.")
|
142
|
+
exit 1
|
143
|
+
end
|
144
|
+
|
145
|
+
node_name = get_node_name(config[:chef_node_name] || config[:server_name])
|
146
|
+
|
147
|
+
server = connection.servers.create(
|
148
|
+
:name => node_name,
|
149
|
+
:image_id => Chef::Config[:knife][:image],
|
150
|
+
:flavor_id => locate_config_value(:flavor),
|
151
|
+
:metadata => Chef::Config[:knife][:rackspace_metadata]
|
152
|
+
)
|
153
|
+
|
154
|
+
msg_pair("Instance ID", server.id)
|
155
|
+
msg_pair("Host ID", server.host_id)
|
156
|
+
msg_pair("Name", server.name)
|
157
|
+
msg_pair("Flavor", server.flavor.name)
|
158
|
+
msg_pair("Image", server.image.name)
|
159
|
+
msg_pair("Metadata", server.metadata)
|
160
|
+
|
161
|
+
print "\n#{ui.color("Waiting server", :magenta)}"
|
162
|
+
|
163
|
+
# wait for it to be ready to do stuff
|
164
|
+
server.wait_for { print "."; ready? }
|
165
|
+
|
166
|
+
puts("\n")
|
167
|
+
|
168
|
+
msg_pair("Public DNS Name", public_dns_name(server))
|
169
|
+
msg_pair("Public IP Address", public_ip(server))
|
170
|
+
msg_pair("Private IP Address", private_ip(server))
|
171
|
+
msg_pair("Password", server.password)
|
172
|
+
|
173
|
+
print "\n#{ui.color("Waiting for sshd", :magenta)}"
|
174
|
+
|
175
|
+
#which IP address to bootstrap
|
176
|
+
bootstrap_ip_address = public_ip(server)
|
177
|
+
if config[:private_network]
|
178
|
+
bootstrap_ip_address = private_ip(server)
|
179
|
+
end
|
180
|
+
Chef::Log.debug("Bootstrap IP Address #{bootstrap_ip_address}")
|
181
|
+
if bootstrap_ip_address.nil?
|
182
|
+
ui.error("No IP address available for bootstrapping.")
|
183
|
+
exit 1
|
184
|
+
end
|
185
|
+
|
186
|
+
print(".") until tcp_test_ssh(bootstrap_ip_address) {
|
187
|
+
sleep @initial_sleep_delay ||= 10
|
188
|
+
puts("done")
|
189
|
+
}
|
190
|
+
bootstrap_for_node(server, bootstrap_ip_address).run
|
191
|
+
|
192
|
+
puts "\n"
|
193
|
+
msg_pair("Instance ID", server.id)
|
194
|
+
msg_pair("Host ID", server.host_id)
|
195
|
+
msg_pair("Name", server.name)
|
196
|
+
msg_pair("Flavor", server.flavor.name)
|
197
|
+
msg_pair("Image", server.image.name)
|
198
|
+
msg_pair("Metadata", server.metadata)
|
199
|
+
msg_pair("Public DNS Name", public_dns_name(server))
|
200
|
+
msg_pair("Public IP Address", public_ip(server))
|
201
|
+
msg_pair("Private IP Address", private_ip(server))
|
202
|
+
msg_pair("Password", server.password)
|
203
|
+
msg_pair("Environment", config[:environment] || '_default')
|
204
|
+
msg_pair("Run List", config[:run_list].join(', '))
|
205
|
+
ipaddress = ''
|
206
|
+
#if not server.private_ip_address
|
207
|
+
# ipaddress = server.public_ip_address
|
208
|
+
#end
|
209
|
+
#if not ipaddress
|
210
|
+
# ipaddress = "false"
|
211
|
+
#end
|
212
|
+
return_hash = {"public_ip" => public_ip(server), "private_ip" => private_ip(server), "server_name" => server.name, "server_id" => server.id}
|
213
|
+
return return_hash
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
class Chef
|
2
|
+
class Knife
|
3
|
+
class RaxClusterChange < Knife
|
4
|
+
attr_accessor :headers, :rax_endpoint, :lb_id
|
5
|
+
include Knife::RaxClusterBase
|
6
|
+
|
7
|
+
banner "knife rax cluster change LB_ID (chef_options)"
|
8
|
+
deps do
|
9
|
+
require 'fog'
|
10
|
+
require 'readline'
|
11
|
+
require 'chef/json_compat'
|
12
|
+
require 'chef/knife/bootstrap'
|
13
|
+
Chef::Knife::Bootstrap.load_deps
|
14
|
+
end
|
15
|
+
|
16
|
+
option :lb_region,
|
17
|
+
:short => "-r lb_region",
|
18
|
+
:long => "--load-balancer-region lb_region",
|
19
|
+
:description => "Load balancer region (only supports ORD || DFW)",
|
20
|
+
:proc => Proc.new { |lb_region| Chef::Config[:knife][:lb_region] = lb_region},
|
21
|
+
:default => "ORD"
|
22
|
+
|
23
|
+
option :run_list,
|
24
|
+
:long => "--run-list run_list",
|
25
|
+
:description => "Pass a comma delimted run list --run-list 'recipe[apt],role[base]'",
|
26
|
+
:proc => Proc.new { |run_list| Chef::Config[:knife][:run_list] = run_list}
|
27
|
+
|
28
|
+
option :chef_env,
|
29
|
+
:long => "--chef-env environment",
|
30
|
+
:description => "Pass a comma delimted run list --run-list 'recipe[apt],role[base]'",
|
31
|
+
:proc => Proc.new { |chef_env| Chef::Config[:knife][:chef_env] = chef_env}
|
32
|
+
|
33
|
+
def change_chef_vars(instances, &block)
|
34
|
+
instances.each { |inst|
|
35
|
+
query = "name:#{inst['server_name']}"
|
36
|
+
query_nodes = Chef::Search::Query.new
|
37
|
+
query_nodes.search('node', query) do |node_item|
|
38
|
+
yield node_item
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
def run
|
43
|
+
if !config[:run_list] and !config[:chef_env]
|
44
|
+
ui.fatal "Please specify either --run-list or --chef-env to change on your cluster"
|
45
|
+
exit(1)
|
46
|
+
end
|
47
|
+
if @name_args.empty?
|
48
|
+
ui.fatal "Please specify a load balancer ID to update"
|
49
|
+
exit(1)
|
50
|
+
end
|
51
|
+
lb_auth = authenticate()
|
52
|
+
headers = {"x-auth-token" => lb_auth['auth_token'], "content-type" => "application/json"}
|
53
|
+
lb_url = ""
|
54
|
+
lb_auth['lb_urls'].each {|lb|
|
55
|
+
if config[:lb_region].to_s.downcase == lb['region'].to_s.downcase
|
56
|
+
lb_url = lb['publicURL']
|
57
|
+
break
|
58
|
+
end
|
59
|
+
lb_url = lb['publicURL']
|
60
|
+
}
|
61
|
+
@name_args.each {|arg|
|
62
|
+
lb_url = lb_url + "/loadbalancers/#{arg}"
|
63
|
+
lb_data = make_web_call("get", lb_url, headers)
|
64
|
+
lb_data = JSON.parse(lb_data.body)
|
65
|
+
instances = []
|
66
|
+
lb_data['loadBalancer']['metadata'].each{|md|
|
67
|
+
instances << {"server_name" => md['key'], "uuid" => md['uuid']}
|
68
|
+
}
|
69
|
+
|
70
|
+
if config[:run_list]
|
71
|
+
config[:run_list] = config[:run_list].split(",")
|
72
|
+
change_chef_vars(instances) { |node_item|
|
73
|
+
ui.msg "Changing #{node_item.name} run list to #{config[:run_list]}"
|
74
|
+
node_item.run_list(config[:run_list])
|
75
|
+
node_item.save
|
76
|
+
}
|
77
|
+
end
|
78
|
+
if config[:chef_env]
|
79
|
+
change_chef_vars(instances){|node_item|
|
80
|
+
ui.msg "Changing #{node_item.name} chef environment to #{config[:chef_env]}"
|
81
|
+
node_item.chef_environment(config[:chef_env])
|
82
|
+
node_item.save
|
83
|
+
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
}
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'chef/knife/rax_cluster_base'
|
2
|
+
require 'chef/knife/rax_cluster_build'
|
3
|
+
|
4
|
+
class Chef
|
5
|
+
class Knife
|
6
|
+
class RaxClusterCreate < Knife
|
7
|
+
attr_accessor :headers, :rax_endpoint, :lb_name
|
8
|
+
include Knife::RaxClusterBase
|
9
|
+
banner "knife rax cluster create (cluster_name) [options]"
|
10
|
+
deps do
|
11
|
+
require 'fog'
|
12
|
+
require 'readline'
|
13
|
+
require 'chef/json_compat'
|
14
|
+
require 'chef/knife/bootstrap'
|
15
|
+
Chef::Knife::Bootstrap.load_deps
|
16
|
+
end
|
17
|
+
|
18
|
+
option :algorithm,
|
19
|
+
:short => "-a Load_balacner_algorithm",
|
20
|
+
:long => "--algorithm algorithm",
|
21
|
+
:description => "Load balancer algorithm",
|
22
|
+
:proc => Proc.new { |algorithm| Chef::Config[:knife][:algorithm] = algorithm },
|
23
|
+
:default => "ROUND_ROBIN"
|
24
|
+
|
25
|
+
option :blue_print,
|
26
|
+
:short => "-B Blue_print_file",
|
27
|
+
:long => "--map blue_print_file",
|
28
|
+
:description => "Path to blue Print json file",
|
29
|
+
:proc => Proc.new { |i| Chef::Config[:knife][:blue_print] = i.to_s }
|
30
|
+
|
31
|
+
option :port,
|
32
|
+
:short => "-lb_port port",
|
33
|
+
:long => "--load-balancer-port port",
|
34
|
+
:description => "Load balancer port",
|
35
|
+
:proc => Proc.new { |port| Chef::Config[:knife][:port] = port},
|
36
|
+
:default => "80"
|
37
|
+
|
38
|
+
option :timeout,
|
39
|
+
:short => "-t timeout",
|
40
|
+
:long => "--load-balancer-timeout timeout",
|
41
|
+
:description => "Load balancer timeout",
|
42
|
+
:proc => Proc.new { |timeout| Chef::Config[:knife][:timeout] = timeout},
|
43
|
+
:default => "30"
|
44
|
+
|
45
|
+
option :lb_region,
|
46
|
+
:short => "-r lb_region",
|
47
|
+
:long => "--load-balancer-region lb_region",
|
48
|
+
:description => "Load balancer region (only supports ORD || DFW)",
|
49
|
+
:proc => Proc.new { |lb_region| Chef::Config[:knife][:lb_region] = lb_region},
|
50
|
+
:default => "ORD"
|
51
|
+
|
52
|
+
option :protocol,
|
53
|
+
:short => "-p protocol",
|
54
|
+
:long => "--load-balancer-protocol protocol",
|
55
|
+
:description => "Load balancer protocol",
|
56
|
+
:proc => Proc.new { |protocol| Chef::Config[:knife][:protocol] = protocol},
|
57
|
+
:default => 'HTTP'
|
58
|
+
|
59
|
+
option :generate_map_template,
|
60
|
+
:short => "-G",
|
61
|
+
:long => "--generate_map_template",
|
62
|
+
:description => "Generate server map Template in current dir named map_template.json"
|
63
|
+
|
64
|
+
#option :session_persistence,
|
65
|
+
#:short => "-S on_or_off",
|
66
|
+
#:long => "--session-persistence session_persistence_on_or_off",
|
67
|
+
#:description => "Load balancer session persistence on or off",
|
68
|
+
#:proc => Proc.new { |session_persistence| Chef::Config[:knife][:session_persistence] = session_persistence}
|
69
|
+
|
70
|
+
def generate_map_template
|
71
|
+
file_name = "./map_template.json"
|
72
|
+
template = %q(
|
73
|
+
{
|
74
|
+
"blue_print" :
|
75
|
+
{
|
76
|
+
"name_convention" : "web",
|
77
|
+
"run_list" : [
|
78
|
+
"recipe[apt]"
|
79
|
+
],
|
80
|
+
"quantity" : 1,
|
81
|
+
"chef_env" : "dev",
|
82
|
+
"image_ref" : "a9753ff4-f46c-427d-9498-1358564f622f",
|
83
|
+
"flavor" : 2
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
}
|
88
|
+
)
|
89
|
+
|
90
|
+
File.open(file_name, 'w') { |file| file.write(template)}
|
91
|
+
end
|
92
|
+
def create_lb(instances)
|
93
|
+
lb_request = {
|
94
|
+
"loadBalancer" => {
|
95
|
+
"name" => @lb_name.to_s + "_cluster",
|
96
|
+
"port" => config[:port] || '80',
|
97
|
+
"protocol" => config[:protocol] || 'HTTP',
|
98
|
+
"algorithm" => config[:algorithm] || 'ROUND_ROBIN',
|
99
|
+
"virtualIps" => [
|
100
|
+
{
|
101
|
+
"type" => "PUBLIC"
|
102
|
+
}
|
103
|
+
],
|
104
|
+
"nodes" => [],
|
105
|
+
"metadata" => []
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
instances.each {|inst|
|
110
|
+
lb_request['loadBalancer']['nodes'] << {"address" => inst['ip_address'], 'port' =>Chef::Config[:knife][:port] || '80', "condition" => "ENABLED" }
|
111
|
+
lb_request['loadBalancer']['metadata'] << {"key" => inst['server_name'], "value" => inst['uuid']}
|
112
|
+
}
|
113
|
+
lb_authenticate = authenticate()
|
114
|
+
lb_url = ""
|
115
|
+
lb_authenticate['lb_urls'].each {|lb|
|
116
|
+
if config[:lb_region].to_s.downcase == lb['region'].to_s.downcase
|
117
|
+
lb_url = lb['publicURL']
|
118
|
+
break
|
119
|
+
end
|
120
|
+
lb_url = lb['publicURL']
|
121
|
+
}
|
122
|
+
lb_url = lb_url + "/loadbalancers"
|
123
|
+
|
124
|
+
headers = {'Content-type' => 'application/json', 'x-auth-token' => lb_authenticate['auth_token']}
|
125
|
+
create_lb_call = make_web_call("post",lb_url, headers, lb_request.to_json )
|
126
|
+
lb_details = JSON.parse(create_lb_call.body)
|
127
|
+
ui.msg "Load Balancer Cluster Sucesfully Created"
|
128
|
+
ui.msg "Load Balancer ID: #{lb_details['loadBalancer']['id']}"
|
129
|
+
ui.msg "Load Balancer Name: #{lb_details['loadBalancer']['name']}"
|
130
|
+
lb_ip = ""
|
131
|
+
lb_details['loadBalancer']['virtualIps'].each {|lb| (lb['ipVersion'] == "IPV4") ? lb_ip = lb['address'] : "not_found"}
|
132
|
+
ui.msg "Load Balancer IP Address: #{lb_ip}"
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def deploy(blue_print,update_cluster=nil)
|
137
|
+
(File.exist?(blue_print)) ? map_contents = JSON.parse(File.read(blue_print)) : map_contents = JSON.parse(blue_print)
|
138
|
+
sleep_interval = 1
|
139
|
+
instances = []
|
140
|
+
if map_contents.has_key?("blue_print")
|
141
|
+
bp_values = map_contents['blue_print']
|
142
|
+
bootstrap_nodes = []
|
143
|
+
quantity = bp_values['quantity'].to_i
|
144
|
+
quantity.times do |node_name|
|
145
|
+
node_name = rand(900000000)
|
146
|
+
create_server = Chef::Knife::RaxClusterBuild.new
|
147
|
+
#create_server.config[:identity_file] = config[:identity_file]
|
148
|
+
Chef::Config[:knife][:image] = bp_values['image_ref']
|
149
|
+
create_server.config[:chef_node_name] = bp_values['name_convention'] + node_name.to_s
|
150
|
+
create_server.config[:environment] = bp_values['chef_env']
|
151
|
+
Chef::Config[:environment] = bp_values['chef_env']
|
152
|
+
create_server.config[:run_list] = bp_values['run_list']
|
153
|
+
Chef::Config[:knife][:flavor] = bp_values['flavor']
|
154
|
+
begin
|
155
|
+
bootstrap_nodes << Thread.new { Thread.current['server_return'] = create_server.run }
|
156
|
+
rescue
|
157
|
+
ui.msg "Bootstrapping failed"
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
quantity.times do |times|
|
162
|
+
if quantity > 20
|
163
|
+
sleep_interval = 3
|
164
|
+
end
|
165
|
+
sleep(sleep_interval)
|
166
|
+
bootstrap_nodes[times].join
|
167
|
+
instances << {"server_name" => bootstrap_nodes[times]['server_return']['server_name'],
|
168
|
+
"ip_address" => bootstrap_nodes[times]['server_return']['private_ip'],
|
169
|
+
"uuid" => bootstrap_nodes[times]['server_return']['server_id'],
|
170
|
+
"name_convention" => bp_values['name_convention'],
|
171
|
+
"chef_env" => bp_values['chef_env'],
|
172
|
+
"run_list" => bp_values['run_list']
|
173
|
+
}
|
174
|
+
end
|
175
|
+
end
|
176
|
+
if update_cluster
|
177
|
+
return instances
|
178
|
+
else
|
179
|
+
create_lb(instances)
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
def run
|
187
|
+
#Generate template config
|
188
|
+
if config[:generate_map_template]
|
189
|
+
generate_map_template()
|
190
|
+
ui.msg "Map template saved as ./map_template.json"
|
191
|
+
exit()
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
if @name_args.empty? or @name_args.size > 1
|
196
|
+
ui.fatal "Please specify a single name for your cluster"
|
197
|
+
exit(1)
|
198
|
+
end
|
199
|
+
#Set load balancer name
|
200
|
+
@lb_name = @name_args[0]
|
201
|
+
|
202
|
+
if config[:blue_print]
|
203
|
+
deploy(config[:blue_print])
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'chef/knife/rax_cluster_base'
|
2
|
+
require 'chef/knife/rackspace_server_delete'
|
3
|
+
|
4
|
+
class Chef
|
5
|
+
class Knife
|
6
|
+
class RaxClusterDelete < Knife
|
7
|
+
attr_accessor :headers, :rax_endpoint, :lb_name
|
8
|
+
include Knife::RaxClusterBase
|
9
|
+
banner "knife rax cluster delete (load_balancer_id) [options]"
|
10
|
+
deps do
|
11
|
+
require 'fog'
|
12
|
+
require 'readline'
|
13
|
+
require 'chef/json_compat'
|
14
|
+
require 'chef/knife/bootstrap'
|
15
|
+
Chef::Knife::Bootstrap.load_deps
|
16
|
+
end
|
17
|
+
|
18
|
+
option :lb_region,
|
19
|
+
:short => "-r lb_region",
|
20
|
+
:long => "--load-balancer-region lb_region",
|
21
|
+
:description => "Load balancer region (only supports ORD || DFW)",
|
22
|
+
:proc => Proc.new { |lb_region| Chef::Config[:knife][:lb_region] = lb_region},
|
23
|
+
:default => "ORD"
|
24
|
+
|
25
|
+
def delete_cluster
|
26
|
+
lb_authenticate = authenticate()
|
27
|
+
lb_url = ""
|
28
|
+
puts config[:lb_region]
|
29
|
+
headers = {"x-auth-token" => lb_authenticate['auth_token'], "content-type" => "application/json"}
|
30
|
+
lb_authenticate['lb_urls'].each {|lb|
|
31
|
+
if config[:lb_region].to_s.downcase == lb['region'].to_s.downcase
|
32
|
+
lb_url = lb['publicURL']
|
33
|
+
break
|
34
|
+
end
|
35
|
+
lb_url = lb['publicURL']
|
36
|
+
}
|
37
|
+
@name_args.each {|arg|
|
38
|
+
server_uuids = []
|
39
|
+
lb_url = lb_url + "/loadbalancers/#{arg}"
|
40
|
+
get_uuids = make_web_call("get", lb_url, headers )
|
41
|
+
if get_uuids.code == '404'
|
42
|
+
ui.msg "Make sure you specify the -r flag to specify what region the LB is located"
|
43
|
+
exit(1)
|
44
|
+
end
|
45
|
+
lb_data = JSON.parse(get_uuids.body)
|
46
|
+
lb_data['loadBalancer']['metadata'].each{|meta|
|
47
|
+
server_uuids << {'uuid' => meta['value'], 'server_name' => meta['key'] }
|
48
|
+
}
|
49
|
+
server_uuids.each { |uuid|
|
50
|
+
rs_delete = RackspaceServerDelete.new
|
51
|
+
rs_delete.config[:yes] = 'yes'
|
52
|
+
rs_delete.name_args = [ uuid['uuid'] ]
|
53
|
+
rs_delete.config[:purge] = true
|
54
|
+
rs_delete.config[:chef_node_name] = uuid['server_name']
|
55
|
+
rs_delete.run
|
56
|
+
}
|
57
|
+
delete_lb_call = make_web_call("delete", lb_url, headers)
|
58
|
+
puts "Deleted loadbalancer id #{arg}"
|
59
|
+
|
60
|
+
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def run
|
65
|
+
if @name_args.empty?
|
66
|
+
ui.fatal "Please specify a Load balancer ID to delete"
|
67
|
+
end
|
68
|
+
ui.confirm("Are you sure you want to delete this Load balancer and ALL nodes associated with it?")
|
69
|
+
delete_cluster
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'chef/knife/rax_cluster_base'
|
2
|
+
require 'chef/knife/rackspace_server_delete'
|
3
|
+
|
4
|
+
class Chef
|
5
|
+
class Knife
|
6
|
+
class RaxClusterExpand < Knife
|
7
|
+
attr_accessor :headers, :rax_endpoint, :lb_id
|
8
|
+
include Knife::RaxClusterBase
|
9
|
+
banner "knife rax cluster expand (load_balancer_id) -B template_file.json"
|
10
|
+
deps do
|
11
|
+
require 'fog'
|
12
|
+
require 'readline'
|
13
|
+
require 'chef/json_compat'
|
14
|
+
require 'chef/knife/bootstrap'
|
15
|
+
Chef::Knife::Bootstrap.load_deps
|
16
|
+
end
|
17
|
+
|
18
|
+
option :blue_print,
|
19
|
+
:short => "-B Blue_print_file",
|
20
|
+
:long => "--map blue_print_file",
|
21
|
+
:description => "Path to blue Print json file",
|
22
|
+
:proc => Proc.new { |i| Chef::Config[:knife][:blue_print] = i.to_s }
|
23
|
+
|
24
|
+
option :port,
|
25
|
+
:short => "-lb_port port",
|
26
|
+
:long => "--load-balancer-port port",
|
27
|
+
:description => "Load balancer port",
|
28
|
+
:proc => Proc.new { |port| Chef::Config[:knife][:port] = port},
|
29
|
+
:default => "80"
|
30
|
+
|
31
|
+
option :lb_region,
|
32
|
+
:short => "-r lb_region",
|
33
|
+
:long => "--load-balancer-region lb_region",
|
34
|
+
:description => "Load balancer region (only supports ORD || DFW)",
|
35
|
+
:proc => Proc.new { |lb_region| Chef::Config[:knife][:lb_region] = lb_region},
|
36
|
+
:default => "ORD"
|
37
|
+
|
38
|
+
def expand_cluster
|
39
|
+
rs_cluster = RaxClusterCreate.new
|
40
|
+
rs_cluster.config[:blue_print] = config[:blue_print]
|
41
|
+
rs_cluster.lb_name = @name_args[0]
|
42
|
+
instance_return = rs_cluster.deploy(config[:blue_print],'update_cluster')
|
43
|
+
lb_auth = authenticate()
|
44
|
+
puts lb_auth['auth_token']
|
45
|
+
headers = {"x-auth-token" => lb_auth['auth_token'], "content-type" => "application/json"}
|
46
|
+
lb_url = ""
|
47
|
+
lb_auth['lb_urls'].each {|lb|
|
48
|
+
if config[:lb_region].to_s.downcase == lb['region'].to_s.downcase
|
49
|
+
lb_url = lb['publicURL']
|
50
|
+
break
|
51
|
+
end
|
52
|
+
lb_url = lb['publicURL']
|
53
|
+
}
|
54
|
+
meta_data_request = {
|
55
|
+
"metadata" => []
|
56
|
+
}
|
57
|
+
node_data_request = {
|
58
|
+
"nodes" => []
|
59
|
+
}
|
60
|
+
meta_url = lb_url + "/loadbalancers/#{@lb_id}/metadata"
|
61
|
+
node_url = lb_url + "/loadbalancers/#{@lb_id}/nodes"
|
62
|
+
|
63
|
+
instance_return.each {|inst|
|
64
|
+
node_data_request['nodes'] << {"address" => inst['ip_address'], 'port' =>Chef::Config[:knife][:port] || '80', "condition" => "ENABLED" }
|
65
|
+
meta_data_request['metadata'] << {"key" => inst['server_name'], "value" => inst['uuid']}
|
66
|
+
}
|
67
|
+
meta_request = make_web_call("post", meta_url, headers, meta_data_request.to_json)
|
68
|
+
lb_status = lb_url + "/loadbalancers/#{@lb_id}"
|
69
|
+
lb_stats = make_web_call("get", lb_status, headers)
|
70
|
+
lb_stats = JSON.parse(lb_stats.body)
|
71
|
+
|
72
|
+
while lb_stats['loadBalancer']['status'].to_s.downcase != 'active'
|
73
|
+
sleep(5)
|
74
|
+
lb_stats = make_web_call("get", lb_status, headers)
|
75
|
+
lb_stats = JSON.parse(lb_stats.body)
|
76
|
+
end
|
77
|
+
node_request = make_web_call("post", node_url, headers, node_data_request.to_json)
|
78
|
+
ui.msg "Load balancer id #{@lb_id} has been updated"
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
def run
|
83
|
+
if @name_args.empty?
|
84
|
+
ui.fatal "Please specify Load balancer ID to add nodes too"
|
85
|
+
exit(1)
|
86
|
+
end
|
87
|
+
if !config[:blue_print]
|
88
|
+
ui.fatal "Please specify a blue print file to parse with -B"
|
89
|
+
exit(1)
|
90
|
+
end
|
91
|
+
|
92
|
+
if config[:blue_print]
|
93
|
+
@lb_id = @name_args[0]
|
94
|
+
expand_cluster
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class Chef
|
2
|
+
class Knife
|
3
|
+
class RaxClusterList < Knife
|
4
|
+
attr_accessor :headers, :rax_endpoint, :lb_id
|
5
|
+
include Knife::RaxClusterBase
|
6
|
+
|
7
|
+
banner "knife rax cluster list -r lb_region"
|
8
|
+
deps do
|
9
|
+
require 'fog'
|
10
|
+
require 'readline'
|
11
|
+
require 'chef/json_compat'
|
12
|
+
require 'chef/knife/bootstrap'
|
13
|
+
Chef::Knife::Bootstrap.load_deps
|
14
|
+
end
|
15
|
+
|
16
|
+
option :lb_region,
|
17
|
+
:short => "-r lb_region",
|
18
|
+
:long => "--load-balancer-region lb_region",
|
19
|
+
:description => "Load balancer region (only supports ORD || DFW)",
|
20
|
+
:proc => Proc.new { |lb_region| Chef::Config[:knife][:lb_region] = lb_region},
|
21
|
+
:default => "ORD"
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
def run
|
26
|
+
lb_auth = authenticate
|
27
|
+
headers = {"x-auth-token" => lb_auth['auth_token'], "content-type" => "application/json"}
|
28
|
+
lb_url = ""
|
29
|
+
lb_auth['lb_urls'].each {|lb|
|
30
|
+
if config[:lb_region].to_s.downcase == lb['region'].to_s.downcase
|
31
|
+
lb_url = lb['publicURL']
|
32
|
+
break
|
33
|
+
end
|
34
|
+
lb_url = lb['publicURL']
|
35
|
+
}
|
36
|
+
lb_url = lb_url + "/loadbalancers"
|
37
|
+
lb_list = make_web_call("get", lb_url, headers)
|
38
|
+
lb_list = JSON.parse(lb_list.body)
|
39
|
+
lb_list['loadBalancers'].each {|lb|
|
40
|
+
if (lb['name'] =~ /_cluster/i)
|
41
|
+
msg_pair("LB Details for #{lb['name']}", " ")
|
42
|
+
msg_pair("\s\s\s\sLB ID", "#{lb['id']}")
|
43
|
+
msg_pair("\s\s\s\sLB Port", "#{lb['port']}")
|
44
|
+
msg_pair("\s\s\s\sLB Algorithm", "#{lb['algorithm']}")
|
45
|
+
msg_pair("\s\s\s\sLB Protocol", "#{lb['protocol']}")
|
46
|
+
msg_pair("\s\s\s\sLB Node Count", "#{lb['nodeCount']}")
|
47
|
+
ui.msg "\n\n"
|
48
|
+
end
|
49
|
+
}
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module MyKnifePlugins
|
2
|
+
# Make sure you subclass from Chef::Knife
|
3
|
+
class OverRide < Chef::Knife
|
4
|
+
|
5
|
+
|
6
|
+
banner "Cloud Builder"
|
7
|
+
deps do
|
8
|
+
|
9
|
+
require 'chef/knife/rackspace/rackspace_server_create'
|
10
|
+
require 'json'
|
11
|
+
require 'fog'
|
12
|
+
require "thread"
|
13
|
+
require 'chef/knife/rackspace/rackspace_base'
|
14
|
+
require 'net/ssh/multi'
|
15
|
+
require 'readline'
|
16
|
+
require 'chef/knife/bootstrap'
|
17
|
+
require 'chef/json_compat'
|
18
|
+
Chef::Knife::Bootstrap.load_deps
|
19
|
+
#include Knife::RackspaceBase
|
20
|
+
end
|
21
|
+
option :server_map,
|
22
|
+
:short => "-M MAP_File",
|
23
|
+
:long => "--map Map_File",
|
24
|
+
:description => "Path to Server Map json file",
|
25
|
+
:proc => Proc.new { |i| Chef::Config[:knife][:server_map] = i.to_s }
|
26
|
+
|
27
|
+
option :provider,
|
28
|
+
:short => "-P Provider",
|
29
|
+
:long => "--provider provider",
|
30
|
+
:description => "Specify RAX, open_stack",
|
31
|
+
:default => 'RAX'
|
32
|
+
#:proc => Proc.new { |i| Chef::Config[:knife][:server_map] = i.to_s }
|
33
|
+
|
34
|
+
option :generate_map_template,
|
35
|
+
:short => "-G",
|
36
|
+
:long => "--generate_map_template",
|
37
|
+
:description => "Generate server map Template in current dir named map_template.json"
|
38
|
+
|
39
|
+
#option :image,
|
40
|
+
#:short => "-I IMAGE",
|
41
|
+
#:long => "--image IMAGE",
|
42
|
+
#:description => "The image of the server",
|
43
|
+
#:proc => Proc.new { |i| Chef::Config[:knife][:image] = i.to_s }
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
# This method will be executed when you run this knife command.
|
49
|
+
def generate_map_template
|
50
|
+
file_name = "./map_template.json"
|
51
|
+
template = %q(
|
52
|
+
{
|
53
|
+
"servers" : [
|
54
|
+
{
|
55
|
+
"name_convention" : "web",
|
56
|
+
"run_list" : [
|
57
|
+
"role[base]",
|
58
|
+
"role[narciss]"
|
59
|
+
],
|
60
|
+
"quantity" : 2,
|
61
|
+
"chef_env" : "dev",
|
62
|
+
"image_ref" : "c195ef3b-9195-4474-b6f7-16e5bd86acd0",
|
63
|
+
"flavor" : 2
|
64
|
+
|
65
|
+
}
|
66
|
+
]
|
67
|
+
})
|
68
|
+
File.open(file_name, 'w') { |file| file.write(template)}
|
69
|
+
end
|
70
|
+
#Populates server_calls with map data
|
71
|
+
def parse_server_map(map_file)
|
72
|
+
map_contents = JSON.parse(File.read(map_file))
|
73
|
+
server_calls = {}
|
74
|
+
if map_contents.has_key?("servers")
|
75
|
+
for i in map_contents['servers']
|
76
|
+
server_calls[i['name_convention']] = {
|
77
|
+
"run_list" => i['run_list'] ,
|
78
|
+
"quantity" => i['quantity'], "chef_env" => i['chef_env'],
|
79
|
+
"image_ref" => i['image_ref']
|
80
|
+
}
|
81
|
+
#i['quantity'].times do
|
82
|
+
run_list = i['run_list'].join(', ')
|
83
|
+
#Thread.new {
|
84
|
+
create_server = Chef::Knife::RackspaceServerCreate.new
|
85
|
+
#create_server.config[:image] = i['image_ref']
|
86
|
+
Chef::Config[:knife][:image] = i['image_ref']
|
87
|
+
create_server.config[:server_name] = i['name_convention']
|
88
|
+
create_server.config[:environment] = i['chef_env']
|
89
|
+
create_server.config[:run_list] = i['run_list']
|
90
|
+
#create_server.config[:flavor] = i['flavor']
|
91
|
+
Chef::Config[:knife][:flavor] = i['flavor']
|
92
|
+
create_server.run
|
93
|
+
##}
|
94
|
+
#end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
else
|
99
|
+
ui.fatal "JSON file incorrect format"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def launch_build
|
105
|
+
yield
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
def run
|
110
|
+
#Generate template config
|
111
|
+
if config[:generate_map_template]
|
112
|
+
generate_map_template()
|
113
|
+
end
|
114
|
+
#Parses Map and takes action
|
115
|
+
if config[:server_map]
|
116
|
+
parse_server_map(config[:server_map])
|
117
|
+
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knife-rackspace-cluster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.2
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- zack feldstein
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2013-02-19 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: knife-rackspace
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: fog
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - "="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.8.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
description: Creates rax clusters
|
38
|
+
email: zack.feldstein@rackspace.com
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- lib/chef/knife/rax_cluster_base.rb
|
47
|
+
- lib/chef/knife/rax_cluster_build.rb
|
48
|
+
- lib/chef/knife/rax_cluster_change.rb
|
49
|
+
- lib/chef/knife/rax_cluster_create.rb
|
50
|
+
- lib/chef/knife/rax_cluster_delete.rb
|
51
|
+
- lib/chef/knife/rax_cluster_expand.rb
|
52
|
+
- lib/chef/knife/rax_cluster_list.rb
|
53
|
+
- lib/chef/knife/super_rax.rb
|
54
|
+
homepage: http://github.com/jrcloud/knife_rax_cluster
|
55
|
+
licenses: []
|
56
|
+
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.8.23
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Knife rax cluster
|
81
|
+
test_files: []
|
82
|
+
|