rebi 0.3.2 → 0.4.0

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
2
  SHA1:
3
- metadata.gz: 8d5506d4a48ece06d7c2c3cc00b56e931ae6aeb3
4
- data.tar.gz: 27748616915072f0eb9de0f9c588a64680212598
3
+ metadata.gz: 5b3bc75f16245ff841a3e7c29293327662b472cb
4
+ data.tar.gz: 06e7e7422dd0486c9b5e9d97c57050b90c653fe8
5
5
  SHA512:
6
- metadata.gz: c8575bb0477ce90c205cdbbcf07000d508594281605d1e406d7ccfa6247ee4f47d6c0e3886deb139982d929b120f4af9a82b3c77936522f5aebc8f8c0b558988
7
- data.tar.gz: 1643039aaa197bbb8303b6ecbaa50ff3cb49522ab86b7f3e46ebaab129913403c6c477fe6e05098d24b3afef666ed99dde0738f5a663099d5e5b7100a22678e7
6
+ metadata.gz: f246e720ffdade2afa9bedcb788db84976633f33423fe4f31b1399b4719ff2328c212c974bace37771c74beaa30dabf70536eb821d123b0b90c1205e93da53da
7
+ data.tar.gz: b7b6e94f5fa07647dba0a27105c147ef6f6164a20d2b542e9f1161d15d4ac90ce8c31a06cdb8f2d1823ef7616ffcaf9c659e87a03c09b82ab113184f791c258a
data/README.md CHANGED
@@ -20,6 +20,13 @@ $ gem install rebi
20
20
 
21
21
  ## Usage
22
22
 
23
+ ### Init
24
+
25
+ ```bash
26
+ $ bundle exec rebi init staging web
27
+ # use profile option if you're using aws profile
28
+ ```
29
+
23
30
  ### Yaml config
24
31
  Default config file is `.rebi.yml` use `-c` to switch
25
32
  ```yaml
@@ -77,9 +84,11 @@ $ bundle exec rebi --help
77
84
 
78
85
  ### ERB in ebextensions config
79
86
  Use `rebi.env` to get environment variables config in .ebextensions
87
+ config file name must end with .config.erb
88
+
80
89
  ```yaml
81
90
  # Ex
82
- # .ebextensions/00-envrionments.config
91
+ # .ebextensions/00-envrionments.config.erb
83
92
  option_settings:
84
93
  - option_name: KEY
85
94
  value: <%= rebi.env[KEY] %>
data/bin/rebi CHANGED
@@ -109,10 +109,22 @@ end
109
109
  command :ssh do |c|
110
110
  c.syntax = 'rebi ssh stage env_name'
111
111
  c.description = "Ssh into instance"
112
- c.option '-s','--select', 'Get environment variables from config'
112
+ c.option '-s','--select', 'Select instance ids'
113
113
  c.action do |args, options|
114
114
  stage, env_name = args
115
115
  raise Rebi::Error.new("Stage cannot be nil") if stage.blank?
116
116
  Rebi.app.ssh_interaction stage, env_name, options.__hash__
117
117
  end
118
118
  end
119
+
120
+ command :init do |c|
121
+ c.syntax = "rebi init stage_name env_name"
122
+ c.description = "Init"
123
+ c.action do |args, options|
124
+ stage, env = args
125
+ raise Rebi::Error.new("Stage cannot be nil") if stage.blank?
126
+ raise Rebi::Error.new("Env cannot be blank") if env.blank?
127
+
128
+ Rebi.init stage, env
129
+ end
130
+ end
@@ -27,6 +27,8 @@ require 'rebi/config'
27
27
  require 'rebi/config_environment'
28
28
  require 'rebi/error'
29
29
  require 'rebi/ec2'
30
+ require 'rebi/eb'
31
+ require 'rebi/init_service'
30
32
  require 'rebi/version'
31
33
 
32
34
  # Dotenv.load
@@ -43,11 +45,11 @@ module Rebi
43
45
  end
44
46
 
