Class: McServer

Inherits:
Server show all
Extended by:
RightScale::Api::GatewayExtend, RightScale::Api::McTaggableExtend
Includes:
RightScale::Api::Gateway, RightScale::Api::McTaggable
Defined in:
lib/rest_connection/rightscale/mc_server.rb

Overview

– Copyright © 2010-2012 RightScale Inc

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++

API 1.5

Constant Summary

Constants included from SshHax

SshHax::SSH_RETRY_COUNT

Instance Attribute Summary collapse

Attributes included from RightScale::Api::Base

#params

Attributes inherited from Server

#internal

Class Method Summary collapse

Instance Method Summary collapse

Methods included from RightScale::Api::GatewayExtend

create, filters, find, find_all, find_by, find_with_filter, load, load_all, parse_args, resource_post_name

Methods included from RightScale::Api::GatewayConnection

#connection

Methods included from RightScale::Api::BaseExtend

#[], #create, #deny_methods, #filters, #find, #find_all, #find_by, #find_by_cloud_id, #find_by_id, #find_by_nickname, #find_by_nickname_speed, #find_with_filter

Methods included from RightScale::Api::BaseConnection

#connection

Methods included from RightScale::Api::McTaggableExtend

find_by_tags

Methods included from RightScale::Api::McTaggable

#tags

Methods included from RightScale::Api::Taggable

#get_info_tags, #remove_info_tags, #remove_tags_by_namespace, #set_info_tags, #set_tags_by_namespace, #set_tags_to, #tags

Methods included from RightScale::Api::Gateway

#[], #[]=, #actions, #hash_of_links, #href, #initialize, #load, #method_missing, #nickname, #parse_params, #rediscover

Methods included from RightScale::Api::Base

#[], #[]=, #destroy, #initialize, #method_missing, #reload, #rs_id

Methods inherited from Server

#alert_specs, #attach_volume, #audit_link, create, #force_stop, #initialize, #lock, #parameters, #reachable_ip, #reboot, #run_executable_and_wait_for_completed, #run_script, #set_inputs, #set_template, #start_ebs, #stop_ebs, #tags, #transform_parameters, #unlock, #wait_for_operational_with_dns, #wait_for_state, #wait_for_state_change

Methods included from RightScale::Api::TaggableExtend

#find_by_tags

Methods included from SshHax

#spot_check, #spot_check_command, #spot_check_command?, #ssh_key_config

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class RightScale::Api::Gateway

Instance Attribute Details

#current_instanceObject

Returns the value of attribute current_instance.



31
32
33
# File 'lib/rest_connection/rightscale/mc_server.rb', line 31

def current_instance
  @current_instance
end

#inputsObject

Returns the value of attribute inputs.



31
32
33
# File 'lib/rest_connection/rightscale/mc_server.rb', line 31

def inputs
  @inputs
end

#next_instanceObject

Returns the value of attribute next_instance.



31
32
33
# File 'lib/rest_connection/rightscale/mc_server.rb', line 31

def next_instance
  @next_instance
end

Class Method Details

.filtersObject



53
54
55
# File 'lib/rest_connection/rightscale/mc_server.rb', line 53

def self.filters
  [:deployment_href, :name]
end

.parse_args(deployment_id = nil) ⇒ Object



49
50
51
# File 'lib/rest_connection/rightscale/mc_server.rb', line 49

def self.parse_args(deployment_id=nil)
  deployment_id ? "deployments/#{deployment_id}/" : ""
end

.resource_plural_nameObject



41
42
43
# File 'lib/rest_connection/rightscale/mc_server.rb', line 41

def self.resource_plural_name
  "servers"
end

.resource_singular_nameObject



45
46
47
# File 'lib/rest_connection/rightscale/mc_server.rb', line 45

def self.resource_singular_name
  "server"
end

Instance Method Details

#add_tags(*args) ⇒ Object



315
316
317
318
319
320
321
# File 'lib/rest_connection/rightscale/mc_server.rb', line 315

def add_tags(*args)
  return false if args.empty?
  args.uniq!
  McTag.set(self.href, args)
  McTag.set(self.current_instance_href, args) if @current_instance
  self.tags(true)
