veronic 0.0.24 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OTQxNzQ2MmVkYTYzMjQyZGRmMzJiZjM4Y2QyMjRmNjU4ZTJjYWViYQ==
4
+ MWFmZDQxMDAyNTQxZDUzN2JmY2M1ZWMyZjJkM2FlOGU2ZWM2NTU4ZQ==
5
5
  data.tar.gz: !binary |-
6
- ZTNkMWQ5ZWY0NmZhMmNiMTMyMmI5NTc4MGI2NzU4MjQzMjRhZWUxMw==
6
+ Y2Y1MzYyMGU5MjI3M2ViY2JlNGUwYzY3MDE0MmQwZjkxM2RlMDA1Mg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NmQ4MTY1ZDlkYjY5NjdjN2QxMDhlY2RjYzk2OWMyNjA1MzBkN2E0MTBmNDQ4
10
- ZWVjZjA0NTI5ZTAxMTk2MTlmNGJlYmI1NjdmOGE1NmVhM2VhNTJiZTk2MzI5
11
- MGUyMjFiMGNkZGUxMmRhYTUyOGE3NjU3MTlkMzVkZjEyYmMxYjE=
9
+ MDA0ZTc4ODVmZDZkZTM0NWFkYzEzNTdiMDcyZTdmNWE0ZTU4NzZjMWE5MDY2
10
+ MTk5NTM1MzM3N2U0NGJkODg5NTg0NGE1YmQ5YjBlOTMzZDJmNTMxOWQ2OTdj
11
+ MmYzZGQ4N2UzMWRhYzg3NGU0MjIyYWM1MTZhZGU2YjYwMTA4MjU=
12
12
  data.tar.gz: !binary |-
13
- NzUwZDcyZDAwOTIxNGRlNjc1YjcyNmMwNDU1MmMzZjdlYmE1YTVjMWI1NWJi
14
- NjA5YjJmYjM0M2RlNWY4NjUzNjk1OTdkNGRlYTQwMGM2NmY4MmE2MDc4ZjY5
15
- ODkzMmNjNWM2ZGE1NmZmNDkwMTg1NDk3NmUwMzQyZjNiNmRmM2Q=
13
+ M2UwZjI2OTJmZDlkNTM5N2E1ZTFkYWE5N2FjM2MxNTljNzExZmNhNDUwM2Mx
14
+ Njk0NmM2NmJhMjBiZTM4M2U0MjZjZjEzM2U0MzM4NDc0N2Y4ZDU5ODdmZjg0
15
+ MzQ1OGU4NTEwZjkyYThjNGNmZGJjYjRiNWVmNDdjNTM3ZGQ5NTU=
data/bin/veronic CHANGED
@@ -154,11 +154,11 @@ opt_parser.parse!
154
154
 
155
155
  case ARGV[0] || ENV['action']
156
156
  when "create"
157
- Veronic::Deployer.new(options).create
157
+ Veronic::Deployer.new(options).create
158
158
  when "bootstrap"
159
159
  Veronic::Deployer.new(options).bootstrap
160
160
  when "destroy"
161
- Veronic::Deployer.new(options).destroy
161
+ Veronic::Deployer.new(options).destroy
162
162
  when "deploy"
163
163
  Veronic::Deployer.new(options).deploy
164
164
  when "search_and_deploy"
@@ -170,11 +170,11 @@ when "deploy_apps"
170
170
  when "run_tests"
171
171
  Veronic::Deployer.new(options).run_tests
172
172
  when "update_instance_dns"
173
- Veronic::Deployer.new(options).update_instance_dns
173
+ Veronic::Deployer.new(options).update_instance_dns
174
174
  when "stop"
175
- Veronic::Deployer.new(options).stop
175
+ Veronic::Deployer.new(options).stop
176
176
  when "start"
177
- Veronic::Deployer.new(options).start
177
+ Veronic::Deployer.new(options).start
178
178
  when "list"
179
179
  Veronic::Deployer.new(options).instances_list
180
180
  when "status"
@@ -183,5 +183,5 @@ when "create_image"
183
183
  image = Veronic::Deployer.new(options).create_image
184
184
  puts "ID: #{image.id}", "NAME: #{image.name}", "STATE: #{image.state}"