45
47
  def eb c=nil
46
- @@eb = Aws::ElasticBeanstalk::Client.new
48
+ @@eb = Rebi::EB.new
47
49
  end
48
50
 
49
51
  def ec2
50
- @@ec2_client = Rebi::EC2.new Aws::EC2::Client.new
52
+ @@ec2_client = Rebi::EC2.new
51
53
  end
52
54
 
53
55
  def iam
@@ -71,4 +73,9 @@ module Rebi
71
73
  config.reload!
72
74
  end
73
75
 
76
+ def init stage_name, env_name
77
+ init = Rebi::InitService.new(stage_name, env_name)
78
+ init.execute
79
+ end
80
+
74
81
  end
@@ -171,6 +171,7 @@ module Rebi
171
171
  end
172
172
 
173
173
  def self.get_or_create_application app_name
174
+ raise "App name cannot be nil" if app_name.blank?
174
175
  begin
175
176
  return get_application app_name
176
177
  rescue Error::ApplicationNotFound
@@ -2,6 +2,7 @@ module Rebi
2
2
  class Config
3
3
  include Singleton
4
4
 
5
+ attr_accessor :data
5
6
  def initialize
6
7
  reload!
7
8
  end
@@ -41,12 +42,16 @@ module Rebi
41
42
  data[:app_name]
42
43
  end
43
44
 
45
+ def app_name=name
46
+ data[:app_name] = name
47
+ end
48
+
44
49
  def app_description
45
50
  data[:app_description] || "Created via rebi"
46
51
  end
47
52
 
48
53
  def stage stage
49
- data[:stages][stage] || raise(Rebi::Error::ConfigNotFound.new("Stage: #{stage}"))
54
+ data[:stages] && data[:stages][stage] || raise(Rebi::Error::ConfigNotFound.new("Stage: #{stage}"))
50
55
  end
51
56
 
52
57
  def timeout
@@ -74,14 +79,26 @@ module Rebi
74
79
  data[:stages].keys
75
80
  end
76
81
 
77
- private
78
82
  def data
79
- @data ||= YAML::load(ERB.new(IO.read(config_file)).result).with_indifferent_access
80
- raise Rebi::Error::ConfigInvalid.new("app_name cannot be nil") if @data[:app_name].blank?
81
- raise Rebi::Error::ConfigInvalid.new("stages cannot be nil") if @data[:stages].blank?
83
+ return @data unless @data.nil?
84
+ begin
85
+ @data = YAML::load(ERB.new(IO.read(config_file)).result).with_indifferent_access
86
+ rescue Errno::ENOENT
87
+ @data = {}.with_indifferent_access
88
+ end
82
89
  return @data
83
90
  end
84
91
 
92
+ def push_to_file
93
+ File.open(config_file, "wb") do |f|
94
+ f.write JSON.parse(data.to_json).to_yaml
95
+ end
96
+
97
+ Rebi.log "Saved config to #{config_file}"
98
+ Rebi.log "For more configs, please refer sample or github"
99
+ end
100
+
101
+ private
85
102
  def set_aws_config
86
103
  conf = {}
87
104
 
@@ -42,6 +42,16 @@ module Rebi
42
42
 
43
43
  DEFAULT_IAM_INSTANCE_PROFILE = "aws-elasticbeanstalk-ec2-role"
44
44
 
45
+
46
+ DEFAULT_CONFIG = {
47
+ tier: "web",
48
+ instance_type: "t2.micro",
49
+ instance_num: {
50
+ min: 1,
51
+ max: 1,
52
+ }
53
+ }
54
+
45
55
  def initialize stage, env_name, env_conf={}
46
56
  @raw_conf = env_conf.with_indifferent_access
47
57
  @stage = stage.to_sym
@@ -52,6 +62,11 @@ module Rebi
52
62
  @name ||= raw_conf[:name] || "#{env_name}-#{stage}"
53
63
  end
54
64
 
65
+
66
+ def name=n
67
+ raw_conf[:name] ||= @name = n
68
+ end
69
+
55
70
  def app_name
