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_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_time ⇒ Object

Gets the instance time or the time it was called and as seconds from epoch Returns Integer TODO: use time codes



22
23
24
25
26
27
28
29
30
31
# File 'lib/cloud_powers/self_awareness.rb', line 22

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 => e
    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.



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

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 => e
    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



62
63
64
65
66
67
68
# File 'lib/cloud_powers/self_awareness.rb', line 62

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_id ⇒ Object

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



72
73
74
# File 'lib/cloud_powers/self_awareness.rb', line 72

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

#instance_url ⇒ Object

Gets and sets the public hostname of the instance Returns String 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



83
84
85
86
87
88
89
90
# File 'lib/cloud_powers/self_awareness.rb', line 83

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)

Returns

  • Array if key is blank
  • String if key is given


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/cloud_powers/self_awareness.rb', line 102

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
      require_relative '../stubs/aws_stubs'
       = Smash::CloudPowers::AwsStubs::INSTANCE_METADATA_STUB

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

#run_time ⇒ Object

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.


124
125
126
# File 'lib/cloud_powers/self_awareness.rb', line 124

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



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

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) * if no id is given, self-instance ID is returned Returns String



144
145
146
147
148
149
150
151
152
# File 'lib/cloud_powers/self_awareness.rb', line 144

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 => e
    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 the id param see also: SelfAwareness#task_names



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

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

Returns:

  • (Boolean)


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

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