qurd 0.0.2 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +6 -0
- data/README.md +22 -10
- data/Rakefile +2 -0
- data/lib/qurd/action.rb +38 -12
- data/lib/qurd/action/chef.rb +14 -12
- data/lib/qurd/action/route53.rb +4 -8
- data/lib/qurd/configuration.rb +5 -3
- data/lib/qurd/listener.rb +36 -1
- data/lib/qurd/version.rb +1 -1
- data/qurd.gemspec +1 -0
- data/scripts/artifact.sh +9 -0
- data/test/action_test.rb +8 -8
- data/test/chef_test.rb +34 -1
- data/test/configuration_test.rb +3 -0
- metadata +19 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 60d8e2710e6c78de59f55d37f0477ce3f1fd98a3
         | 
| 4 | 
            +
              data.tar.gz: 63d106eb2c2817c6b1a7f21f77534eeb37ea639c
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: f1afebad665bf6e6b1586aadffa014ab7e201694d7104d373a8ddfe4e6ab945f9b887e5c776e5da41fde63199f762e87e40e38e03f848fb1e1115643252e7bce
         | 
| 7 | 
            +
              data.tar.gz: 9a29b9618381985cb9396fdb388a1f14483027cc042731ddb264c2d6a67910b43b0730e9de2bfbe6ba935d31c2fe5cf5d44a40efd126ac277c42aa6f4cec8106
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            2.1 | 
| 1 | 
            +
            2.3.1
         | 
    
        data/CHANGELOG.md
    ADDED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -19,15 +19,20 @@ Dummy is provided as a simple example, but, in a nutshell, inherit from | |
| 19 19 | 
             
            Qurd::Action and override the actions you respond to.
         | 
| 20 20 |  | 
| 21 21 | 
             
            Your action class can configure itself, by overriding the class method
         | 
| 22 | 
            -
            `configure`. Instances must override the action methods launch | 
| 23 | 
            -
            terminate | 
| 24 | 
            -
            `message` and `context`. Message is a `Qurd::Message` | 
| 25 | 
            -
            `Cabin::Context`, used for logging. Callbacks, to | 
| 26 | 
            -
            before and after the instance are executed, can be | 
| 22 | 
            +
            `configure`. Instances must override the action methods `launch`,
         | 
| 23 | 
            +
            `launch_error`, `terminate`, `terminate_error`, and `test`. Action instances
         | 
| 24 | 
            +
            have two attributes, `message` and `context`. Message is a `Qurd::Message`
         | 
| 25 | 
            +
            instance. Context is a `Cabin::Context`, used for logging. Callbacks, to
         | 
| 26 | 
            +
            interact with the action before and after the instance are executed, can be
         | 
| 27 | 
            +
            overridden.
         | 
| 27 28 |  | 
| 28 29 | 
             
            The mixins for AwsClients and Configuration are also available at the class and
         | 
| 29 30 | 
             
            instance level.
         | 
| 30 31 |  | 
| 32 | 
            +
            Action instances will also respond to `aws_credentials`, 
         | 
| 33 | 
            +
            `chef_client`, `chef_client=`, `chef_node`, `chef_node=`, `failed!`, `failed?`,
         | 
| 34 | 
            +
            `instance`, `instance_id`, `instance_name`, `name`, `region`.
         | 
| 35 | 
            +
             | 