56
71
  Rebi.config.app_name
57
72
  end
@@ -71,7 +86,7 @@ module Rebi
71
86
  elsif cfg.present? && cfg[:EnvironmentTier].present? && cfg[:EnvironmentTier][:Name].present?
72
87
  cfg[:EnvironmentTier][:Name] == "Worker" ? :worker : :web
73
88
  else
74
- :web
89
+ DEFAULT_CONFIG[:tier].to_sym
75
90
  end
76
91
 
77
92
  @tier = if t == :web
@@ -128,6 +143,7 @@ module Rebi
128
143
  end
129
144
 
130
145
  def cfg_file
146
+ return nil
131
147
  @cfg_file ||= raw_conf[:cfg_file]
132
148
  return @cfg_file if @cfg_file.blank?
133
149
  return @cfg_file if Pathname.new(@cfg_file).absolute?
@@ -153,7 +169,7 @@ module Rebi
153
169
  end
154
170
 
155
171
  def solution_stack_name
156
- @solution_stack_name ||= raw_conf[:solution_stack_name] || "64bit Amazon Linux 2017.09 v2.6.0 running Ruby 2.4 (Puma)"
172
+ @solution_stack_name ||= raw_conf[:solution_stack_name] || "64bit Amazon Linux 2017.09 v2.6.5 running Ruby 2.4 (Puma)"
157
173
  end
158
174
 
159
175
  def platform_arn
@@ -170,6 +186,11 @@ module Rebi
170
186
  end
171
187
  end
172
188
 
189
+ def ebignore
190
+ return @ebignore ||= raw_conf[:ebignore] || ".ebignore"
191
+ end
192
+
193
+
173
194
  def raw_environment_variables
174
195
  raw_conf[:environment_variables] || {}
175
196
  end
@@ -0,0 +1,55 @@
1
+ class Rebi::EB
2
+
3
+ attr_reader :client
4
+ def initialize client=Aws::ElasticBeanstalk::Client.new
5
+ @client = client
6
+ end
7
+
8
+ def applications
9
+ client.describe_applications.applications.map(&:application_name)
10
+ end
11
+
12
+ def solution_stacks
13
+ @solution_stacks = client.list_available_solution_stacks.solution_stacks.map do |s|
14
+ stacks_from_string s
15
+ end
16
+ end
17
+
18
+ def platforms
19
+ @platforms ||= solution_stacks.map do |st|
20
+ st["platform"]
21
+ end.uniq
22
+ end
23
+
24
+ def versions_by_platform platform
25
+ raise "Invalid platform" unless platforms.include?(platform)
26
+
27
+ solution_stacks.select do |st|
28
+ st["platform"] == platform
29
+ end.map do |st|
30
+ st["version"]
31
+ end.uniq
32
+ end
33
+
34
+ def get_solution_stack platform, version
35
+ solution_stacks.find do |st|
36
+ st["platform"] == platform && st["version"] == version
37
+ end["solution_stack"]
38
+ end
39
+
40
+ def method_missing(m, *args, &block)
41
+ client.send(m, *args, &block)
42
+ end
43
+
44
+ private
45
+
46
+ def stacks_from_string s
47
+ res = {}.with_indifferent_access
48
+ res[:platform] = s.match('.+running\s([^0-9]+).*')&.captures&.first.try(:strip)
49
+ res[:version] = s.match('.+running\s(.*)')&.captures&.first.try(:strip)
50
+ res[:server] = s.match('(.*)\srunning\s.*')&.captures&.first.try(:strip)
51
+ res[:stack_version] = s.match('.+v([0-9.]+)\srunning\s.*')&.captures&.first.try(:strip)
52
+ res[:solution_stack] = s
53
+ res
54
+ end
55
+ end
@@ -5,7 +5,7 @@ module Rebi
5
5
 
6
6
  attr_reader :client
7
7
 
8
- def initialize client
8
+ def initialize client=Aws::EC2::Client.new
9
9
  @client = client
