rebi 0.3.2 → 0.4.0

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 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