185
185
  else
186
- puts opt_parser
186
+ puts opt_parser
187
187
  end
data/lib/config/config.rb CHANGED
@@ -3,9 +3,12 @@ module Veronic
3
3
  attr_accessor :dnsprovider, :cloudprovider, :configprovider, :dnsprovider_access_key_id, :dnsprovider_secret_access_key, :cloudprovider_access_key_id, :cloudprovider_secret_access_key, :cloudprovider_images_owner_id, :dnsprovider_zones, :region, :availability_zone, :aws_ssh_key_id, :node_name, :client_key, :validation_client_name, :validation_key, :chef_server_url, :ssl_version, :identity_file, :branch, :environment, :ssh_user, :ssh_port, :role, :flavor, :security_groups, :deploy_cmd, :name, :image, :zone_name, :zone_url, :verbose, :query
4
4
 
5
5
  def initialize(options={})
6
- config_file = File.exists?('/etc/veronic/veronic.yml') ? '/etc/veronic/veronic.yml' : File.exists?('./veronic.yml') ? './veronic.yml' : nil
7
- if config_file || File.exists?(options[:config_file])
8
- config_from_file = YAML.load_file(options[:config_file] || config_file)
6
+ default_config_file = "/etc/veronic/veronic.yml"
7
+ config_from_file = Hash.new(nil)
8
+ if options[:config_file] && File.exists?(options[:config_file])
9
+ config_from_file = YAML.load_file(options[:config_file])
10
+ elsif File.exists?(default_config_file)
11
+ config_from_file = YAML.load_file(default_config_file)
9
12
  end
10
13
 
11
14
  @dnsprovider = options[:dnsprovider] || config_from_file['dnsprovider'] || :route53
@@ -33,7 +36,7 @@ module Veronic
33
36
  @ssh_port = options[:ssh_port] || config_from_file['ssh_port'] || 22
34
37
  @role = options[:role] || config_from_file['role']
35
38
  @flavor = options[:flavor] || config_from_file['flavor'] || 'm1.medium'
36
- @security_groups = options[:security_groups].split(',') || config_from_file['security_groups'].split(',')
39
+ @security_groups = (options[:security_groups] || 'default').split(',') || (config_from_file['security_groups'] || 'default').split(',')
37
40
  @deploy_cmd = options[:deploy_cmd] || config_from_file['deploy_cmd'] || 'sudo chef-client'
38
41
  @name = (options[:branch] || config_from_file['branch']) ? (options[:branch] || config_from_file['branch']) : (options[:name] || config_from_file['name'])
39
42
  @image = options[:ami_image] || config_from_file['ami_image']
@@ -4,17 +4,18 @@ module Provider
4
4
 
5
5
  def initialize(name)
6
6
  @name = name
7
+ @logger = Veronic::Deployer.new().logger
7
8
  end
8
9
 
9
10
  def destroy(name=nil)
10
- puts "Destroying client #{@name} from chef-server ..."
11
+ @logger.info "Destroying client #{@name} from chef-server ..."
11
12
  knife = Chef::Knife.new()
12
13
  knife.config[:yes] = true
13
14
  if self.exists?
14
15
  knife.delete_object(Chef::ApiClient, @name)
15
- puts "Client #{@name} destroy from chef-server"
16
+ @logger.info "Client #{@name} destroy from chef-server"
16
17
  else
17
- puts "Unabled to find client #{@name}"
18
+ @logger.info "Unabled to find client #{@name}"
18
19
  end
19
20
  end
20
21
 
@@ -1,124 +1,125 @@
1
1
  module Provider