10
10
  end
11
11
 
@@ -182,7 +182,7 @@ module Rebi
182
182
  def create_app_version opts={}
183
183
  return if opts[:settings_only]
184
184
  start = Time.now.utc
185
- source_bundle = Rebi::ZipHelper.new.gen(self.config, opts)
185
+ source_bundle = Rebi::ZipHelper.new(self.config, opts).gen
186
186
  version_label = source_bundle[:label]
187
187
  key = "#{app_name}/#{version_label}.zip"
188
188
  log("Uploading source bundle: #{version_label}.zip")
@@ -303,8 +303,17 @@ module Rebi
303
303
 
304
304
  Rebi.ec2.authorize_ssh instance_id do
305
305
  user = "ec2-user"
306
- key_file = "~/.ssh/#{instance.key_name}.pem"
307
- raise Rebi::Error::KeyFileNotFound unless File.exists? File.expand_path(key_file)
306
+ key_files = [
307
+ "~/.ssh/#{instance.key_name}.pem",
308
+ "~/.ssh/#{instance.key_name}",
309
+ ]
310
+
311
+ key_file = key_files.find do |f|
312
+ File.exists? File.expand_path(f)
313
+ end
314
+
315
+ raise Rebi::Error::KeyFileNotFound unless key_file.present?
316
+
308
317
  cmd = "ssh -i #{key_file} #{user}@#{instance.public_ip_address}"
309
318
  log cmd
310
319
 
@@ -0,0 +1,109 @@
1
+ module Rebi
2
+
3
+ class InitService
4
+
5
+ include Rebi::Log
6
+
7
+ attr_reader :stage_name, :env_name, :stage, :env_data
8
+
9
+ def initialize stage_name, env_name
10
+ if config.app_name.blank?
11
+ config.app_name = get_appname
12
+ end
13
+ @stage_name = stage_name
14
+ @env_name = env_name
15
+ config.data[:stages] ||= {}.with_indifferent_access
16
+
17
+ begin
18
+ @stage = config.stage stage_name
19
+ raise "Already exists" if @stage.keys.include? env_name
20
+ rescue Rebi::Error::ConfigNotFound
21
+ config.data[:stages][stage_name] = {}.with_indifferent_access
22
+ end
23
+
24
+ config.data[:stages][stage_name].merge!({
25
+ env_name => ConfigEnvironment::DEFAULT_CONFIG.clone
26
+ }.with_indifferent_access)
27
+
28
+ @env_data = config.data[:stages][stage_name][env_name]
29
+ end
30
+
31
+ def config
32
+ Rebi.config
33
+ end
34
+
35
+ def eb
36
+ @eb ||= Rebi.eb
37
+ end
38
+
39
+ def execute
40
+ env_data.reverse_merge!({name: get_envname})
41
+ env_data[:solution_stack_name] = get_solution_stack
42
+ config.push_to_file
43
+ end
44
+
45
+ def get_appname
46
+ app_name = nil
47
+ if (apps = eb.applications).present?
48
+ idx = -1
49
+ while idx < 0 || idx > apps.count
50
+ apps.each.with_index do |app, idx|
51
+ log "#{idx + 1}: #{app}"
52
+ end
53
+ log "0: Create new application"
54
+ idx = ask_for_integer "Select application:"
55
+ end
56
+ app_name = idx > 0 ? apps[idx - 1] : nil
57
+ end
58
+
59
+ if app_name.blank?
60
+ app_name = ask_for_string "Enter application name:"
61
+ end
62
+
63
+ app_name
64
+ end
65
+
66
+ def get_envname
67
+ name = ask_for_string "Enter environment name(Default: #{default_envname}):"
68
+ name = name.chomp.gsub(/\s+/, "")
69
+
70
+ name = name.present? ? name : default_envname
71
+ name
72
+ end
73
+
74
+ def default_envname
75
+ "#{env_name}-#{stage_name}"
76
+ end
77
+
78
+ def get_solution_stack
79
+ idx = 0
80
+ platform = nil
81
+ version = nil
82
+ while idx <= 0 || idx > eb.platforms.count
83
+ eb.platforms.each.with_index do |pl, idx|
84
+ log "#{idx + 1}: #{pl}"
85
+ end
86
+ idx = ask_for_integer "Select platform:"
87
+ end
88
+
89
+ platform = eb.platforms[idx - 1]
90
+ versions = eb.versions_by_platform platform
91
+ idx = versions.count <= 1 ? 1 : 0
92
+
93
+ while idx <=0 || idx > versions.count
94
+ versions.each.with_index do |ver, idx|
95
+ log "#{idx + 1}: #{ver}"
96
+ end
97
+ idx = ask_for_integer "Select version:"
98
+ end
99
+
100
+ version = versions[idx - 1]
101
+
102
+ eb.get_solution_stack platform, version
103
+ end
104
+
105
+ def log_label
106
+ ""
107
+ end
108
+ end
109
+ end
@@ -1,7 +1,7 @@
1
1
  module Rebi
