Module: Smash::CloudPowers::SelfAwareness

Extended by:
Helper, Smash::CloudPowers::Synapse::Pipe, Smash::CloudPowers::Synapse::Queue, Zenv
Includes:
AwsResources
Included in:
Smash::CloudPowers, Node
Defined in:
lib/cloud_powers/self_awareness.rb

Instance Method Summary collapse

Methods included from Helper

attr_map!, available_resources, called_from, create_logger, deep_modify_keys_with, format_error_message, log_file, logger, modify_keys_with, smart_retry, task_exist?, task_home, task_path, task_require_path, to_camel, to_hyph, to_i_var, to_pascal, to_ruby_file_name, to_snake, update_message_body, valid_json?, valid_url?

Methods included from Smash::CloudPowers::Synapse::Pipe

create_stream, flow_from_pipe, flow_to_pipe, from_pipe, message_body_collection, pipe_message_body, pipe_to, stream_config, stream_exists?, stream_status

Methods included from Zenv

env_vars, file_tree_search, i_vars, project_root, project_root=, system_vars, zfind

Methods included from AwsResources

#ec2, #image, #kinesis, #region, #s3, #sns, #sqs

Methods included from Auth

creds, region

Methods included from Smash::CloudPowers::Synapse::Queue

board_name, build_queue, create_queue!, delete_queue_message, get_queue_message_count, pluck_queue_message, poll, queue_exists?, queue_poller, queue_search, send_queue_message

Instance Method Details

#boot_timeObject

Gets the instance time or the time it was called and as seconds from epoch

Returns Integer

Notes

  • TODO: use time codes



26
27
28
29
30
31
32
33
34
35
# File 'lib/cloud_powers/self_awareness.rb', line 26

def boot_time
  begin
    @boot_time ||=
      ec2.describe_instances(dry_run: zfind(:testing), instance_ids:[instance_id]).
        reservations[0].instances[0].launch_time.to_i
  rescue Aws::EC2::Errors::DryRunOperation
    logger.info "dry run for testing: #{e}"
    @boot_time ||= Time.now.to_i # comment the code below for development mode
  end
end

#die!Object

Send a status message on the status Pipe then terminates the instance.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/cloud_powers/self_awareness.rb', line 38

def die!
  Thread.kill(@status_thread) unless @status_thread.nil?
  # blame = errors.sort_by(&:reverse).last.first
  logger.info("The cause for the shutdown is TODO: fix SmashErrors")

  pipe_to(:status_stream) do
    {
      instanceID: @instance_id,
      type: 'status-update',
      content: 'dying'
      # extraInfo: blame
    }
  end

  [:count, :wip].each do |queue|
    delete_queue_message(queue, max_number_of_messages: 1)
  end
  send_logs_to_s3
  begin
    ec2.terminate_instances(dry_run: zfind('testing'), ids: [@instance_id])
  rescue Aws::EC2::Error::DryRunOperation
    logger.info "dry run testing in die! #{format_error_message(e)}"
    @instance_id
  end
end

#get_awareness!Object

Get resource metadata, public host, boot time and task name and set them as instance variables

Returns Array of values, each from a separate key, set in the order in the Array

Notes

  • See #metadata_request()

  • See #attr_map!()



74
75
76
77
78
79
80
# File 'lib/cloud_powers/self_awareness.rb', line 74

def get_awareness!
  keys = 
  attr_map!(keys) { |key| (key) }
  boot_time # gets and sets @boot_time
  task_name # gets and sets @task_name
  instance_url # gets and sets @instance_url
end

#instance_idObject

Assures there is always a valid instance id because many other Aws calls require it

Returns String



86
87
88
# File 'lib/cloud_powers/self_awareness.rb', line 86

def instance_id
  @instance_id ||= ('instance_id')
end

#instance_urlObject

Gets and sets the public hostname of the instance

Returns String - the Public Hostname for this instance

Notes

  • When this is being called from somewhere other than an Aws instance, a hardcoded example URL is returned because of the way instance metadata is retrieved



98
99
100
101
102
103
104
105
# File 'lib/cloud_powers/self_awareness.rb', line 98

