sortinghat 0.3.3 → 0.3.4.develop

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8781c38bf0c7c5db4a3ca524b653fc6dd43bf457
4
- data.tar.gz: 70f1c58afeadd42a06e63d02b95f87cdb5237be7
2
+ SHA256:
3
+ metadata.gz: 9a0bb1fc284e16b20cff54621a6608e51c1b233fcfe6877012c9f9f2560a0453
4
+ data.tar.gz: 4fb17c7cccf23ed6e006e90d171d0ef339a2516664907d1fb166d9c3b9e05d29
5
5
  SHA512:
6
- metadata.gz: c9a2813b2ff10016d9dfbed256170a088104c1ae986c23d39e6ea0584fffdb59349d84ad01bec7be403aecdba4aa7c00215894a79cef5f377e2af89a83bb8d0d
7
- data.tar.gz: 5715916fce1f304cc93b7140389ab1af2f12b6a005ad89ad7e5bc7aed9be456f5c590a1964040e4c1f64a35dae33fddbe37921ba444bcd718aa5ddb557fb7444
6
+ metadata.gz: '07584c6af915ac9aea638cd9e24592b4fa8576545285298ece0ec4bfd5deff9bee34ae9db876dffc63d610103e44edc1eefc26ba90313819802d5b66bd7284a3'
7
+ data.tar.gz: 83fed95b1925f27736a4f4fd9b20807a6bf2ddf2a0b0ca6beb61ccb244d1bc3c126bd4835f3a6339bc26c3ebf19afc4cc8bc33f4c3c4c415584da97fc113666c
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  /.bundle/
2
+ /.idea/
2
3
  /.yardoc
3
4
  /Gemfile.lock
4
5
  /_yardoc/
@@ -7,3 +8,5 @@
7
8
  /pkg/
8
9
  /spec/reports/
9
10
  /tmp/