2
2
  module Log
3
3
  def log mes, label=self.log_label
4
- puts "#{label ? "#{colorize_prefix(label)}: " : ""}#{mes}"
4
+ puts "#{label.present? ? "#{colorize_prefix(label)}: " : ""}#{mes}"
5
5
  end
6
6
 
7
7
  def error mes, label=self.error_label
@@ -1,3 +1,3 @@
1
1
  module Rebi
2
- VERSION = '0.3.2'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -3,12 +3,18 @@ module Rebi
3
3
 
4
4
  include Rebi::Log
5
5
 
6
- EB_IGNORE = ".ebignore"
6
+ attr_reader :env_conf, :opts
7
7
 
8
- def initialize
8
+ def initialize env_conf,opts={}
9
+ @env_conf = env_conf
10
+ @opts = opts
9
11
  # raise Rebi::Error::NoGit.new("Not a git repository") unless git?
10
12
  end
11
13
 
14
+ def staged?
15
+ opts[:staged]
16
+ end
17
+
12
18
  def git?
13
19
  `git status 2>&1`
14
20
  $?.success?
@@ -18,13 +24,13 @@ module Rebi
18
24
  `git ls-files 2>&1`.split("\n")
19
25
  end
20
26
 
21
- def raw_zip_archive opts={}
27
+ def raw_zip_archive
22
28
  tmp_file = Tempfile.new("git_archive")
23
29
  if !git? || ebignore?
24
30
  Zip::File.open(tmp_file.path, Zip::File::CREATE) do |z|
25
31
  spec = ebignore_spec
26
32
  Dir.glob("**/*").each do |f|
27
- next if ebignore_spec.match f
33
+ next if spec.match f
28
34
  if File.directory?(f)
29
35
  z.mkdir f unless z.find_entry f
30
36
  else
@@ -33,7 +39,7 @@ module Rebi
33
39
  end
34
40
  end
35
41
  else
36
- commit_id = opts[:staged] ? `git write-tree`.chomp : "HEAD"
42
+ commit_id = staged? ? `git write-tree`.chomp : "HEAD"
37
43
  system "git archive --format=zip #{commit_id} > #{tmp_file.path}"
38
44
  end
39
45
  return tmp_file
@@ -48,27 +54,35 @@ module Rebi
48
54
  end
49
55
 
50
56
  # Create zip archivement
51
- def gen env_conf,opts={}
57
+ def gen
52
58
  log("Creating zip archivement", env_conf.name)
53
59
  start = Time.now
54
60
  ebextensions = env_conf.ebextensions
55
- tmp_file = raw_zip_archive opts
61
+ tmp_file = raw_zip_archive
56
62
  tmp_folder = Dir.mktmpdir
57
63
  Zip::File.open(tmp_file.path) do |z|
58
64
  ebextensions.each do |ex_folder|