def instance_url
  @instance_url ||= unless zfind('TESTING')
    hostname_uri = 'http://169.254.169.254/latest/meta-data/public-hostname'
    HTTParty.get(hostname_uri).parsed_response
  else
    'http://ec2-000-0-000-00.compute-0.amazonaws.com'
  end
end

#metadata_request(key = '') ⇒ Object

Makes the http request to self/meta-data to get all the metadata keys or, if a key is given, the method makes the http request to get that particular key from the metadata

Parameters

  • key String (optional) (default is ”) - the key for the metadata information you want from this instance.

Returns

  • Array if key is blank

  • String if key is given

Example


# => a +Hash+ containing every key => value pair AWS provides
('instance-id')
# => 'abc-1234'


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/cloud_powers/self_awareness.rb', line 124

def (key = '')
  key = to_hyph(key)
  begin
    unless zfind('TESTING')
       = "http://169.254.169.254/latest/meta-data/#{key}"
      HTTParty.get().parsed_response.split("\n")
    else
       = Smash::CloudPowers::AwsStubs.

      key.empty? ? .keys : [to_hyph(key)]
    end
  rescue Exception => e
    logger.fatal format_error_message e
  end
end

#run_timeObject

Return the time since boot_time

Returns Integer

Notes

  • TODO: refactor to use valid time stamps for better tracking.

  • reason -> separate regions or OSs etc.



148
149
150
# File 'lib/cloud_powers/self_awareness.rb', line 148

def run_time
  Time.now.to_i - boot_time
end

#send_frequent_status_updates(opts = {}) ⇒ Object

Send a message on a Pipe at an interval

Parameters

  • opts Hash (optional)

    • :interval - how long to wait between sending updates

    • :stream_name - name of stream you want to use



158
159
160
161
162
163
164
165
166
167
# File 'lib/cloud_powers/self_awareness.rb', line 158

def send_frequent_status_updates(opts = {})
  sleep_time = opts.delete(:interval) || 10
  stream = opts.delete(:stream_name)
  while true
    message = lambda { |o| update_message_body(o.merge(content: status)) }
    logger.info "Send update to status board #{message.call(opts)}"
    pipe_to(stream || :status_stream) { message.call(opts) }
    sleep sleep_time
  end
end

#status(id = @instance_id) ⇒ Object

Get the instance status.

Parameters

  • id String (optional) (default is @instance_id)

Returns String



175
176
177
178
179
180
181
182
183
# File 'lib/cloud_powers/self_awareness.rb', line 175

def status(id = @instance_id)
  begin
    ec2.describe_instances(dry_run: zfind('TESTING'), instance_ids: [id]).
      reservations[0].instances[0].state.name
  rescue Aws::EC2::Errors::DryRunOperation
    logger.info "Dry run flag set for testing: #{e}"
    'testing'
  end
end

#task_name(id = @instance_id) ⇒ Object

Check self-tags for ‘task’ and act as an attr_accessor. A different node’s tag’s can be checked for a task by passing that instance’s id as a parameter

Parameters

  • id String (optional) (default is @instance_id) - instance you want a tag from

Returns String



194
195
196
197
198
199
200
201
202
203
204
# File 'lib/cloud_powers/self_awareness.rb', line 194

def task_name(id = @instance_id)
  # get @task_name
  return @task_name unless @task_name.nil?
  # set @task_name
  # TODO: get all tasks instead of just the first
  resp = ec2.describe_instances(instance_ids: [id].flatten).reservations.first
  return @task_name = nil if resp.nil?
  @task_name = resp.instances[0].tags.select do |t|
    t.value if t.key == 'taskType'
  end.first
end

#time_is_up?Boolean

This method will return true if:

  • The run time is more than 5 minutes

and

  • The run time is 5 minutes from the hour mark from when the instance started

and will return false otherwise

Returns Boolean

Returns:

  • (Boolean)


214
215
216
217
218
219
220
# File 'lib/cloud_powers/self_awareness.rb', line 214

def time_is_up?
  an_hours_time = 60 * 60
  five_minutes_time = 60 * 5

  return false if run_time < five_minutes_time
  run_time % an_hours_time < five_minutes_time
end