11
+ /*.gem
12
+ /*.sublime*
data/README.md CHANGED
@@ -1,4 +1,8 @@
1
1
  # Sortinghat
2
+ [![Gem Version](https://badge.fury.io/rb/sortinghat.svg)](https://badge.fury.io/rb/sortinghat)
3
+ [![Total Gem Downloads](https://ruby-gem-downloads-badge.herokuapp.com/sortinghat?type=total)](https://rubygems.org/gems/sortinghat)
4
+ [![Build Status](https://travis-ci.org/praymann/sortinghat.svg?branch=master)](https://travis-ci.org/praymann/sortinghat?branch=master)
5
+ [![Build Status](https://travis-ci.org/praymann/sortinghat.svg?branch=develop)](https://travis-ci.org/praymann/sortinghat?branch=develop)
2
6
 
3
7
  Sortinghat is a unqiue Ruby gem that allows AWS AutoScaling instances to name themselves.
4
8
 
@@ -9,12 +13,12 @@ When the Sorting Hat is given specific arguments, it can find the gaps in curren
9
13
  It follows a specific pattern for hostnames/fqdn:
10
14
 
11
15
  ```
12
- [client]-[environment]-[type][prefix].[domain].com.
16
+ [client]-[environment]-[type][suffix]-[region].[domain].com.
13
17
  ```
14
18
  For example:
15
19
 
16
20
  ```
17
- nike-prod-nginx09.prod-nike.com
21
+ nike-prod-nginx09-us-west-2.prod-nike.com
18
22
  ```
19
23
 
20
24
  ## Installation:
@@ -31,8 +35,6 @@ It requires the following gems:
31
35
  * aws-sdk 2.1.2
32
36
  * pure_json
33
37
 
34
- The v2.1.2 dependency comes from the fact that as of this writting the latest codedeploy-agent (installed via .rpm) breaks if it does not have v2.1.2.
35
-
36
38
  During actually usage, the gem requires that the instance have the following IAM actions allowed via policy:
37
39
  * autoscaling:DescribeAutoScalingInstances
38
40
  * autoscaling:DescribeAutoScalingGroups
@@ -71,6 +73,11 @@ Run:
71
73
 
72
74
  $ bundle exec bin/sortinghat -h
73
75
 
76
+ ## Credits
77
+
78
+ Kudos to [nerk01](https://github.com/nerk01) for help and guidance with anything Ruby! He is also a contributor to this project.
79
+
80
+ Kudos to [jrbeilke](https://github.com/jrbeilke) for help and guidance with Ruby and the "[rubber duck debugging](https://en.wikipedia.org/wiki/Rubber_duck_debugging)" support.
74
81
 
75
82
  ## Contributing
76
83
 
data/bin/sortinghat CHANGED
@@ -5,13 +5,17 @@ require 'optparse'
5
5
 
6
6
  options = {}
7
7
 
8
+ # Default to being numbered instances
9
+ options[:numbered] = true
10
+
8
11
  parser = OptionParser.new do |opt|
9
- opt.banner = "Usage: sortinghat [OPTIONS]"
10
- opt.separator ""
11
- opt.separator "All options are required for the Sorting Hat to function."
12
- opt.separator "A trailing dot will be added to the zone should you forget it."
13
- opt.separator ""
14
- opt.separator "Options:"
12
+ opt.banner = 'Usage: sortinghat [OPTIONS]'
13
+ opt.separator ''
14
+ opt.separator 'All options except --numbered are required for the Sorting Hat to function.'
15
+ opt.separator 'The option --numbered is by default \'true\''
16
+ opt.separator 'A trailing dot will be added to the zone should you forget it.'
17
+ opt.separator ''
18
+ opt.separator 'Options:'
15
19
 
16
20
  opt.on("-c", "--client CLIENT", "Client name") do |client|
17
21
  options[:client] = client
@@ -26,13 +30,17 @@ parser = OptionParser.new do |opt|
26
30
  end
27
31
 
28
32
  opt.on("-r", "--region REGION", "Region name") do |region|
29
- options[:region] = region
33
+ options[:region] = region
30
34
  end
31
35
 
32
36
  opt.on("-z", "--zone DOMAIN", "Hosted Zone") do |zone|
33
37
  options[:zone] = zone
34
38
  end
35
39
 
40
+ opt.on('-n', '--[not-]numbered', 'Number suffix?') do |numbered|
41
+ options[:numbered] = numbered
42
+ end
43
+
36
44
  opt.on("-h", "--help", "Help menu") do
37
45
  puts parser
38
46
  exit 0
@@ -41,12 +49,6 @@ end
41
49
 
42
50
  parser.parse!
43
51
 
44
- if options.length < 5
45
- abort "All options are required."
46
- end
47
-
48
- this = Sortinghat::Banquet.new(options)
49
-
50
- this.dejavu?
52
+ abort 'All options are required.' if options.length < 5
51
53
 
52
- this.start!
54
+ Sortinghat::Banquet.assign_house(options)
@@ -5,12 +5,13 @@ require 'date'
5
5
 
6
6
  module Sortinghat
7
7
  class AWS
8
- def initialize( region = 'us-east-1' )
8
+ def initialize(region = 'us-east-1')
9
9
  # Be using this lots, make it an instance variable
10
10
  @region = region
11
11
 
12
12
  # Set a generic client for use
13
- @client = Aws::EC2::Client.new(region: @region)
13
+ @ec2_client = Aws::EC2::Client.new(region: @region)
14
+ @autoscale_client = Aws::AutoScaling::Client.new(region: @region)
14
15
 
15
16
  # Create a syslog for us to use as an instance variable
16
17
  @log = Syslog::Logger.new 'sortinghat'
@@ -18,35 +19,28 @@ module Sortinghat
18
19
 
19
20
  # Method to discover what auto-scaling group the current instance is in, then the instances in that group
20
21
  # Returns array of the Name tag values of the instances
21
- def discover()
22
- # Temporay array for use
23
- ids = Array.new
24
-
25
- # Start a new client
26
- autoscale = Aws::AutoScaling::Client.new( region: @region )
27
-
28
- # Use the client to describe this instance
29
- current = autoscale.describe_auto_scaling_instances({
30
- instance_ids: [grabinstanceid()],
31
- max_records: 1
32
- })
33
- @log.info("Grabbed current AutoScaling instance via aws-sdk")
34
-
22
+ def discover
35
23
  # Use the client to grab all instances in this auto-scaling group
36
- all = autoscale.describe_auto_scaling_groups({
37
- auto_scaling_group_names: [current.auto_scaling_instances[0].auto_scaling_group_name],
24
+ all = @autoscale_client.describe_auto_scaling_groups(
25
+ auto_scaling_group_names: [find_own_autoscale_name],
38
26
  max_records: 1
39
- })
40
- @log.info("Grabbed the instances of our AutoScaling group via aws-sdk")
27
+ )
28
+ @log.info('Grabbed the instances of our AutoScaling group via aws-sdk')
29
+
30
+ # Grab their hostname(s)
31
+ names = all.auto_scaling_groups[0].instances.map { |instance| idtoname(instance.instance_id) }
32
+ @log.info("Returning instances '#{names.join("','")}'")
41
33
 
42
- # Grab their instanceId(s)
43
- all.auto_scaling_groups[0].instances.each do |instance|
44
- ids << idtoname(instance.instance_id)
45
- end
46
- @log.info("Returning instances '#{ids.join("','")}'")
47
-
48
34
  # Return the ids
49
- ids
35
+ names
36
+ end
37
+
38
+ # Method to search for instances matching a hostname
39
+ # Returns array of instances
40
+ def search_hosts(hostname)
41
+ resp = @client.describe_instances(filters: [{ name: 'tag:Name', value: [hostname] }])
42
+ return resp.reservations unless resp.reservations.empty?
43
+ []
50
44
  end
51
45
 
52
46
  # Method to set the Name tag on the current instance
@@ -56,32 +50,21 @@ module Sortinghat
56
50
  resource = Aws::EC2::Resource.new(client: @client)
57
51
 
58
52
  # Use the resource, to find current instance, and set the Name tag
59
- resource.instance(grabinstanceid()).create_tags({
60
- tags: [
61
- {
62
- key: 'Name',
63
- value: hostname,
64
- },
65
- ]
66
- })
53
+ resource.instance(grabinstanceid)
54
+ .create_tags(tags: [{ key: 'Name', value: hostname }])
67
55
  @log.info("Set Name tag to #{hostname} via aws-sdk")
68
56
  end
69
57
 
70
58
  # Method to remove the Name tag, and set a temporary one
71
59
  # Returns nothing
72
- def removetag!()
60
+ def removetag!
73
61
  # Use the instance varible client to create a new Resource
74
62
  resource = Aws::EC2::Resource.new(client: @client)
75
63
 
76
64
  # Use the resource, to find current instance, and set the Name tag
77
- resource.instance(grabinstanceid()).create_tags({
78
- tags: [
79
- {
80
- key: 'Name',
81
- value: "sortinghat-#{rand(100)}",
82
- },
83
- ]
84
- })
65
+ hostname = "sortinghat-#{rand(100)}"
66
+ resource.instance(grabinstanceid)
67
+ .create_tags(tags: [{ key: 'Name', value: hostname }])
85
68
  @log.info("Set Name tag to temporary #{hostname} via aws-sdk")
86
69
  end
87
70
 
@@ -89,10 +72,10 @@ module Sortinghat
89
72
  # Returns nothing
90
73
  def setroute53(zone, fqdn)
91
74
  # Create a new client, and use it to update/insert our A record
92
- Aws::Route53::Client.new(region: @region).change_resource_record_sets({
75
+ Aws::Route53::Client.new(region: @region).change_resource_record_sets(
93
76
  hosted_zone_id: zonetoid(zone),
94
77
  change_batch: {
95
- comment: "Sorting Hat #{Date.today.to_s}",
78
+ comment: "Sorting Hat #{Date.today}",
96
79
  changes: [
97
80
  {
98
81
  action: 'UPSERT',
@@ -100,22 +83,18 @@ module Sortinghat
100
83
  name: fqdn,
101
84
  type: 'A',
102
85
  ttl: '30',
103
- resource_records: [
104
- {
105
- value: grabinstanceprivateip()
106
- },
107
- ],
108
- },
109
- },
110
- ],
111
- },
112
- })
86
+ resource_records: [{ value: grabinstanceprivateip }]
87
+ }
88
+ }
89
+ ]
90
+ }
91
+ )
113
92
  @log.info("Issued UPSERT to Route53 for #{fqdn}")
114
93
  end
115
94
 
116
- def privateip()
117
- return grabinstanceprivateip()
118
- end
95
+ def privateip
96
+ grabinstanceprivateip
97
+ end
119
98
 
120
99
  private
121
100
 
@@ -126,20 +105,30 @@ module Sortinghat
126
105
  end
127
106
 
128
107
  def zonetoid(hostedzone)
129
- resp = Aws::Route53::Client.new(region: @region).list_hosted_zones()
108
+ resp = Aws::Route53::Client.new(region: @region).list_hosted_zones
130
109
  resp.hosted_zones.each do |zone|
131
- if zone.name == hostedzone
132
- return zone.id
133
- end
110
+ return zone.id if zone.name == hostedzone
134
111
  end
135
112
  end
136
113
 
137
- def grabinstanceid()
138
- return Net::HTTP.get_response(URI.parse("http://169.254.169.254/latest/meta-data/instance-id")).body
114
+ def grabinstanceid
115
+ Net::HTTP.get_response(URI.parse('http://169.254.169.254/latest/meta-data/instance-id')).body
116
+ end
117
+
118
+ def grabinstanceprivateip
119
+ Net::HTTP.get_response(URI.parse('http://169.254.169.254/latest/meta-data/local-ipv4')).body
139
120
  end
140
121
 
141
- def grabinstanceprivateip()
142
- return Net::HTTP.get_response(URI.parse("http://169.254.169.254/latest/meta-data/local-ipv4")).body
122
+ def find_own_autoscale_name
123
+ # Use the client to describe this instances autoscale
124
+ current_as = @autoscale_client.describe_auto_scaling_instances(
125
+ instance_ids: [grabinstanceid],
126
+ max_records: 1
127
+ )
128
+ @log.info('Grabbed current AutoScaling instance via aws-sdk')
129
+
130
+ # Return current autoscale name
131
+ current_as.auto_scaling_instances[0].auto_scaling_group_name
143
132
  end
144
133
  end
145
134
  end
@@ -3,19 +3,22 @@ require 'fileutils'
3
3
 
4
4
  module Sortinghat
5
5
  class Banquet
6
+ def self.assign_house(options = {})
7
+ this = new(options)
8
+ this.dejavu?
9
+ this.start!
10
+ end
6
11
 
7
12
  # Creation method
8
13
  def initialize(options = {})
9
14
  # Check that we have write premissions
10
- checkpermissions()
15
+ checkpermissions
11
16
 
12
17
  # Create a syslog for us to use as an instance variable
13
18
  @log = Syslog::Logger.new 'sortinghat'
14
19
 
15
20
  # Append a trailing dot to the zone, if there isn't one
16
- if options[:zone][-1, 1] != '.'
17
- options[:zone] << '.'
18
- end
21
+ options[:zone] << '.' if options[:zone][-1, 1] != '.'
19
22
 
20
23
  # Save the options as instance variable
21
24
  @options = options
@@ -27,7 +30,7 @@ module Sortinghat
27
30
  # Method to figure out if we've been here before
28
31
  def dejavu?
29
32
  # Check for sentinel file
30
- if File.exists?('/etc/.sorted')
33
+ if File.exist?('/etc/.sorted')
31
34
  # We found it, log error and exit successfully
32
35
  @log.info('Found /etc/.sorted, refusing to sort.')
33
36
  exit 0
@@ -36,51 +39,25 @@ module Sortinghat
36
39
 
37
40
  # Main method of Sortinghat
38
41
  def start!
39
-
40
- # Best thing to avoid run conditions are to wait
41
- sleep rand(10)
42
-
43
- # Find out who is who, instances alive
44
- # If discover() returns an Array full of nil(s), alive will become an empty Array
45
- alive = cleanup(@aws.discover())
46
-
47
- # Given the alive instances, find our prefix
48
- # If alive an empty array, selection will return the number '1'
49
- @prefix = ensurezero(selection(alive))
50
-
51
- # Put together hostname/fqdn
52
- construction()
42
+ construct_hostname
53
43
 
54
44
  # Set the Name tag on this instance
55
45
  @aws.settag!(@hostname)
56
46
 
57
- # Find out who is who, instances alive
58
- # If discover() returns an Array full of nil(s), alive will become an empty Array
59
- alive = cleanup(@aws.discover())
60
-
61
- # Only enter recursion if the uniq() length of the alive array does not equal the actual length
62
- # On AutoScalingGroup initalization, the cleanup() should ensure the alive array is empty not nil so uniq() works
63
- unless alive.uniq.length == alive.length
64
- # There are duplicates, remove tag, wait, restart
65
- @aws.removetag!()
66
- sleep rand(10)
67
- start!()
68
- end
69
-
70
47
  # Register in DNS
71
48
  @aws.setroute53(@options[:zone], @fqdn)
72
49
 
73
50
  # Set the localhost hostname
74
- setlocal()
51
+ setlocal
75
52
 
76
53
  # Set /etc/hosts
77
- sethostsfile()
54
+ sethostsfile
78
55
 
79
56
  # Throw the hostname in /etc/sysconfig/httpd (if exists)
80
- givetohttpd()
57
+ givetohttpd
81
58
 
82
59
  # All done
83
- finish!()
60
+ finish!
84
61
  end
85
62
 
86
63
  # Last method of Sortinghat
@@ -92,7 +69,7 @@ module Sortinghat
92
69
  private
93
70
 
94
71
  # Method to check that we have write permissions to /etc/*
95
- def checkpermissions()
72
+ def checkpermissions
96
73
  unless File.stat('/etc/hosts').writable?
97
74
  # We found it, log error and exit successfully
98
75
  @log.error('Can not write to /etc, missing required permissions.')
@@ -103,71 +80,87 @@ module Sortinghat
103
80
  # Method to cleanup the array returned by aws.discover()
104
81
  # Remove nil values basically
105
82
  def cleanup(array)
106
- clean = array.reject { |item| item.nil? }
83
+ clean = array.reject(&:nil?)
107
84
  return [] if clean.empty?
108
85
  clean
109
86
  end
110
87
 
111
- # Method to consume the alive array and figure out what this instance's prefix should be
88
+ # Cconsume the alive array and return array of available suffix
112
89
  def selection(array)
113
- # If array is empty, just return 01
114
- return 1 if array.empty?
90
+ array = cleanup(array)
115
91
 
116
- # Array to store the numbers already taken
117
- taken = Array.new
92
+ # If array is empty, just return 01
93
+ return [1] if array.empty?
118
94
 
119
95
  # Filter the incoming array, find the numbers and store them in the taken Array
120
- array.each { |string| taken << string.scan(/\d./).join('').sub(/^0+/, '').to_i }
96
+ taken = array.map { |str| str[/^.*\D(\d{2,}).*/, 1].sub(/^0+/, '').to_i }
121
97
 