59
-
60
- z.remove_folder ex_folder unless ex_folder == ".ebextension"
61
- Dir.glob("#{ex_folder}/*.config") do |fname|
65
+ z.remove_folder ex_folder unless ex_folder == ".ebextensions"
66
+ Dir.glob("#{ex_folder}/*.config*") do |fname|
62
67
  next unless File.file?(fname)
63
- next unless y = YAML::load(ErbHelper.new(File.read(fname), env_conf).result)
68
+
64
69
  basename = File.basename(fname)
65
- target = ".ebextensions/#{basename}"
66
- tmp_yaml = "#{tmp_folder}/#{basename}"
67
- File.open(tmp_yaml, 'w') do |f|
68
- f.write y.to_yaml
70
+ source_file = fname
71
+
72
+ if fname.match(/\.erb$/)
73
+ next unless y = YAML::load(ErbHelper.new(File.read(fname), env_conf).result)
74
+ basename = basename.gsub(/\.erb$/,'')
75
+ source_file = "#{tmp_folder}/#{basename}"
76
+ File.open(source_file, 'w') do |f|
77
+ f.write y.to_yaml
78
+ end
69
79
  end
80
+
81
+ target = ".ebextensions/#{basename}"
82
+
70
83
  z.remove target if z.find_entry target
71
- z.add target, tmp_yaml
84
+ z.remove fname if z.find_entry fname
85
+ z.add target, source_file
72
86
  end
73
87
  end
74
88
  dockerrun_file = env_conf.dockerrun || "Dockerrun.aws.json"
@@ -87,8 +101,6 @@ module Rebi
87
101
  end
88
102
 
89
103
  FileUtils.rm_rf tmp_folder
90
-
91
-
92
104
  log("Zip was created in: #{Time.now - start}s", env_conf.name)
93
105
  return {
94
106
  label: Time.now.strftime("app_#{env_conf.name}_#{version_label}_%Y%m%d_%H%M%S"),
@@ -99,7 +111,7 @@ module Rebi
99
111
 
100
112
  def ebignore_spec
101
113
  if ebignore?
102
- path_spec = PathSpec.from_filename(EB_IGNORE)
114
+ path_spec = PathSpec.from_filename(ebignore)
103
115
  path_spec.add(".git")
104
116
  return path_spec
105
117
  else
@@ -108,9 +120,12 @@ module Rebi
108
120
  end
109
121
 
110
122
  def ebignore?
111
- File.exist?(EB_IGNORE)
123
+ File.exist?(ebignore)
112
124
  end
113
125
 
126
+ def ebignore
127
+ env_conf.ebignore
128
+ end
114
129
  end
115
130
  end
116
131
 
@@ -37,12 +37,12 @@ stages: #Required: Hash
37
37
  # - web_extensions
38
38
  # - web1_extensions
39
39
  # Result will has 01.config, 02.config(from web1_extensions) and 03.config
40
- cfg_file: File path or cfg name # Optional
41
40
 
42
41
  dockerrun: Dockerrun.aws.json.stg # Dockerrun file
43
42
  options: #Hash, Other custom options for using in erb
44
43
  use_basic: true # rebi.opts.use_basic
45
44
 
45
+ ebignore: .ebignore_web #Optional
46
46
  hooks:
47
47
  pre: ls # String or Array, run before upload source bundle
48
48
  post: ls # String or Array, run right after sending deploy request
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rebi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - KhiemNS
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-20 00:00:00.000000000 Z
11
+ date: 2018-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -195,10 +195,12 @@ files:
195
195
  - lib/rebi/application.rb
196
196
  - lib/rebi/config.rb
197
197
  - lib/rebi/config_environment.rb
198
+ - lib/rebi/eb.rb
198
199
  - lib/rebi/ec2.rb
199
200
  - lib/rebi/environment.rb
200
201
  - lib/rebi/erb_helper.rb
201
202
  - lib/rebi/error.rb
203
+ - lib/rebi/init_service.rb
202
204
  - lib/rebi/log.rb
203
205
  - lib/rebi/version.rb
204
206
  - lib/rebi/zip_helper.rb