end

#clear_tags(namespace = nil) ⇒ Object



347
348
349
350
351
352
# File 'lib/rest_connection/rightscale/mc_server.rb', line 347

def clear_tags(namespace = nil)
  tags = self.tags(true)
  tags.deep_merge! self.current_tags if @current_instance
  tags = tags.select { |tag| tag.start_with?("#{namespace}:") } if namespace
  self.remove_tags(*tags)
end

#cloud_idObject



254
255
256
257
258
259
# File 'lib/rest_connection/rightscale/mc_server.rb', line 254

def cloud_id
  settings unless @next_instance
  cloud_href = @current_instance.hash_of_links["cloud"] if @current_instance
  cloud_href = @next_instance.hash_of_links["cloud"] unless cloud_href
  return cloud_href.split("/").last.to_i
end

#current_instance_hrefObject



250
251
252
# File 'lib/rest_connection/rightscale/mc_server.rb', line 250

def current_instance_href
  hash_of_links["current_instance"]
end

#current_tags(reload = true) ⇒ Object

Override Taggable mixin so that it sets tags on both next and current instances



307
308
309
310
311
312
313
# File 'lib/rest_connection/rightscale/mc_server.rb', line 307

def current_tags(reload=true)
  ret = []
  if @current_instance
    ret = McTag.search_by_href(self.current_instance_href).first["tags"].map { |h| h["name"] }
  end
  ret
end

#deployment_hrefObject



246
247
248
# File 'lib/rest_connection/rightscale/mc_server.rb', line 246

def deployment_href
  hash_of_links["deployment"]
end

#dns_nameObject



261
262
263
264
265
266
267
268
269
270
# File 'lib/rest_connection/rightscale/mc_server.rb', line 261

def dns_name
  self.settings
  ret = nil
  if @current_instance
    ret ||= @current_instance.public_ip_addresses.first
    ret ||= @current_instance.public_dns_names.first
    ret ||= get_tags_by_namespace("server")["current_instance"]["public_ip_0"]
  end
  ret
end

#force_terminateObject



149
150
151
152
153
154
# File 'lib/rest_connection/rightscale/mc_server.rb', line 149

def force_terminate
  t = URI.parse(self.href)
  connection.post(t.path + '/terminate')
  connection.post(t.path + '/terminate')
  @current_instance = nil
end

#get_sketchy_data(params) ⇒ Object



300
301
302
303
304
# File 'lib/rest_connection/rightscale/mc_server.rb', line 300

def get_sketchy_data(params)
  settings
  raise "No current instance found!" unless @current_instance
  @current_instance.get_sketchy_data(params)
end

#get_tags_by_namespace(namespace) ⇒ Object



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/rest_connection/rightscale/mc_server.rb', line 331

def get_tags_by_namespace(namespace)
  ret = {}
  tags = {"self" => self.tags(true)}
  tags["current_instance"] = self.current_tags if @current_instance
  tags.each { |res,ary|
    ret[res] ||= {}
    ary.each { |tag|
      next unless tag.start_with?("#{namespace}:")
      key = tag.split("=").first.split(":")[1..-1].join(":")
      value = tag.split(":")[1..-1].join(":").split("=")[1..-1].join("=")
      ret[res][key] = value
    }
  }
  return ret
end

#launchObject



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/rest_connection/rightscale/mc_server.rb', line 57