122
98
  # We have two digits, define our range of numbers
123
99
  limits = (1..99).to_a
124
100
 
125
- # Return the first value once we find what isn't taken in our range of numbers
126
- (limits - taken)[0]
101
+ # Return the avilable values once we find what isn't taken in our range of numbers
102
+ limits - taken
103
+ end
104
+
105
+ def construct_hostname
106
+ # Get array of hostnames in our scale group
107
+ scalegroup_hosts = @aws.discover
108
+
109
+ # determine the next available suffix
110
+ selection(scalegroup_hosts).find(method(:assignment_unclear)) do |candidate|
111
+ @suffix = ''
112
+ @suffix = ensurezero(candidate) if @options[:numbered]
113
+ construction
114
+ matches = @aws.search_hosts(@hostname)
115
+ matches.empty?
116
+ end
127
117
  end
128
118
 
129
- # Method to ensure our prefix always has a leading 0 if < 10
130
- def ensurezero(prefix)
131
- prefix < 10 ? prefix.to_s.rjust(2, "0") : prefix
119
+ # Method to ensure our suffix always has a leading 0 if < 10
120
+ def ensurezero(suffix)
121
+ return suffix.to_s.rjust(2, '0') if suffix < 10
122
+ suffix
132
123
  end
133
124
 