2
- class ChefServer
3
- class Instance
4
-
5
- def initialize(config)
6
- @access_key_id = config[:cloudprovider_access_key_id]
7
- @secret_access_key = config[:cloudprovider_secret_access_key]
8
- @name = config[:name]
9
- @image = config[:image]
10
- @security_groups = config[:security_groups]
11
- @ssh_user = config[:ssh_user]
12
- @ssh_port = config[:ssh_port]
13
- @identity_file = config[:identity_file]
14
- @aws_ssh_key_id = config[:aws_ssh_key_id]
15
- @environment = config[:environment]
2
+ class ChefServer
3
+ class Instance
4
+
5
+ def initialize(config)
6
+ @access_key_id = config[:cloudprovider_access_key_id]
7
+ @secret_access_key = config[:cloudprovider_secret_access_key]
8
+ @name = config[:name]
9
+ @image = config[:image]
10
+ @security_groups = config[:security_groups]
11
+ @ssh_user = config[:ssh_user]
12
+ @ssh_port = config[:ssh_port]
13
+ @identity_file = config[:identity_file]
14
+ @aws_ssh_key_id = config[:aws_ssh_key_id]
15
+ @environment = config[:environment]
16
16
  @role = config[:role]
17
- @roles = "role[#{config[:role]}]"
18
- @flavor = config[:flavor]
19
- @region = config[:region]
20
- @availability_zone = config[:availability_zone]
21
- @verbose = config[:verbose]
22
- Chef::Config[:knife][:image] = @image
23
- Chef::Config[:knife][:aws_ssh_key_id] = @aws_ssh_key_id
24
- Chef::Config[:knife][:aws_access_key_id] = @access_key_id
25
- Chef::Config[:knife][:aws_secret_access_key] = @secret_access_key
26
- Chef::Config[:knife][:region] = @region
27
- Chef::Config[:knife][:availability_zone] = @availability_zone
28
- Chef::Config[:knife][:log_level] = @verbose
29
- end
30
-
31
- def create
32
- puts "Creating ec2 server #{@name} ..."
33
-
34
- node = Chef::Knife::Ec2ServerCreate.new()
35
-
36
- node.config[:run_list] = [@roles]
37
- node.config[:image] = @image
38
- node.config[:flavor] = @flavor
39
- node.config[:security_groups] = @security_groups
40
- node.config[:ssh_user] = @ssh_user
41
- node.config[:ssh_port] = @ssh_port
42
- node.config[:chef_node_name] = @name
43
- node.config[:identity_file] = @identity_file
44
- node.config[:environment] = @environment
45
- node.config[:log_level] = @verbose
46
-
47
- puts node.config
48
- node.run
49
- end
50
-
51
- def bootstrap(recursive_count=0)
52
- puts "Bootstrapping ec2 server #{@name} ..."
53
-
54
- node = Chef::Knife::Ec2ServerCreate.new()
55
-
56
- node.config[:image] = @image
57
- node.config[:flavor] = @flavor
58
- node.config[:security_groups] = @security_groups
59
- node.config[:ssh_user] = @ssh_user
60
- node.config[:ssh_port] = @ssh_port
61
- node.config[:chef_node_name] = @name
62
- node.config[:identity_file] = @identity_file
63
- node.config[:environment] = @environment
64
- node.config[:log_level] = @verbose
65
-
66
- puts node.config
67
- begin
68
- node.run
69
- rescue => e
70
- puts "Creation of #{@name} failed"
71
- puts "Message: " + e.inspect
72
- puts "Stacktrace:#{e.backtrace.map {|l| " #{l}\n"}.join}"
73
- self.destroy([node.server.id]) if node.server
74
- if recursive_count < 10
75
- puts "Creation of #{@name} retrying #{recursive_count}"
76
- self.bootstrap(recursive_count+=1)
77
- else
78
- puts "Creation of #{@name} failed after #{recursive_count} retry"
79
- exit 1
80
- end
81
- end
82
- end
83
-
84
- def destroy(instance_ids=[])
85
- puts "Deleting ec2 server #{@name} ..."
86
-
87
- node = Chef::Knife::Ec2ServerDelete.new()
88
-
89
- node.config[:purge] = true
90
- node.config[:chef_node_name] = @name
91
- node.config[:yes] = true
92
- node.name_args = instance_ids
93
-
94
- puts node.config
95
- node.run
96
- node.destroy_item(Chef::Node, @name, "node")
97
- node.destroy_item(Chef::ApiClient, @name, "client")
98
- end
99
-
100
- def set_role
101
- node = Chef::Knife::NodeRunListAdd.new()
102
- node.name_args = [@name, @roles]
103
- node.run
104
- end
105
-
106
- def set_environment
107
- node = Chef::Node.new.tap do |n|
108
- n.name( @name )
17
+ @roles = "role[#{config[:role]}]"
18
+ @flavor = config[:flavor]
19
+ @region = config[:region]
20
+ @availability_zone = config[:availability_zone]
21
+ @verbose = config[:verbose]
22
+ Chef::Config[:knife][:image] = @image
23
+ Chef::Config[:knife][:aws_ssh_key_id] = @aws_ssh_key_id
24
+ Chef::Config[:knife][:aws_access_key_id] = @access_key_id
25
+ Chef::Config[:knife][:aws_secret_access_key] = @secret_access_key
26
+ Chef::Config[:knife][:region] = @region
27
+ Chef::Config[:knife][:availability_zone] = @availability_zone
28
+ Chef::Config[:knife][:log_level] = @verbose
29
+ @logger = Veronic::Deployer.new().logger
30
+ end
31
+
32
+ def create
33
+ @logger.info "Creating ec2 server #{@name} ..."
34
+
35
+ node = Chef::Knife::Ec2ServerCreate.new()
36
+
37
+ node.config[:run_list] = [@roles]
38
+ node.config[:image] = @image
39
+ node.config[:flavor] = @flavor
40
+ node.config[:security_groups] = @security_groups
41
+ node.config[:ssh_user] = @ssh_user
42
+ node.config[:ssh_port] = @ssh_port
43
+ node.config[:chef_node_name] = @name
44
+ node.config[:identity_file] = @identity_file
45
+ node.config[:environment] = @environment
46
+ node.config[:log_level] = @verbose
47
+
48
+ @logger.info node.config
49
+ node.run
50
+ end
51
+
52
+ def bootstrap(recursive_count=0)
53
+ @logger.info "Bootstrapping ec2 server #{@name} ..."
54
+
55
+ node = Chef::Knife::Ec2ServerCreate.new()
56
+
57
+ node.config[:image] = @image
58
+ node.config[:flavor] = @flavor
59
+ node.config[:security_groups] = @security_groups
60
+ node.config[:ssh_user] = @ssh_user
61
+ node.config[:ssh_port] = @ssh_port
62
+ node.config[:chef_node_name] = @name
63
+ node.config[:identity_file] = @identity_file
64
+ node.config[:environment] = @environment
65
+ node.config[:log_level] = @verbose
66
+
67
+ @logger.info node.config
68
+ begin
69
+ node.run
70
+ rescue => e
71
+ @logger.info "Creation of #{@name} failed"
72
+ @logger.info "Message: " + e.inspect
73
+ @logger.info "Stacktrace:#{e.backtrace.map {|l| " #{l}\n"}.join}"
74
+ self.destroy([node.server.id]) if node.server
75
+ if recursive_count < 10
76
+ @logger.info "Creation of #{@name} retrying #{recursive_count}"
77
+ self.bootstrap(recursive_count+=1)
78
+ else
79
+ @logger.info "Creation of #{@name} failed after #{recursive_count} retry"
80
+ exit 1
81
+ end
82
+ end
83
+ end
84
+
85
+ def destroy(instance_ids=[])
86
+ @logger.info "Deleting ec2 server #{@name} ..."
87
+
88
+ node = Chef::Knife::Ec2ServerDelete.new()
89
+
90
+ node.config[:purge] = true
91
+ node.config[:chef_node_name] = @name
92
+ node.config[:yes] = true
93
+ node.name_args = instance_ids
94
+
95
+ @logger.info node.config
96
+ node.run
97
+ node.destroy_item(Chef::Node, @name, "node")
98
+ node.destroy_item(Chef::ApiClient, @name, "client")
99
+ end
100
+
101
+ def set_role
102
+ node = Chef::Knife::NodeRunListAdd.new()
103
+ node.name_args = [@name, @roles]
104
+ node.run
105
+ end
106
+
107
+ def set_environment
108
+ node = Chef::Node.new.tap do |n|
109
+ n.name( @name )
109
110
  n.chef_environment( @environment )