def launch
  if actions.include?("launch")
    t = URI.parse(self.href)
    begin
      connection.post(t.path + '/launch')
    rescue Exception => e
      if connection.settings[:azure_hack_on]
        puts "**** [AZURE_HACK is ON] - McServer.launch() nickname: #{nickname}, caught exception #{e.message}"
        puts "**** connection.settings[:azure_hack_retry_count] = #{connection.settings[:azure_hack_retry_count]}"
        puts "**** connection.settings[:azure_hack_sleep_seconds] = #{connection.settings[:azure_hack_sleep_seconds]}"

        # 504 Gateway should always be treated as a successful launch
        target_504_gateway_timeout_error_message = "504 Gateway Time-out"

        # All 422 exceptions should be retried
        target_422_error_message = "Invalid response HTTP code: 422:"

        if e.message =~ /#{target_504_gateway_timeout_error_message}/
          exception_matched_message = "**** McServer.launch(): Caught #{e.message}, treating as a successful launch..."
          puts(exception_matched_message)
          connection.logger(exception_matched_message)
          true
        elsif e.message =~ /#{target_422_error_message}/
          azure_hack_retry_count = connection.settings[:azure_hack_retry_count]
          exception_matched_message = "**** McServer.launch(): Caught #{e.message}, retrying launch..."
          puts(exception_matched_message)
          connection.logger(exception_matched_message)

          retry_count = 1
          loop do
            # sleep for azure_hack_sleep_seconds seconds
            sleep_message = "**** McServer.launch(): Sleeping for #{connection.settings[:azure_hack_sleep_seconds]} seconds and then retrying (#{retry_count}) launch..."
            puts(sleep_message)
            connection.logger(sleep_message)
            sleep(connection.settings[:azure_hack_sleep_seconds])

            # retry the launch
            begin
              connection.post(t.path + '/launch')
            rescue Exception => e2
              exception_caught_message = "**** McServer.launch(): Retry caught #{e2.message}..."
              puts(exception_caught_message)
              connection.logger(exception_caught_message)

              if e2.message =~ /#{target_422_error_message}/
                azure_hack_retry_count -= 1
                if azure_hack_retry_count > 0
                  retry_count += 1

                  # Try again on next iteration
                  next
                else
                  # Azure Hack maximum retries exceeded so rethrow the new 422 exception
                  raise
                end
              else
                # On this re-launch we got some other exception so rethrow it
                raise
              end
            end

            # Fell through so launch worked and we need to break out of the retry do loop
            break
          end
        else
          # Didn't match on any target exception so rethrow the original exception
          raise
        end
      else
        # Azure Hack isn't enabled so rethrow the original exception
        raise
      end
    end
  elsif self.state == "inactive"
    raise "FATAL: Server is in an unlaunchable state!"
  else
    connection.logger("WARNING: was in #{self.state} so skipping launch call")
  end
end

#monitoringObject



220
221
222
223
224
# File 'lib/rest_connection/rightscale/mc_server.rb', line 220

def monitoring
  ret = @current_instance.fetch_monitoring_metrics
  raise "FATAL: Monitoring not available!" if ret.empty?
  ret
end

#private_ipObject



272
273
274
275
276
277
278
279
280
281
# File 'lib/rest_connection/rightscale/mc_server.rb', line 272

def private_ip
  self.settings
  ret = nil
  if @current_instance
    ret ||= @current_instance.private_ip_addresses.first
    ret ||= @current_instance.private_dns_names.first
    ret ||= get_tags_by_namespace("server")["current_instance"]["private_ip_0"]
  end
  ret
end

#relaunch(timeout = 1200) ⇒ Object

*timeout <~Integer> optional, how long to wait for the inactive state before declare failure (in seconds).



227
228
229
230
231
# File 'lib/rest_connection/rightscale/mc_server.rb', line 227

def relaunch(timeout=1200)
  self.terminate
  self.wait_for_state("inactive", timeout)
  self.launch
end

#reload_as_currentObject



292
293
294
# File 'lib/rest_connection/rightscale/mc_server.rb', line 292

def reload_as_current
  settings # Gets all instance (including current) information
end

#reload_as_nextObject



296
297
298
# File 'lib/rest_connection/rightscale/mc_server.rb', line 296

def reload_as_next
  settings # Gets all instance (including current) information
end

#remove_tags(*args) ⇒ Object



323
324
325
326
327
328
329
# File 'lib/rest_connection/rightscale/mc_server.rb', line 323

def remove_tags(*args)
  return false if args.empty?
  args.uniq!
  McTag.unset(self.href, args)
  McTag.unset(self.current_instance_href, args) if @current_instance
  self.tags(true)
end

#resource_plural_nameObject



33
34
35
# File 'lib/rest_connection/rightscale/mc_server.rb', line 33