134
125
  # Method to construct our instance variables @hostname and @fqdn
135
- def construction()
136
- @hostname = "#{@options[:client]}-#{@options[:env]}-#{@options[:type]}#{@prefix.to_s}-#{@options[:region]}"
137
- @fqdn = "#{@options[:client]}-#{@options[:env]}-#{@options[:type]}#{@prefix.to_s}-#{@options[:region]}.#{@options[:zone]}"
126
+ def construction
127
+ @hostname = "#{@options[:client]}-#{@options[:env]}-#{@options[:type]}#{@suffix}-#{@options[:region]}"
128
+ @fqdn = "#{@options[:client]}-#{@options[:env]}-#{@options[:type]}#{@suffix}-#{@options[:region]}.#{@options[:zone]}"
129
+ end
130
+
131
+ def assignment_unclear
132
+ @suffix = ensurezero("#{rand(100)}")
133
+ construction
138
134
  end
139
135
 
140
136
  # Method to set the local hostname on this instance
141
- def setlocal()
137
+ def setlocal
142
138
  if system("hostnamectl set-hostname #{@fqdn}")
143
139
  @log.info("Set the localhost hostname to #{@fqdn}.")
144
140
  end
145
141
  end
146
142
 
147
- def sethostsfile()
143
+ def sethostsfile
148
144
  # Store the ip address so we only make one metadata call here
