Class: KnifeCloudstack::CsStackCreate

Inherits:
Chef::Knife
  • Object
show all
Defined in:
lib/chef/knife/cs_stack_create.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#current_stackObject

Returns the value of attribute current_stack.



24
25
26
# File 'lib/chef/knife/cs_stack_create.rb', line 24

def current_stack
  @current_stack
end

Instance Method Details

#connectionObject



88
89
90
91
92
93
94
95
96
# File 'lib/chef/knife/cs_stack_create.rb', line 88

def connection
  if (!@connection) then
    url = locate_config_value(:cloudstack_url)
    api_key = locate_config_value(:cloudstack_api_key)
    secret_key = locate_config_value(:cloudstack_secret_key)
    @connection = CloudstackClient::Connection.new(url, api_key, secret_key)
  end
  @connection
end

#create_server(server) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/chef/knife/cs_stack_create.rb', line 120

def create_server(server)

  cmd = KnifeCloudstack::CsServerCreate.new([server[:name]])

  # configure and run command
  # TODO: validate parameters
  cmd.config[:ssh_user] = config[:ssh_user]
  cmd.config[:ssh_password] = config[:ssh_password]
  cmd.config[:ssh_port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port]
  cmd.config[:identity_file] = config[:identity_file]
  cmd.config[:cloudstack_template] = server[:template] if server[:template]
  cmd.config[:cloudstack_service] = server[:service] if server[:service]
  cmd.config[:cloudstack_zone] = server[:service] if server[:zone]
  cmd.config[:cloudstack_networks] = server[:networks].split(/[\s,]+/) if server[:networks]
  cmd.config[:run_list] = server[:run_list].split(/[\s,]+/) if server[:run_list]
  cmd.config[:port_rules] = server[:port_rules].split(/[\s,]+/) if server[:port_rules]
  if current_stack[:environment]
    cmd.config[:environment] = current_stack[:environment]
    Chef::Config[:environment] = current_stack[:environment]
  end

  cmd.run_with_pretty_exceptions

end

#create_stack(stack) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/chef/knife/cs_stack_create.rb', line 98

def create_stack(stack)
  @current_stack = Mash.new(stack)
  current_stack[:servers].each do |server|
    if server[:name]

      # create server(s)
      names = server[:name].split(/[\s,]+/)
      names.each do |n|
        s = Mash.new(server)
        s[:name] = n
        create_server(s)
      end

    end

    # execute actions
    run_actions server[:actions]
  end

  print_local_hosts
end

#destroy_all(domain, excludes = []) ⇒ Object



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/chef/knife/cs_stack_create.rb', line 284

def destroy_all(domain, excludes=[])
  servers = connection.list_servers || []
  servers.each do |s|
    excluded = false
    excludes.each { |val|
      if s['name'] =~ /#{val}/ then
        excluded = true
        next
      end
    }
    next if excluded
    nodename = "#{s['name']}.#{domain}"
    system "knife cs server delete #{s['name']} -y"
    system "knife client delete #{nodename} -y"
    system "knife node delete #{nodename} -y"
  end
end

#find_public_ips(query) ⇒ Object



256
257
258
259
260
261
262
263
# File 'lib/chef/knife/cs_stack_create.rb', line 256

def find_public_ips(query)
  hostnames = search_nodes(query, 'hostname')
  puts "Found hostnames: #{hostnames.inspect}"
  ips = hostnames.map { |h|
    public_ip_for_host h
  }
  ips.compact.uniq
end

#get_environmentObject



280
281
282
# File 'lib/chef/knife/cs_stack_create.rb', line 280

def get_environment
  current_stack[:environment]
end

#http_request(url) ⇒ Object



233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/chef/knife/cs_stack_create.rb', line 233

