Class: Jackal::Cfn::Resource
- Inherits:
-
Jackal::Callback
- Object
- Jackal::Callback
- Jackal::Cfn::Resource
- Includes:
- Utils, Utils::Http
- Defined in:
- lib/jackal-cfn/resource.rb
Overview
Callback for resource types
Direct Known Subclasses
AmiManager, AmiRegister, HashExtractor, JackalStack, OrchestrationUnit, Scrubber
Defined Under Namespace
Modules: InheritedValidity
Constant Summary collapse
- VALID_RESOURCE_STATUS =
['SUCCESS', 'FAILED']
Class Method Summary collapse
-
.inherited(klass) ⇒ Object
Update validity checks in subclasses.
Instance Method Summary collapse
-
#build_response(cfn_resource) ⇒ Hash
Generate response hash.
-
#execute(message) ⇒ Object
Generate payload and drop.
-
#failure_wrap(message) ⇒ Object
Custom wrap to send resource failure.
-
#physical_resource_id ⇒ String
Physical ID of the resource created.
-
#respond_to_stack(response, response_url) ⇒ TrueClass, FalseClass
Send response to the waiting stack.
-
#setup(*_) ⇒ Object
Setup the dependency requirements for the callback.
-
#unpack(message) ⇒ Smash
Unpack message and create payload.
-
#valid?(message) ⇒ TrueClass, FalseClass
Determine message validity.
Methods included from Utils::Http
Methods included from Utils
#snakecase, #transform_parameters
Class Method Details
.inherited(klass) ⇒ Object
Update validity checks in subclasses
40 41 42 43 44 |
# File 'lib/jackal-cfn/resource.rb', line 40 def self.inherited(klass) klass.class_eval do include InheritedValidity end end |
Instance Method Details
#build_response(cfn_resource) ⇒ Hash
Generate response hash
83 84 85 86 87 88 89 90 91 92 |
# File 'lib/jackal-cfn/resource.rb', line 83 def build_response(cfn_resource) Smash.new( 'LogicalResourceId' => cfn_resource[:logical_resource_id], 'PhysicalResourceId' => cfn_resource.fetch(:physical_resource_id, physical_resource_id), 'StackId' => cfn_resource[:stack_id], 'RequestId' => cfn_resource[:request_id], 'Status' => 'SUCCESS', 'Data' => Smash.new ) end |
#execute(message) ⇒ Object
Generate payload and drop
156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/jackal-cfn/resource.rb', line 156 def execute() data_payload = unpack() payload = new_payload( config.fetch(:name, :jackal_cfn), :cfn_resource => data_payload ) if(config[:reprocess]) debug "Reprocessing received message! #{payload}" Carnivore::Supervisor.supervisor[destination(:input, payload)].transmit(payload) .confirm! else completed(payload, ) end end |
#failure_wrap(message) ⇒ Object
Custom wrap to send resource failure
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/jackal-cfn/resource.rb', line 174 def failure_wrap() begin payload = unpack() yield payload rescue => e error "Unexpected error encountered processing custom resource - #{e.class}: #{e.}" debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}" cfn_resource = payload.get(:data, :cfn_resource) cfn_response = build_response(cfn_resource) cfn_response['Status'] = 'FAILED' cfn_response['Reason'] = "Unexpected error encountered [#{e.}]" respond_to_stack(cfn_response, cfn_resource[:response_url]) .confirm! end end |
#physical_resource_id ⇒ String
this should be overridden in subclasses when actual resources are being created
Physical ID of the resource created
71 72 73 |
# File 'lib/jackal-cfn/resource.rb', line 71 def physical_resource_id "#{self.class.name.split('::').last}-#{Carnivore.uuid}" end |
#respond_to_stack(response, response_url) ⇒ TrueClass, FalseClass
Send response to the waiting stack
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 |
# File 'lib/jackal-cfn/resource.rb', line 99 def respond_to_stack(response, response_url) unless(VALID_RESOURCE_STATUS.include?(response['Status'])) raise ArgumentError.new "Invalid resource status provided. Got: #{response['Status']}. Allowed: #{VALID_RESOURCE_STATUS.join(', ')}" end if(response['Status'] == 'FAILED' && !response['Reason']) response['Reason'] = 'Unknown' end url = URI.parse(response_url) connection = response_endpoint(url.host, url.scheme) path = "#{url.path}?#{url.query}" debug "Custom resource response data: #{response.inspect}" complete = connection.put(path, JSON.dump(response)) case complete.status when 200 info "Custom resource response complete! (Sent to: #{url})" true when 403 error "Custom resource response failed. Endpoint is forbidden (403): #{url}" false when 404 error "Custom resource response failed. Endpoint is not found (404): #{url}" false else raise "Response failed. Received status: #{complete.status} endpoint: #{url}" end end |
#setup(*_) ⇒ Object
Setup the dependency requirements for the callback
62 63 64 |
# File 'lib/jackal-cfn/resource.rb', line 62 def setup(*_) require 'patron' end |
#unpack(message) ⇒ Smash
Unpack message and create payload
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/jackal-cfn/resource.rb', line 130 def unpack() payload = super if(self.is_a?(Jackal::Cfn::Resource)) begin if(payload['Message']) payload = MultiJson.load(payload['Message']).to_smash payload = transform_parameters(payload) payload[:origin_type] = [:message].get('Body', 'Type') payload[:origin_subject] = [:message].get('Body', 'Subject') payload[:request_type] = snakecase(payload[:request_type]) payload else payload.to_smash.fetch('Attributes', 'Body', payload.to_smash.fetch('Body', payload.to_smash)) end rescue MultiJson::ParseError # Not our expected format so return empty payload Smash.new end else payload.to_smash.fetch('Attributes', 'Body', payload.to_smash.fetch('Body', payload.to_smash)) end end |
#valid?(message) ⇒ TrueClass, FalseClass
Determine message validity
50 51 52 53 54 55 56 57 58 59 |
# File 'lib/jackal-cfn/resource.rb', line 50 def valid?() super do |payload| if(block_given?) yield payload else payload[:origin_type] == 'Notification' && payload[:origin_subject].to_s.downcase.include?('cloudformation custom resource') end end end |