110
111
  end
111
112
  node.save
112
- puts "Environment: #{@environment}"
113
- end
113
+ @logger.info "Environment: #{@environment}"
114
+ end
114
115
 
115
- def ssh(query, cmd_line, manual)
116
- knife_ssh = Chef::Knife::Ssh.new()
116
+ def ssh(query, cmd_line, manual)
117
+ knife_ssh = Chef::Knife::Ssh.new()
117
118
 
118
- knife_ssh.config[:manual] = manual
119
- knife_ssh.config[:ssh_user] = @ssh_user
120
- knife_ssh.config[:identity_file] = @identity_file
121
- knife_ssh.config[:log_level] = @verbose
119
+ knife_ssh.config[:manual] = manual
120
+ knife_ssh.config[:ssh_user] = @ssh_user
121
+ knife_ssh.config[:identity_file] = @identity_file
122
+ knife_ssh.config[:log_level] = @verbose
122
123
 
123
124
  unless manual
124
125
  if @environment
@@ -129,18 +130,18 @@ module Provider
129
130
  end
130
131
  end
131
132
 
132
- knife_ssh.name_args = [query, cmd_line]
133
- sys_status = knife_ssh.run
134
- end
133
+ knife_ssh.name_args = [query, cmd_line]
134
+ sys_status = knife_ssh.run
135
+ end
135
136
 