def http_request(url)
  match_data = /\$\{([a-zA-Z0-9-]+)\}/.match url
  if match_data
    server_name = match_data[1]
    ip = public_ip_for_host(server_name)
    url = url.sub(/\$\{#{server_name}\}/, ip)
  end


  puts "HTTP Request: #{url}"
  puts `curl -s -m 5 #{url}`
end

#knife_ssh(host_list, command) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/chef/knife/cs_stack_create.rb', line 194

def knife_ssh(host_list, command)

  ssh = Chef::Knife::Ssh.new
  ssh.name_args = [host_list, command]
  ssh.config[:ssh_user] = config[:ssh_user]
  ssh.config[:ssh_password] = config[:ssh_password]
  ssh.config[:ssh_port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port]
  ssh.config[:identity_file] = config[:identity_file]
  ssh.config[:manual] = true
  ssh.config[:no_host_key_verify] = config[:no_host_key_verify]
  ssh
end

#knife_ssh_action(query, command) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/chef/knife/cs_stack_create.rb', line 214

def knife_ssh_action(query, command)

  public_ips = find_public_ips(query)
  return if public_ips.nil? || public_ips.empty?
  host_list = public_ips.join(' ')

  ssh = knife_ssh(host_list, command)
  begin
    ssh.run
  rescue Net::SSH::AuthenticationFailed
    unless config[:ssh_password]
      puts "Failed to authenticate #{config[:ssh_user]} - trying password auth"
      ssh = knife_ssh_with_password_auth(host_list, command)
      ssh.run
    end
  end

end

#knife_ssh_with_password_auth(host_list, command) ⇒ Object



207
208
209
210
211
212
# File 'lib/chef/knife/cs_stack_create.rb', line 207

def knife_ssh_with_password_auth(host_list, command)
  ssh = knife_ssh(host_list, command)
  ssh.config[:identity_file] = nil
  ssh.config[:ssh_password] = ssh.get_password
  ssh
end

#locate_config_value(key) ⇒ Object



319
320
321
322
# File 'lib/chef/knife/cs_stack_create.rb', line 319

def locate_config_value(key)
  key = key.to_sym
  Chef::Config[:knife][key] || config[key]
end


302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/chef/knife/cs_stack_create.rb', line 302

def print_local_hosts
  hosts = []
  current_stack[:servers].each do |server|
    next unless server[:local_hosts]
    name = server[:name].split(' ').first
    ip = public_ip_for_host(name)
    server[:local_hosts].each { |host|
      hostname = host.sub(/\$\{environment\}/, get_environment)
      hosts << "#{ip}    #{hostname}"
    }
  end
  unless hosts.empty?
    puts "\nAdd this to your /etc/hosts file:"
    puts hosts.join("\n")
  end
end

#public_ip_for_host(name) ⇒ Object



265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/chef/knife/cs_stack_create.rb', line 265

def public_ip_for_host(name)
  return nil unless name
  @public_ip_cache ||= {}

  if !@public_ip_cache[name] then
    server = connection.get_server(name)
    return nil unless server

    ip = connection.get_server_public_ip(server)
    @public_ip_cache[name] = ip if ip
  end

  @public_ip_cache[name]
end

#runObject



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/chef/knife/cs_stack_create.rb', line 74

def run
  file_path = File.expand_path(@name_args.first)
  unless File.exist?(file_path) then
    ui.error "Stack file '#{file_path}' not found. Please check the path."
    exit 1
  end

  data = File.read file_path
  stack = Chef::JSONCompat.from_json data
  create_stack stack

  #puts "Stack: #{stack.inspect}"
end

#run_actions(actions) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/chef/knife/cs_stack_create.rb', line 145

def run_actions(actions)
  puts "\n"
  ui.msg("Processing actions...")
  sleep 1 # pause for e.g. chef solr indexing
  actions ||= []
  actions.each do |cmd|
    cmd ||= {}
    cmd.each do |name, args|
      case name
        when 'knife_ssh'
          knife_ssh_action(*args)
        when 'http_request'
          http_request(args)
        when 'run_list_remove'
          run_list_remove(*args)
        when 'sleep'
          dur = args || 5
          sleep dur
      end
    end
  end

end

#run_list_remove(query, entry) ⇒ Object



246
247
248
249
250
251
252
253
254
# File 'lib/chef/knife/cs_stack_create.rb', line 246

def run_list_remove(query, entry)
  nodes = search_nodes(query)
  return unless nodes

  nodes.each do |n|
    cmd = Chef::Knife::NodeRunListRemove.new([n.name, entry])
    cmd.run_with_pretty_exceptions
  end
end

#search_nodes(query, attribute = nil) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/chef/knife/cs_stack_create.rb', line 169

def search_nodes(query, attribute=nil)
  if get_environment
    query = "(#{query})" + " AND chef_environment:#{get_environment}"
  end

  Chef::Log.debug("Searching for nodes: #{query}")

  q = Chef::Search::Query.new
  nodes = Array(q.search(:node, query))

  # the array of nodes is the first item in the array returned by the search
  if nodes.length > 1
    nodes = nodes.first || []
  end

  # return attribute values instead of nodes
  if attribute
    nodes.map do |node|
      node[attribute.to_s]
    end
  else
    nodes
  end
end