def resource_plural_name
  "servers"
end

#resource_singular_nameObject



37
38
39
# File 'lib/rest_connection/rightscale/mc_server.rb', line 37

def resource_singular_name
  "server"
end

#run_executable(executable, opts = nil, ignore_lock = false) ⇒ Object



164
165
166
167
# File 'lib/rest_connection/rightscale/mc_server.rb', line 164

def run_executable(executable, opts=nil, ignore_lock=false)
  raise "Instance isn't running; Can't run executable" unless @current_instance
  @current_instance.run_executable(executable, opts, ignore_lock)
end

#saveObject



283
284
285
# File 'lib/rest_connection/rightscale/mc_server.rb', line 283

def save
  update
end

#server_template_hrefObject



238
239
240
241
242
243
244
# File 'lib/rest_connection/rightscale/mc_server.rb', line 238

def server_template_href
  if @current_instance
    return @current_instance.server_template
  end
  self.settings unless @next_instance
  return @next_instance.server_template
end

#server_typeObject

Attributes taken for granted in API 1.0



234
235
236
# File 'lib/rest_connection/rightscale/mc_server.rb', line 234

def server_type
  "gateway"
end

#set_current_inputs(hash = {}) ⇒ Object



197
198
199
200
# File 'lib/rest_connection/rightscale/mc_server.rb', line 197

def set_current_inputs(hash = {})
  settings unless @next_instance
  @current_instance.multi_update(transform_inputs(:to_a, hash)) if @current_instance
end

#set_input(name, value) ⇒ Object



191
192
193
194
195
# File 'lib/rest_connection/rightscale/mc_server.rb', line 191

def set_input(name, value)
  settings unless @next_instance
  @current_instance.multi_update([{'name' => name, 'value' => value}]) if @current_instance
  @next_instance.multi_update([{'name' => name, 'value' => value}])
end

#set_next_inputs(hash = {}) ⇒ Object



202
203
204
205
# File 'lib/rest_connection/rightscale/mc_server.rb', line 202

def set_next_inputs(hash = {})
  settings unless @next_instance
  @next_instance.multi_update(transform_inputs(:to_a, hash))
end

#settingsObject

show



208
209
210
211
212
213
214
215
216
217
218
# File 'lib/rest_connection/rightscale/mc_server.rb', line 208

def settings #show
  serv_href = URI.parse(self.href)
  @params = connection.get(serv_href.path, 'view' => 'instance_detail')
  if self['current_instance']
    @current_instance = McInstance.new(self['current_instance'])
    @current_instance.show
  end
  @next_instance = McInstance.new(self['next_instance'])
  @next_instance.show
  @params
end

#startObject

start_ebs



156
157
158
# File 'lib/rest_connection/rightscale/mc_server.rb', line 156

def start #start_ebs
  raise "You shouldn't be here."
end

#stopObject

stop_ebs



160
161
162
# File 'lib/rest_connection/rightscale/mc_server.rb', line 160

def stop #stop_ebs
  raise "You shouldn't be here."
end

#terminateObject



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/rest_connection/rightscale/mc_server.rb', line 137

def terminate
  if actions.include?("terminate")
    t = URI.parse(self.href)
    connection.post(t.path + '/terminate')
    @current_instance = nil
#    elsif self.state != "inactive"
#      raise "FATAL: Server is in an interminable state!"
  else
    connection.logger("WARNING: was in #{self.state} so skipping terminate call")
  end
end

#transform_inputs(sym, parameters) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
# File 'lib/rest_connection/rightscale/mc_server.rb', line 169

def transform_inputs(sym, parameters)
  ret = nil
  if parameters.is_a?(Array) and sym == :to_h
    ret = {}
    parameters.each { |hash| ret[hash['name']] = hash['value'] }
  elsif parameters.is_a?(Hash) and sym == :to_a
    ret = []
    parameters.each { |key,val| ret << {'name' => key, 'value' => val} }
  end
  ret
end

#updateObject



287
288
289
290
# File 'lib/rest_connection/rightscale/mc_server.rb', line 287

def update
  @next_instance.update
  @current_instance.update if @current_instance
end