149
145
  privateip = @aws.privateip()
150
- if File.readlines('/etc/hosts').grep(/#{@hostname}|#{privateip}/).size < 1
146
+ if File.readlines('/etc/hosts').grep(/#{@hostname}|#{privateip}/).empty?
151
147
  File.open('/etc/hosts', 'a') do |file|
152
148
  file.puts "#{privateip} \t #{@hostname} #{@fqdn}"
153
149
  end
154
- @log.info("Added hostname(s) to /etc/hosts.")
150
+ @log.info('Added hostname(s) to /etc/hosts.')
155
151
  else
156
- @log.warn("The hostname(s) were already in /etc/hosts.")
152
+ @log.warn('The hostname(s) were already in /etc/hosts.')
157
153
  end
158
154
  end
159
155
 
160
- def givetohttpd()
156
+ def givetohttpd
161
157
  file = '/etc/sysconfig/httpd'
162
- if File.exists?(file)
163
- if File.readlines(file).grep(/HOSTNAME/).size < 1
164
- @log.info("Found #{file}, appending HOSTNAME=#{@hostname}.")
165
- File.open(file, 'a') do |file|
166
- file.puts "HOSTNAME=#{@hostname}"
167
- end
168
- else
169
- @log.warn("Found HOSTNAME already in #{file}")
170
- end
158
+ return unless File.exist?(file)
159
+ if File.readlines(file).grep(/HOSTNAME/).empty?
160
+ @log.info("Found #{file}, appending HOSTNAME=#{@hostname}.")
161
+ File.open(file, 'a') { |sysconfig| sysconfig.puts "HOSTNAME=#{@hostname}" }
162
+ else
163
+ @log.warn("Found HOSTNAME already in #{file}")
171
164
  end
172
165
  end
173
166
  end
@@ -1,3 +1,3 @@
1
1
  module Sortinghat
2
- VERSION = "0.3.3"
2
+ VERSION = '0.3.4.develop'.freeze
3
3
  end
data/sortinghat.gemspec CHANGED
@@ -31,6 +31,6 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "rake", "~> 10.0"
32
32
  spec.add_development_dependency "rspec"
33
33
 
34
- spec.add_runtime_dependency "aws-sdk", '2.1.2'
34
+ spec.add_runtime_dependency "aws-sdk", "~> 2.1.2"
35
35
  spec.add_runtime_dependency "json_pure"
36
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sortinghat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4.develop
5
5
  platform: ruby
6
6
  authors:
7
7
  - D. Pramann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-21 00:00:00.000000000 Z
11
+ date: 2019-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -56,14 +56,14 @@ dependencies:
56
56
  name: aws-sdk
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '='
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: 2.1.2
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '='
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 2.1.2
69
69
  - !ruby/object:Gem::Dependency
@@ -118,12 +118,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
118
118
  version: '0'
119
119
  required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - ">="
121
+ - - ">"
122
122
  - !ruby/object:Gem::Version
123
- version: '0'
123
+ version: 1.3.1
124
124
  requirements: []
125
125
  rubyforge_project:
126
- rubygems_version: 2.4.8
126
+ rubygems_version: 2.7.7
127
127
  signing_key:
128
128
  specification_version: 4
129
129
  summary: Have auto-scaling instances name themselves!