136
- def client
137
- Provider::ChefServer::Client.new(@name)
138
- end
137
+ def client
138
+ Provider::ChefServer::Client.new(@name)
139
+ end
139
140
 
140
- def delete_client_key(node, client_key="/etc/chef/client.pem")
141
- puts "Deleting client_key #{client_key}"
142
- self.ssh(node, "sudo chef-client -W > /dev/null ; sudo rm -f #{client_key}", true)
143
- end
144
- end
145
- end
141
+ def delete_client_key(node, client_key="/etc/chef/client.pem")
142
+ @logger.info "Deleting client_key #{client_key}"
143
+ self.ssh(node, "sudo chef-client -W > /dev/null ; sudo rm -f #{client_key}", true)
144
+ end
145
+ end
146
+ end
146
147
  end
@@ -7,6 +7,7 @@ module Provider
7
7
  @role = role
8
8
  @ami_name = ami_name
9
9
  @owner_id = owner_id
10
+ @logger = Veronic::Deployer.new().logger
10
11
  end
11
12
 
12
13
  def id
@@ -16,12 +17,12 @@ module Provider
16
17
  end
17
18
 
18
19
  def detroy
19
- puts "Destroying image #{@ami_name} ..."
20
+ @logger.info "Destroying image #{@ami_name} ..."
20
21
  if get_image
21
22
  begin
22
23
  get_image.deregister
23
24
  sleep 5
24
- puts "Image #{@ami_name} destroyed"
25
+ @logger.info "Image #{@ami_name} destroyed"
25
26
  rescue
26
27
  return false
27
28
  end
@@ -35,24 +36,24 @@ module Provider
35
36
 
36
37
  def get_image
37
38
  @get_image || AWS.memoize do
38
- puts "Getting image #{@ami_name}"
39
+ @logger.info "Getting image #{@ami_name}"
39
40
  my_image = @ec2.images.with_owner(@owner_id).select {|x| x.name == @ami_name}.first
40
41
  unless my_image
41
42
  my_image = @ec2.images[@ami_name]
42
43
  unless my_image.exists?
43
- puts "Unabled to found image #{@ami_name}"
44
+ @logger.info "Unabled to found image #{@ami_name}"
44
45
  return false
45
46
  end
46
47
  else
47
48
  while my_image.exists? == false && my_image.state != :failed
48
- print "."
49
+ @logger.info "."
49
50
  sleep 1
50
51
  end
51
52
  while my_image.state == :pending && my_image.state != :failed
52
- print "."
53
+ @logger.info "."
53
54
  sleep 1
54
55
  end
55
- puts ""
56
+ @logger.info ""
56
57
  end
57
58
  @get_image = my_image
58
59
  return @get_image
@@ -7,24 +7,25 @@ module Provider
7
7
  @name = name
8
8
  @instance = instance
9
9
  @ami_name = image || name
10
+ @logger = Veronic::Deployer.new().logger
10
11
  end
11
12
 
12
13
  def stop