| 31 36 | 
             
            ```ruby
         | 
| 32 37 | 
             
            # This contrived example creates a file in s3 when an instance launches
         | 
| 33 38 | 
             
            # It can be triggered by adding the class name to the list of actions in the
         | 
| @@ -45,7 +50,7 @@ class Foo < Qurd::Action | |
| 45 50 | 
             
                aws_retryable do
         | 
| 46 51 | 
             
                  aws_client(:S3).delete_object(
         | 
| 47 52 | 
             
                    bucket: qurd_configuration.bucket,
         | 
| 48 | 
            -
                    key:  | 
| 53 | 
            +
                    key: instance_id
         | 
| 49 54 | 
             
                  )
         | 
| 50 55 | 
             
                end
         | 
| 51 56 | 
             
              end
         | 
| @@ -54,8 +59,8 @@ class Foo < Qurd::Action | |
| 54 59 | 
             
                aws_retryable do
         | 
| 55 60 | 
             
                  aws_client(:S3).put_object(
         | 
| 56 61 | 
             
                    bucket: qurd_configuration.bucket,
         | 
| 57 | 
            -
                    key:  | 
| 58 | 
            -
                    body:  | 
| 62 | 
            +
                    key: instance_id,
         | 
| 63 | 
            +
                    body: instance.private_ip_address
         | 
| 59 64 | 
             
                  )
         | 
| 60 65 | 
             
                end
         | 
| 61 66 | 
             
              end
         | 
| @@ -64,7 +69,7 @@ class Foo < Qurd::Action | |
| 64 69 | 
             
                aws_retryable do
         | 
| 65 70 | 
             
                  o = aws_client(:S3).get_object(
         | 
| 66 71 | 
             
                    bucket: qurd_configuration.bucket,
         | 
| 67 | 
            -
                    key:  | 
| 72 | 
            +
                    key: instance_id
         | 
| 68 73 | 
             
                  )
         | 
| 69 74 | 
             
                  qurd_logger.debug("Found #{o.body}")
         | 
| 70 75 | 
             
                end
         | 
| @@ -121,7 +126,7 @@ If you are using the route53 action, you will also need | |
| 121 126 | 
             
                            "route53:ChangeResourceRecordSets",
         | 
| 122 127 | 
             
                            "route53:DeleteHostedZone",
         | 
| 123 128 | 
             
                            "route53:GetHostedZone",
         | 
| 124 | 
            -
                            "route53: | 
| 129 | 
            +
                            "route53:ListHostedZonesByName",
         | 
| 125 130 | 
             
                            "route53:ListResourceRecordSets"
         | 
| 126 131 | 
             
                        ],
         | 
| 127 132 | 
             
                        "Resource": [
         | 
| @@ -215,6 +220,13 @@ To configure the daemon, edit the YAML configuration file. The default path is | |
| 215 220 | 
             
                <td><tt>true</tt></td>
         | 
| 216 221 | 
             
              </tr>
         | 
| 217 222 |  | 
| 223 | 
            +
              <tr>
         | 
| 224 | 
            +
                <td><tt>stats_interval</tt></td>
         | 
| 225 | 
            +
                <td>Control the interval at which stats are logged, in seconds</td>
         | 
| 226 | 
            +
                <td><tt>Fixnum</tt></td>
         | 
| 227 | 
            +
                <td><tt>600</tt></td>
         | 
| 228 | 
            +
              </tr>
         | 
| 229 | 
            +
             | 
| 218 230 | 
             
              <tr>
         | 
| 219 231 | 
             
                <td><tt>sqs_set_attributes_timeout</tt></td>
         | 
| 220 232 | 
             
                <td>Defines the timeout, in seconds, for a thread setting SQS attributes</td>
         | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/lib/qurd/action.rb
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            require 'forwardable'
         | 
| 1 2 | 
             
            module Qurd
         | 
| 2 3 | 
             
              # Subclass and override {#launch}, {#launch_error}, {#terminate},
         | 
| 3 4 | 
             
              # {#terminate_error}, and {#test}, optionally override class method
         | 
| @@ -12,12 +13,49 @@ module Qurd | |
| 12 13 | 
             
                autoload :Chef, 'qurd/action/chef'
         | 
| 13 14 | 
             
                autoload :Route53, 'qurd/action/route53'
         | 
| 14 15 |  | 
| 16 | 
            +
                extend Forwardable
         | 
| 17 | 
            +
             | 
| 15 18 | 
             
                extend Qurd::Mixins::Configuration
         | 
| 16 19 | 
             
                include Qurd::Mixins::Configuration
         | 
| 17 20 |  | 
| 18 21 | 
             
                extend Qurd::Mixins::AwsClients
         | 
| 19 22 | 
             
                include Qurd::Mixins::AwsClients
         | 
| 20 23 |  | 
| 24 | 
            +
                # @!attribute aws_credentials [r]
         | 
| 25 | 
            +
                #   @return [Aws::Credentials]
         | 
| 26 | 
            +
                def_delegator :@message, :aws_credentials, :aws_credentials
         | 
| 27 | 
            +
                # @!attribute chef_client
         | 
| 28 | 
            +
                #   @return [Chef::ApiClient]
         | 
| 29 | 
            +
                def_delegator :@message, :chef_client, :chef_client
         | 
| 30 | 
            +
                def_delegator :@message, :chef_client=, :chef_client=
         | 
| 31 | 
            +
                # @!attribute chef_node
         | 
| 32 | 
            +
                #   @return [Chef::Node]
         | 
| 33 | 
            +
                def_delegator :@message, :chef_node, :chef_node
         | 
| 34 | 
            +
                def_delegator :@message, :chef_node=, :chef_node=
         | 
| 35 | 
            +
                # @!method failed!(e) [r]
         | 
| 36 | 
            +
                #   Log an action failure, setting the Qurd::Message
         | 
| 37 | 
            +
                #   @return [Aws::Credentials]
         | 
| 38 | 
            +
                #   @see Qurd::Message.failed!
         | 
| 39 | 
            +
                def_delegator :@message, :failed!, :failed!
         | 
| 40 | 
            +
                # @!attribute failed? [r]
         | 
| 41 | 
            +
                #   @return [Boolean]
         | 
| 42 | 
            +
                def_delegator :@message, :failed?, :failed?
         | 
| 43 | 
            +
                # @!attribute instance_id [r]
         | 
| 44 | 
            +
                #   @return [String]
         | 
| 45 | 
            +
                def_delegator :@message, :instance_id, :instance_id
         | 
| 46 | 
            +
                # @!attribute instance_name [r]
         | 
| 47 | 
            +
                #   @return [String]
         | 
| 48 | 
            +
                def_delegator :@message, :instance_name, :instance_name
         | 
| 49 | 
            +
                # @!attribute instance [r]
         | 
| 50 | 
            +
                #   @return [Struct]
         | 
| 51 | 
            +
                def_delegator :@message, :instance, :instance
         | 
| 52 | 
            +
                # @!attribute name [r]
         | 
| 53 | 
            +
                #   @return [String]
         | 
| 54 | 
            +
                def_delegator :@message, :name, :name
         | 
| 55 | 
            +
                # @!attribute region [r]
         | 
| 56 | 
            +
                #   @return [String]
         | 
| 57 | 
            +
                def_delegator :@message, :region, :region
         | 
| 58 | 
            +
             | 
| 21 59 | 
             
                # @!attribute context [r]
         | 
| 22 60 | 
             
                #   The logging context
         | 
| 23 61 | 
             
                #   @return [Cabin::Context]
         | 
| @@ -46,18 +84,6 @@ module Qurd | |
| 46 84 | 
             
                  @context = message.context
         | 
| 47 85 | 
             
                end
         | 
| 48 86 |  | 
| 49 | 
            -
                # Aws region for the message
         | 
| 50 | 
            -
                # @return [String]
         | 
| 51 | 
            -
                def region
         | 
| 52 | 
            -
                  message.region
         | 
| 53 | 
            -
                end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                # Aws credentials for the message
         | 
| 56 | 
            -
                # @return [Aws::Credentials]
         | 
| 57 | 
            -
                def aws_credentials
         | 
| 58 | 
            -
                  message.aws_credentials
         | 
| 59 | 
            -
                end
         | 
| 60 | 
            -
             | 
| 61 87 | 
             
                # Executed before the processor runs the plugins for an action
         | 
| 62 88 | 
             
                # @see Qurd::Processor
         | 
| 63 89 | 
             
                def run_before
         | 
    
        data/lib/qurd/action/chef.rb
    CHANGED
    
    | @@ -47,14 +47,14 @@ module Qurd | |
| 47 47 | 
             
                  # dry_run is not true
         | 
| 48 48 | 
             
                  # @see {#Qurd::Message}
         | 
| 49 49 | 
             
                  def terminate
         | 
| 50 | 
            -
                    if  | 
| 50 | 
            +
                    if failed?
         | 
| 51 51 | 
             
                      qurd_logger.warn('Not deleting, message failed to process')
         | 
| 52 52 | 
             
                    elsif qurd_configuration.dry_run
         | 
| 53 53 | 
             
                      check_dry_run
         | 
| 54 54 | 
             
                    else
         | 
| 55 55 | 
             
                      qurd_logger.debug('Deleting')
         | 
| 56 | 
            -
                       | 
| 57 | 
            -
                       | 
| 56 | 
            +
                      chef_node.destroy unless chef_node.nil?
         | 
| 57 | 
            +
                      chef_client.destroy unless chef_client.nil?
         | 
| 58 58 | 
             
                    end
         | 
| 59 59 | 
             
                  end
         | 
| 60 60 |  | 
| @@ -68,26 +68,27 @@ module Qurd | |
| 68 68 | 
             
                  # Set the +message+ +chef_node+ and +context+ +chef_name+
         | 
| 69 69 | 
             
                  # @see chef_search_node
         | 
| 70 70 | 
             
                  def find_chef_node
         | 
| 71 | 
            -
                    node = chef_search_node
         | 
| 72 | 
            -
                     | 
| 71 | 
            +
                    node = chef_search_node("instance_id", instance_id)
         | 
| 72 | 
            +
                    node ||= chef_search_node("name", instance_name)
         | 
| 73 | 
            +
                    self.chef_node = node
         | 
| 73 74 | 
             
                    message.context[:chef_name] = node.name
         | 
| 74 75 | 
             
                    qurd_logger.debug('Chef node found')
         | 
| 75 76 | 
             
                  rescue NoMethodError
         | 
| 76 77 | 
             
                    qurd_logger.warn('Chef node not found')
         | 
| 77 | 
            -
                     | 
| 78 | 
            +
                    self.chef_node = nil
         | 
| 78 79 | 
             
                    message.context[:chef_name] = nil
         | 
| 79 80 | 
             
                  end
         | 
| 80 81 |  | 
| 81 82 | 
             
                  # Set the +message+ +chef_client+ and +context+ +chef_client_name+
         | 
| 82 83 | 
             
                  # @see chef_search_client
         | 
| 83 84 | 
             
                  def find_chef_client
         | 
| 84 | 
            -
                    client = chef_search_client( | 
| 85 | 
            -
                     | 
| 85 | 
            +
                    client = chef_search_client(chef_node.name)
         | 
| 86 | 
            +
                    self.chef_client = client
         | 
| 86 87 | 
             
                    message.context[:chef_client_name] = client.name
         | 
| 87 88 | 
             
                    qurd_logger.debug('Chef client found')
         | 
| 88 89 | 
             
                  rescue NoMethodError
         | 
| 89 90 | 
             
                    qurd_logger.warn('Chef client not found')
         | 
| 90 | 
            -
                     | 
| 91 | 
            +
                    self.chef_client = nil
         | 
| 91 92 | 
             
                    message.context[:chef_client_name] = nil
         | 
| 92 93 | 
             
                  end
         | 
| 93 94 |  | 
| @@ -98,10 +99,11 @@ module Qurd | |
| 98 99 | 
             
                  end
         | 
| 99 100 |  | 
| 100 101 | 
             
                  # Search for a Chef node, based on the +instance_id+
         | 
| 102 | 
            +
                  # @param [String] key the chef key to search
         | 
| 103 | 
            +
                  # @param [String] value the value of the key to search
         | 
| 101 104 | 
             
                  # @return [Chef::Node|nil]
         | 
| 102 | 
            -
                   | 
| 103 | 
            -
             | 
| 104 | 
            -
                    res = chef_search.search(:node, "instance_id:#{message.instance_id}")
         | 
| 105 | 
            +
                  def chef_search_node(key, value)
         | 
| 106 | 
            +
                    res = chef_search.search(:node, "#{key}:#{value}")
         | 
| 105 107 | 
             
                    res.last == 1 ? res[0][0] : nil
         | 
| 106 108 | 
             
                  end
         | 
| 107 109 |  | 
    
        data/lib/qurd/action/route53.rb
    CHANGED
    
    | @@ -39,7 +39,7 @@ module Qurd | |
| 39 39 | 
             
                  # dry_run is not true
         | 
| 40 40 | 
             
                  # @see {#Qurd::Message}
         | 
| 41 41 | 
             
                  def terminate
         | 
| 42 | 
            -
                    if  | 
| 42 | 
            +
                    if failed?
         | 
| 43 43 | 
             
                      qurd_logger.warn('Not deleting, message failed to process')
         | 
| 44 44 | 
             
                    elsif qurd_configuration.dry_run
         | 
| 45 45 | 
             
                      if !hosted_zone
         | 
| @@ -63,21 +63,17 @@ module Qurd | |
| 63 63 |  | 
| 64 64 | 
             
                  private
         | 
| 65 65 |  | 
| 66 | 
            -
                  def instance_name
         | 
| 67 | 
            -
                    message.instance_name
         | 
| 68 | 
            -
                  end
         | 
| 69 | 
            -
             | 
| 70 66 | 
             
                  def route53
         | 
| 71 67 | 
             
                    @route53 ||= aws_client(:Route53)
         | 
| 72 68 | 
             
                  end
         | 
| 73 69 |  | 
| 74 70 | 
             
                  def qurd_route53
         | 
| 75 | 
            -
                    @config ||= qurd_configuration.route53[ | 
| 71 | 
            +
                    @config ||= qurd_configuration.route53[name]
         | 
| 76 72 | 
             
                  end
         | 
| 77 73 |  | 
| 78 74 | 
             
                  def chef_node_name
         | 
| 79 75 | 
             
                    return @chef_node_name if @chef_node_name
         | 
| 80 | 
            -
                    @chef_node_name =  | 
| 76 | 
            +
                    @chef_node_name = chef_node.name
         | 
| 81 77 | 
             
                    qurd_logger.debug("Found chef name '#{@chef_node_name}'")
         | 
| 82 78 | 
             
                    @chef_node_name
         | 
| 83 79 | 
             
                  rescue NoMethodError
         | 
| @@ -127,7 +123,7 @@ module Qurd | |
| 127 123 | 
             
                    end
         | 
| 128 124 | 
             
                  rescue Qurd::Action::Route53::Errors => e
         | 
| 129 125 | 
             
                    qurd_logger.error("Failed to delete: #{e}")
         | 
| 130 | 
            -
                     | 
| 126 | 
            +
                    failed!(e)
         | 
| 131 127 | 
             
                  end
         | 
| 132 128 |  | 
| 133 129 | 
             
                  def hosted_zone(tries = nil)
         | 
    
        data/lib/qurd/configuration.rb
    CHANGED
    
    | @@ -8,8 +8,8 @@ module Qurd | |
| 8 8 | 
             
                #   Configuration options, ie
         | 
| 9 9 | 
             
                #   +aws_credentials+, +auto_scaling_queues+, +actions+, +daemonize+,
         | 
| 10 10 | 
             
                #   +dry_run+, +listen_timeout+, +log_file+, +log_level+, +pid_file+,
         | 
| 11 | 
            -
                #   +save_failures+, + | 
| 12 | 
            -
                #   +wait_time+.
         | 
| 11 | 
            +
                #   +save_failures+, +stats_interval+, +sqs_set_attributes_timeout+,
         | 
| 12 | 
            +
                #   +visibility_timeout+, +wait_time+.
         | 
| 13 13 | 
             
                #   Additional configuration keys include +listeners+.
         | 
| 14 14 | 
             
                #   @return [Hashie::Mash] the config YAML as a Mash
         | 
| 15 15 | 
             
                # @!attribute [r] logger
         | 
| @@ -30,10 +30,12 @@ module Qurd | |
| 30 30 | 
             
                  @config.save_failures = get_or_default(@config, :save_failures, true)
         | 
| 31 31 | 
             
                  @queues = []
         | 
| 32 32 | 
             
                  @aws_credentials = []
         | 
| 33 | 
            +
                  st = get_or_default(@config, :sqs_set_attributes_timeout, 10, :to_f)
         | 
| 34 | 
            +
                  si = get_or_default(@config, :stats_interval, 600, :to_i)
         | 
| 33 35 | 
             
                  vt = get_or_default(@config, :visibility_timeout, 300, :to_s)
         | 
| 34 36 | 
             
                  wt = get_or_default(@config, :wait_time, 20, :to_s)
         | 
| 35 | 
            -
                  st = get_or_default(@config, :sqs_set_attributes_timeout, 10, :to_f)
         | 
| 36 37 | 
             
                  lt = get_or_default(@config, :listen_timeout, vt, :to_f)
         | 
| 38 | 
            +
                  @config.stats_interval = si
         | 
| 37 39 | 
             
                  @config.visibility_timeout = vt
         | 
| 38 40 | 
             
                  @config.wait_time = wt
         | 
| 39 41 | 
             
                  @config.sqs_set_attributes_timeout = st
         | 
    
        data/lib/qurd/listener.rb
    CHANGED
    
    | @@ -58,6 +58,9 @@ module Qurd | |
| 58 58 | 
             
                # @yieldparam [Cabin::Context] ctx the logging context
         | 
| 59 59 | 
             
                def queue_threads(&_block)
         | 
| 60 60 | 
             
                  queues.map do |qurl|
         | 
| 61 | 
            +
                    @mutex = Mutex.new
         | 
| 62 | 
            +
                    @counter = Hashie::Mash.new({thread_timeouts: 0, aws_service_errors: 0, successes: 0, failures: 0, messages: 0})
         | 
| 63 | 
            +
             | 
| 61 64 | 
             
                    qurd_logger.debug("Creating thread for #{qurl}")
         | 
| 62 65 | 
             
                    Thread.new(qurl) do |url|
         | 
| 63 66 | 
             
                      ctx = qurd_config.get_context(name: name, queue_name: url[/([^\/]+)$/])
         | 
| @@ -71,7 +74,7 @@ module Qurd | |
| 71 74 | 
             
                # message received
         | 
| 72 75 | 
             
                # @return [Array<Thread>]
         | 
| 73 76 | 
             
                def listen
         | 
| 74 | 
            -
                  queue_threads do |qurl, _context|
         | 
| 77 | 
            +
                  threads = queue_threads do |qurl, _context|
         | 
| 75 78 | 
             
                    loop do
         | 
| 76 79 | 
             
                      begin
         | 
| 77 80 | 
             
                        msgs = aws_client(:SQS).receive_message(
         | 
| @@ -84,13 +87,17 @@ module Qurd | |
| 84 87 | 
             
                          thread.join(qurd_configuration.listen_timeout)
         | 
| 85 88 | 
             
                        end
         | 
| 86 89 | 
             
                        if joins.compact.count != threads.count
         | 
| 90 | 
            +
                          nthreads = threads.count - joins.compact.count
         | 
| 91 | 
            +
                          lock_counter { @counter.thread_timeouts += nthreads }
         | 
| 87 92 | 
             
                          qurd_logger.warn('Some threads timed out')
         | 
| 88 93 | 
             
                        end
         | 
| 89 94 | 
             
                      rescue Aws::Errors::ServiceError => e
         | 
| 95 | 
            +
                        lock_counter { @counter.aws_service_errors += 1 }
         | 
| 90 96 | 
             
                        qurd_logger.error("Aws raised #{e}")
         | 
| 91 97 | 
             
                      end
         | 
| 92 98 | 
             
                    end
         | 
| 93 99 | 
             
                  end
         | 
| 100 | 
            +
                  threads << stats_thread
         | 
| 94 101 | 
             
                end
         | 
| 95 102 |  | 
| 96 103 | 
             
                # @private
         | 
| @@ -100,12 +107,39 @@ module Qurd | |
| 100 107 |  | 
| 101 108 | 
             
                private
         | 
| 102 109 |  | 
| 110 | 
            +
                def stats_thread
         | 
| 111 | 
            +
                  Thread.new do
         | 
| 112 | 
            +
                    loop do
         | 
| 113 | 
            +
                      sleep(qurd_configuration.stats_interval)
         | 
| 114 | 
            +
                      lock_counter { qurd_logger.info("STATS", @counter) }
         | 
| 115 | 
            +
                    end
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                def lock_counter(&_block)
         | 
| 120 | 
            +
                  @mutex.synchronize {
         | 
| 121 | 
            +
                    begin
         | 
| 122 | 
            +
                      yield
         | 
| 123 | 
            +
                    rescue ThreadError => e
         | 
| 124 | 
            +
                      @mutex.sleep(0.1)
         | 
| 125 | 
            +
                      qurd_logger.debug("ThreadError: #{e}")
         | 
| 126 | 
            +
                      retry
         | 
| 127 | 
            +
                    end
         | 
| 128 | 
            +
                  }
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 103 131 | 
             
                def process_messages(qurl, msgs)
         | 
| 132 | 
            +
                  lock_counter { @counter.messages += msgs.messages.count }
         | 
| 104 133 | 
             
                  msgs.messages.map do |msg|
         | 
| 105 134 | 
             
                    Thread.new(msg) do |m|
         | 
| 106 135 | 
             
                      qurd_logger.debug("Found message #{msg}")
         | 
| 107 136 | 
             
                      r = Processor.new self, m, name, qurl
         | 
| 108 137 | 
             
                      r.process
         | 
| 138 | 
            +
                      lock_counter { 
         | 
| 139 | 
            +
                        r.message.failed? ?
         | 
| 140 | 
            +
                          @counter.failures += 1 :
         | 
| 141 | 
            +
                          @counter.successes += 1
         | 
| 142 | 
            +
                      }
         | 
| 109 143 | 
             
                    end
         | 
| 110 144 | 
             
                  end
         | 
| 111 145 | 
             
                end
         | 
| @@ -134,6 +168,7 @@ module Qurd | |
| 134 168 | 
             
                      )
         | 
| 135 169 | 
             
                    rescue Aws::SQS::Errors::ServiceError::QueueDoesNotExist => e
         | 
| 136 170 | 
             
                      qurd_logger.error("SQS raised #{e}")
         | 
| 171 | 
            +
                      Thread.terminate
         | 
| 137 172 | 
             
                    rescue Aws::SQS::Errors::ServiceError => e
         | 
| 138 173 | 
             
                      qurd_logger.error("SQS raised #{e}")
         | 
| 139 174 | 
             
                      raise e
         | 
    
        data/lib/qurd/version.rb
    CHANGED
    
    
    
        data/qurd.gemspec
    CHANGED
    
    | @@ -21,6 +21,7 @@ Gem::Specification.new do |spec| | |
| 21 21 | 
             
              spec.add_development_dependency "bundler", "~> 1.8"
         | 
| 22 22 | 
             
              spec.add_development_dependency "rake", "~> 10.0"
         | 
| 23 23 | 
             
              spec.add_development_dependency "minitest"
         | 
| 24 | 
            +
              spec.add_development_dependency "ci_reporter_minitest"
         | 
| 24 25 | 
             
              spec.add_development_dependency "pry-nav"
         | 
| 25 26 | 
             
              spec.add_development_dependency "webmock"
         | 
| 26 27 | 
             
              spec.add_development_dependency "minitest-matchers_vaccine"
         | 
    
        data/scripts/artifact.sh
    ADDED
    
    | @@ -0,0 +1,9 @@ | |
| 1 | 
            +
            #!/bin/bash
         | 
| 2 | 
            +
            set -e
         | 
| 3 | 
            +
            bundle package --all
         | 
| 4 | 
            +
            bundle install --binstubs bundler-bin --deployment --local --without development test
         | 
| 5 | 
            +
            echo ${BUILD_NUMBER} > .release.txt
         | 
| 6 | 
            +
            git rev-parse --verify HEAD >> .release.txt
         | 
| 7 | 
            +
            rm -rf release
         | 
| 8 | 
            +
            mkdir -p release
         | 
| 9 | 
            +
            tar -cvzf release/qurd-${BUILD_NUMBER}.tgz --exclude release * .release.txt .bundle .ruby-version
         | 
    
        data/test/action_test.rb
    CHANGED
    
    | @@ -39,12 +39,12 @@ describe Qurd::Action do | |
| 39 39 | 
             
                  aws_sqs_list_queues
         | 
| 40 40 | 
             
                  aws_sqs_set_queue_attributes
         | 
| 41 41 | 
             
                  aws_sqs_receive_message 'test/responses/aws/sqs-receive-message-1-launch.xml'
         | 
| 42 | 
            -
                  Qurd::Configuration.instance.configure('test/inputs/ | 
| 42 | 
            +
                  Qurd::Configuration.instance.configure('test/inputs/qurd_chef.yml')
         | 
| 43 43 | 
             
                end
         | 
| 44 44 | 
             
                let(:sqs_client) { Aws::SQS::Client.new(region: 'us-west-2') }
         | 
| 45 45 | 
             
                let(:queue_url) { 'https://sqs.us-west-2.amazonaws.com/123456890/test2-ScalingNotificationsQueue-HPPYDAYSAGAI1' }
         | 
| 46 46 | 
             
                let(:sqs_message) { sqs_client.receive_message(queue_url: queue_url).messages.first }
         | 
| 47 | 
            -
                let(:qurd_message) { Qurd::Message.new(message: sqs_message) }
         | 
| 47 | 
            +
                let(:qurd_message) { Qurd::Message.new(message: sqs_message, region: 'us-west-2', aws_credentials: Aws::Credentials.new('a', 'b')) }
         | 
| 48 48 | 
             
                let(:subject) { TestActionClass.new(qurd_message) }
         | 
| 49 49 |  | 
| 50 50 | 
             
                it 'includes configuration mixin' do
         | 
| @@ -72,12 +72,12 @@ describe Qurd::Action do | |
| 72 72 | 
             
                  end
         | 
| 73 73 | 
             
                end
         | 
| 74 74 |  | 
| 75 | 
            -
                 | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
                   | 
| 75 | 
            +
                %w[aws_credentials instance chef_client chef_node failed! failed? 
         | 
| 76 | 
            +
                   instance_id instance_name name region].each do |method|
         | 
| 77 | 
            +
                  it "responds to #{method}" do
         | 
| 78 | 
            +
                    aws_ec2_describe_instances 'test/responses/aws/ec2-describe-instances-1.xml'
         | 
| 79 | 
            +
                   subject.send(method).must_equal qurd_message.send(method)
         | 
| 80 | 
            +
                  end
         | 
| 81 81 | 
             
                end
         | 
| 82 82 |  | 
| 83 83 | 
             
                %w[launch launch_error terminate terminate_error test].each do |action|
         | 
    
        data/test/chef_test.rb
    CHANGED
    
    | @@ -57,6 +57,11 @@ describe Qurd::Action::Chef do | |
| 57 57 | 
             
                    'node',
         | 
| 58 58 | 
             
                    "instance_id:#{qurd_message.instance_id}"
         | 
| 59 59 | 
             
                  )
         | 
| 60 | 
            +
                  chef_search(
         | 
| 61 | 
            +
                    'test/responses/chef/search-node-instance-n.json',
         | 
| 62 | 
            +
                    'node',
         | 
| 63 | 
            +
                    "name:test-414.staging.example.com"
         | 
| 64 | 
            +
                  )
         | 
| 60 65 | 
             
                  chef_search(
         | 
| 61 66 | 
             
                    'test/responses/chef/search-client-name-n.json',
         | 
| 62 67 | 
             
                    'client',
         | 
| @@ -67,7 +72,7 @@ describe Qurd::Action::Chef do | |
| 67 72 | 
             
                  subject.message.context[:chef_name].must_equal nil
         | 
| 68 73 | 
             
                end
         | 
| 69 74 |  | 
| 70 | 
            -
                it 'finds a node and client' do
         | 
| 75 | 
            +
                it 'finds a node (instance_id) and client' do
         | 
| 71 76 | 
             
                  chef_search(
         | 
| 72 77 | 
             
                    'test/responses/chef/search-node-instance-1.json',
         | 
| 73 78 | 
             
                    'node',
         | 
| @@ -85,12 +90,40 @@ describe Qurd::Action::Chef do | |
| 85 90 | 
             
                  subject.message.context[:chef_client_name].must_equal 'test-414.staging.example.com'
         | 
| 86 91 | 
             
                end
         | 
| 87 92 |  | 
| 93 | 
            +
                it 'finds a node (name) and client' do
         | 
| 94 | 
            +
                  chef_search(
         | 
| 95 | 
            +
                    'test/responses/chef/search-node-instance-0.json',
         | 
| 96 | 
            +
                    'node',
         | 
| 97 | 
            +
                    "instance_id:#{qurd_message.instance_id}"
         | 
| 98 | 
            +
                  )
         | 
| 99 | 
            +
                  chef_search(
         | 
| 100 | 
            +
                    'test/responses/chef/search-node-instance-1.json',
         | 
| 101 | 
            +
                    'node',
         | 
| 102 | 
            +
                    "name:test-414.staging.example.com"
         | 
| 103 | 
            +
                  )
         | 
| 104 | 
            +
                  chef_search(
         | 
| 105 | 
            +
                    'test/responses/chef/search-client-name-1.json',
         | 
| 106 | 
            +
                    'client',
         | 
| 107 | 
            +
                    'name:test-414.staging.example.com'
         | 
| 108 | 
            +
                  )
         | 
| 109 | 
            +
                  subject.run_before
         | 
| 110 | 
            +
                  subject.message.chef_node.must_be_kind_of Chef::Node
         | 
| 111 | 
            +
                  subject.message.context[:chef_name].must_equal 'test-414.staging.example.com'
         | 
| 112 | 
            +
                  subject.message.chef_client.must_be_kind_of Chef::ApiClient
         | 
| 113 | 
            +
                  subject.message.context[:chef_client_name].must_equal 'test-414.staging.example.com'
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
             | 
| 88 116 | 
             
                it 'does not find a node' do
         | 
| 89 117 | 
             
                  chef_search(
         | 
| 90 118 | 
             
                    'test/responses/chef/search-node-instance-0.json',
         | 
| 91 119 | 
             
                    'node',
         | 
| 92 120 | 
             
                    "instance_id:#{qurd_message.instance_id}"
         | 
| 93 121 | 
             
                  )
         | 
| 122 | 
            +
                  chef_search(
         | 
| 123 | 
            +
                    'test/responses/chef/search-node-instance-0.json',
         | 
| 124 | 
            +
                    'node',
         | 
| 125 | 
            +
                    "name:test-414.staging.example.com"
         | 
| 126 | 
            +
                  )
         | 
| 94 127 | 
             
                  chef_search(
         | 
| 95 128 | 
             
                    'test/responses/chef/search-client-name-0.json',
         | 
| 96 129 | 
             
                    'client',
         | 
    
        data/test/configuration_test.rb
    CHANGED
    
    | @@ -61,6 +61,7 @@ describe Qurd::Configuration do | |
| 61 61 | 
             
                    subject.config.pid_file.must_equal '/var/run/qurd/qurd.pid'
         | 
| 62 62 | 
             
                    subject.config.save_failures.must_equal true
         | 
| 63 63 | 
             
                    subject.config.sqs_set_attributes_timeout.must_equal 10.0
         | 
| 64 | 
            +
                    subject.config.stats_interval.must_equal 600
         | 
| 64 65 | 
             
                    subject.config.visibility_timeout.must_equal '300'
         | 
| 65 66 | 
             
                    subject.config.wait_time.must_equal '20'
         | 
| 66 67 | 
             
                  end
         | 
| @@ -74,6 +75,7 @@ describe Qurd::Configuration do | |
| 74 75 | 
             
                    pid_file: 'tmp/qurd.pid',
         | 
| 75 76 | 
             
                    save_failures: false,
         | 
| 76 77 | 
             
                    sqs_set_attributes_timeout: 3,
         | 
| 78 | 
            +
                    stats_interval: 100,
         | 
| 77 79 | 
             
                    visibility_timeout: 0,
         | 
| 78 80 | 
             
                    wait_time: 1
         | 
| 79 81 | 
             
                  )
         | 
| @@ -85,6 +87,7 @@ describe Qurd::Configuration do | |
| 85 87 | 
             
                    subject.config.pid_file.must_equal 'tmp/qurd.pid'
         | 
| 86 88 | 
             
                    subject.config.save_failures.must_equal false
         | 
| 87 89 | 
             
                    subject.config.sqs_set_attributes_timeout.must_equal 3.0
         | 
| 90 | 
            +
                    subject.config.stats_interval.must_equal 100
         | 
| 88 91 | 
             
                    subject.config.visibility_timeout.must_equal '0'
         | 
| 89 92 | 
             
                    subject.config.wait_time.must_equal '1'
         | 
| 90 93 | 
             
                  end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: qurd
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.6
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Philip Champon
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2017-11-08 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -52,6 +52,20 @@ dependencies: | |
| 52 52 | 
             
                - - ">="
         | 
| 53 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 54 | 
             
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: ci_reporter_minitest
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 55 69 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 70 | 
             
              name: pry-nav
         | 
| 57 71 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -161,6 +175,7 @@ extra_rdoc_files: [] | |
| 161 175 | 
             
            files:
         | 
| 162 176 | 
             
            - ".gitignore"
         | 
| 163 177 | 
             
            - ".ruby-version"
         | 
| 178 | 
            +
            - CHANGELOG.md
         | 
| 164 179 | 
             
            - Gemfile
         | 
| 165 180 | 
             
            - LICENSE.txt
         | 
| 166 181 | 
             
            - README.md
         | 
| @@ -183,6 +198,7 @@ files: | |
| 183 198 | 
             
            - lib/qurd/version.rb
         | 
| 184 199 | 
             
            - lib/string.rb
         | 
| 185 200 | 
             
            - qurd.gemspec
         | 
| 201 | 
            +
            - scripts/artifact.sh
         | 
| 186 202 | 
             
            - test/action_test.rb
         | 
| 187 203 | 
             
            - test/chef_test.rb
         | 
| 188 204 | 
             
            - test/configuration_test.rb
         | 
| @@ -251,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 251 267 | 
             
                  version: '0'
         | 
| 252 268 | 
             
            requirements: []
         | 
| 253 269 | 
             
            rubyforge_project: 
         | 
| 254 | 
            -
            rubygems_version: 2. | 
| 270 | 
            +
            rubygems_version: 2.5.1
         | 
| 255 271 | 
             
            signing_key: 
         | 
| 256 272 | 
             
            specification_version: 4
         | 
| 257 273 | 
             
            summary: 'QUeue Resource Daemon: reaping and sowing your auto-scaled resources'
         | 
| @@ -304,4 +320,3 @@ test_files: | |
| 304 320 | 
             
            - test/route53_test.rb
         | 
| 305 321 | 
             
            - test/support/web_mock_stubs.rb
         | 
| 306 322 | 
             
            - test/test_helper.rb
         | 
| 307 | 
            -
            has_rdoc: 
         |