13
- print "Stopping instance #{@name}..."
14
+ @logger.info "Stopping instance #{@name}..."
14
15
  if self.exist?
15
16
  @instance.stop
16
17
  i = 0
17
18
  while self.status != :stopped
18
- print "." ; sleep 3 ; i += 1
19
+ @logger.info "." ; sleep 3 ; i += 1
19
20
  return false if i > 120
20
21
  end
21
- puts "\nInstance #{@name} is stopped"
22
+ @logger.info "\nInstance #{@name} is stopped"
22
23
  end
23
24
  return true
24
25
  end
25
26
 
26
27
  def start
27
- print "Starting instance #{@name}..."
28
+ @logger.info "Starting instance #{@name}..."
28
29
  if self.exist?
29
30
  while self.status == :stopping
30
31
  sleep 2
@@ -32,21 +33,21 @@ module Provider
32
33
  @instance.start
33
34
  i = 0
34
35
  while self.status != :running
35
- print "." ; sleep 3 ; i += 1
36
+ @logger.info "." ; sleep 3 ; i += 1
36
37
  return false if i > 120
37
38
  end
38
- puts "\nInstance #{@name} is started"
39
+ @logger.info "\nInstance #{@name} is started"
39
40
  end
40
41
  return true
41
42
  end
42
43
 
43
44
  def exists?
44
- puts "Checking for ec2 server #{@name} ..."
45
+ @logger.info "Checking for ec2 server #{@name} ..."
45
46
  if AWS.memoize do @ec2.instances.any? {|x| x.tags['Name'] == @name && x.status != :shutting_down && x.status != :terminated} end
46
- puts "Instance #{@name} found"
47
+ @logger.info "Instance #{@name} found"
47
48
  return true
48
49
  else
49
- puts "Instance #{@name} is misssing"
50
+ @logger.info "Instance #{@name} is misssing"
50
51
  return false
51
52
  end
52
53
  end
@@ -78,24 +79,24 @@ module Provider
78
79
  end
79
80
 
80
81
  def create_image
81
- puts "Create image #{@ami_name}"
82
+ @logger.info "Create image #{@ami_name}"
82
83
  new_image = @instance.create_image(@ami_name, { :no_reboot => true })
83
84
  while new_image.exists? == false && new_image.state != :failed
84
- print "."
85
+ @logger.info "."
85
86
  sleep 1
86
87
  end
87
88
  while new_image.state == :pending && new_image.state != :failed
88
- print "."
89
+ @logger.info "."
89
90
  sleep 1
90
91
  end
91
- puts ""
92
+ @logger.info ""
92
93
  return new_image
93
94
  end
94
95
 
95
96
  def tags(hash={})
96
- puts "Tagging instance ..."
97
+ @logger.info "Tagging instance ..."
97
98
  hash.keys.each do |k|
98
- puts k + ': ' + hash[k]
99
+ @logger.info k + ': ' + hash[k]
99
100
  @instance.tags[k] = hash[k]
100
101
  end
101
102
  end
@@ -8,6 +8,7 @@ module Route53
8
8
  @values = values
9
9
  @type = type
10
10
  @ttl = ttl
11
+ @logger = Veronic::Deployer.new().logger
11
12
  end
12
13
 
13
14
  def get
@@ -23,13 +24,13 @@ module Route53
23
24
  end
24
25
 
25
26
  def wait_set
26
- print "Waitting for record { name: #{@name}, value: #{@values} }..."
27
+ @logger.info "Waitting for record { name: #{@name}, value: #{@values} }..."
27
28
  while !self.match?
28
- print "."
29
+ @logger.info "."
29
30
  self.set
30
31
  sleep 5
31
32
  end
32
- puts "\nRecord { name: #{@name}, value: #{@values} } updated"
33
+ @logger.info "\nRecord { name: #{@name}, value: #{@values} } updated"
33
34
  end
34
35
 
35
36
  def set
data/veronic.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'veronic'
3
- s.version = '0.0.24'
3
+ s.version = '0.0.26'
4
4
  s.date = '2013-04-05'
5
5
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
6
6
  s.summary = "Veronic, a simple cloud deployer"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: veronic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.24
4
+ version: 0.0.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Klein