jack-eb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,107 @@
1
+ module Jack
2
+ class CLI < Thor
3
+ class Help
4
+ class << self
5
+ def convention
6
+ <<-EOL
7
+ The configuration name is based on convention. An environment with the name of stag-rails-app-s1 results in the jack/cfg/stag-rails-app.cfg.yml being used. The convention can be overriden with the --cfg option.
8
+ EOL
9
+ end
10
+
11
+ def create
12
+ <<-EOL
13
+ Creates a new environment using the configuration in jack/cfg folder.
14
+
15
+ #{convention}
16
+
17
+ Example:
18
+
19
+ $ jack create stag-rails-app-s1
20
+
21
+ $ jack create -c myconfig stag-rails-app-s1
22
+
23
+ $ jack create -a myapp -c myconfig stag-rails-app-s1
24
+ EOL
25
+ end
26
+
27
+ def upload
28
+ <<-EOL
29
+ Uploads the specified template configuration in jack/cfg and applies it to the environment immediately.
30
+
31
+ #{convention}
32
+
33
+ Example:
34
+
35
+ $ jack config upload stag-rails-app-s1
36
+
37
+ $ jack config upload -a myapp -c myconfig stag-rails-app-s1
38
+ EOL
39
+ end
40
+
41
+ def download
42
+ <<-EOL
43
+ Downloads the environment's config to jack/cfg/[CONFIG_NAME].cfg.yml
44
+
45
+ #{convention}
46
+
47
+ Example:
48
+
49
+ $ jack config download stag-rails-app-s1
50
+
51
+ $ jack config download -a myapp -c myconfig stag-rails-app-s1
52
+ EOL
53
+ end
54
+
55
+
56
+ def diff
57
+ <<-EOL
58
+ Diff local jack config vs environment config. The environment config is generated on the fly.
59
+
60
+ If you have colordiff installed the diff command will use make use of it. If you want to have your own custom diff, you can set your JACK_DIFF environment variable to it.
61
+
62
+ #{convention}
63
+
64
+ Example:
65
+
66
+ $ jack config diff stag-rails-app-s1
67
+
68
+ $ jack config diff -a myapp -c myconfig stag-rails-app-s1
69
+ EOL
70
+ end
71
+
72
+ def sort
73
+ <<-EOL
74
+ Reformats local jack config file to a sorted yaml format.
75
+
76
+ #{convention}
77
+
78
+ Example:
79
+
80
+ $ jack config sort stag-rails-app-s1
81
+
82
+ $ jack config sort -c myconfig stag-rails-app-s1 # env name doesnt matter here
83
+ EOL
84
+ end
85
+
86
+ # dumb thor bug, so this doesnt even show, leaving here in case Thor is fixed
87
+ def config
88
+ <<-EOL
89
+ Manage the environment's config. Can use this to download the environment's config to jack/cfg folder or upload config in jack/cfg folder and apply it to the environment.
90
+
91
+ Example:
92
+
93
+ $ jack config download stag-rails-app-s1
94
+
95
+ For more info:
96
+
97
+ $ jack help config
98
+
99
+ $ jack config help apply
100
+
101
+ $ jack config help download
102
+ EOL
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,13 @@
1
+ require 'fileutils'
2
+
3
+ module Jack
4
+ module Config
5
+ autoload :Base, 'jack/config/base'
6
+ autoload :Diff, 'jack/config/diff'
7
+ autoload :Download, 'jack/config/download'
8
+ autoload :Sort, 'jack/config/sort'
9
+ autoload :Transmit, 'jack/config/transmit'
10
+ autoload :Upload, 'jack/config/upload'
11
+ autoload :YamlFormatter, 'jack/config/yaml_formatter'
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ module Jack
2
+ module Config
3
+ class Diff
4
+ attr_reader :transmit
5
+ def initialize(options={})
6
+ @options = options
7
+ @root = options[:root] || '.'
8
+ @env_name = options[:env_name]
9
+ @download = Jack::Config::Download.new(options)
10
+ end
11
+
12
+ def run
13
+ @download.get_current_cfg
14
+ do_diff(@download.current_path, @download.local_config_path)
15
+ cleanup_files
16
+ end
17
+
18
+ def do_diff(current, local)
19
+ UI.say "Comparing #{current} and #{local}"
20
+ return if @options[:noop]
21
+ sorter = YamlFormatter.new
22
+ sorter.process(current)
23
+ sorter.process(local)
24
+ # need to use system so that the diff shows up properly in the terminal
25
+ system(diff_command, @download.current_path, @download.local_config_path)
26
+ puts ""
27
+ end
28
+
29
+ def cleanup_files
30
+ return false if @options[:dirty]
31
+ @download.clean(silent=true)
32
+ end
33
+
34
+ def diff_command
35
+ return ENV['JACK_DIFF'] if ENV['JACK_DIFF']
36
+ if system("type colordiff > /dev/null 2>&1")
37
+ "colordiff"
38
+ else
39
+ "diff"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,66 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+
4
+ module Jack
5
+ module Config
6
+ class Download < Transmit
7
+ include Util
8
+
9
+ attr_reader :current_path, :current_name
10
+
11
+ def initialize(options={})
12
+ super
13
+ @current_path = "#{@saved_configs}/current-#{timestamp}.cfg.yml"
14
+ @current_name = extract_name(@current_path)
15
+ end
16
+
17
+ def run
18
+ download
19
+ end
20
+
21
+ def download
22
+ get_current_cfg
23
+ copy_to_local_cfg
24
+ clean
25
+ UI.say "Config downloaded to #{@local_config_path}".colorize(:green)
26
+ end
27
+
28
+ def get_current_cfg
29
+ UI.say "Downloading config file..."
30
+ eb_config_save
31
+ end
32
+
33
+ # for specs
34
+ def eb_config_save
35
+ do_cmd("eb config save --cfg #{current_name} #{@env_name}", @options)
36
+ end
37
+
38
+ def copy_to_local_cfg
39
+ UI.say "Writing to local config file: #{@local_config_path}"
40
+ dirname = File.dirname("#{@root}/#{@local_config_path}")
41
+ FileUtils.mkdir_p(dirname) unless File.exist?(dirname)
42
+ do_copy_to_local_cfg
43
+ end
44
+
45
+ # for specs
46
+ def do_copy_to_local_cfg
47
+ return if @options[:noop]
48
+ local_path = "#{@root}/#{@local_config_path}"
49
+ FileUtils.cp(@current_path, local_path)
50
+ YamlFormatter.new.process(local_path)
51
+ end
52
+
53
+ # remove both the local download file and remote eb config
54
+ def clean(silent=false)
55
+ return if @options[:dirty]
56
+ UI.say "Cleaning up eb remote config and local files" unless silent
57
+ eb.delete_configuration_template(
58
+ application_name: @app_name,
59
+ template_name: current_name
60
+ ) unless @options[:noop]
61
+ FileUtils.rm_f(@current_path)
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,19 @@
1
+ require 'fileutils'
2
+
3
+ module Jack
4
+ module Config
5
+ class Sort < Transmit # for the local_config_path method
6
+ include Util
7
+
8
+ def initialize(options={})
9
+ super
10
+ @options = options
11
+ end
12
+
13
+ def run
14
+ YamlFormatter.new.process("#{@root}/#{local_config_path}")
15
+ UI.say "Reformatted the local config to a sorted yaml format at #{local_config_path}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,77 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+
4
+ module Jack
5
+ module Config
6
+ class Transmit
7
+ include Util
8
+
9
+ attr_reader :local_config_path
10
+ def initialize(options={})
11
+ @options = options
12
+ @root = options[:root] || '.'
13
+ @env_name = options[:env_name]
14
+ @app_name = @options[:app_name] || app_name_convention(@env_name)
15
+
16
+ @saved_configs = "#{@root}/.elasticbeanstalk/saved_configs"
17
+
18
+ local_config_name = options[:cfg] || config_name_convention(@env_name)
19
+ @local_config_path = "jack/cfg/#{local_config_name}.cfg.yml"
20
+
21
+ sync_eb_config_yml
22
+ end
23
+
24
+ def eb_config_path
25
+ "#{@root}/.elasticbeanstalk/config.yml"
26
+ end
27
+
28
+ def sync_eb_config_yml(force=false)
29
+ # should break out to another class but too much work right now
30
+ create = Create.new(@options)
31
+ create.ensure_eb_init
32
+ do_sync_eb_config_yml(force)
33
+ end
34
+
35
+ private
36
+
37
+ # force flag for specs
38
+ def do_sync_eb_config_yml(force)
39
+ return if @options[:noop] and !force
40
+ envs = describe_environments
41
+ env = envs[:environments].first
42
+ if env
43
+ write_eb_config_yml(env.application_name, env.solution_stack_name)
44
+ else
45
+ UI.say "#{@env_name} could not be found".colorize(:red)
46
+ exit 0
47
+ end
48
+ end
49
+
50
+ def write_eb_config_yml(application_name, solution_stack_name)
51
+ data = YAML.load_file(eb_config_path)
52
+ data['global']['application_name'] = application_name
53
+ data['global']['default_platform'] = solution_stack_name
54
+ dump = YAML.dump(data).gsub("!ruby/object:Hash", '')
55
+ dump = dump.split("\n")[1..-1].join("\n") # strip first line
56
+ File.write(eb_config_path, dump)
57
+ end
58
+
59
+ # useful for specs
60
+ def describe_environments
61
+ eb.describe_environments(environment_names: [@env_name])
62
+ end
63
+
64
+ def config_name_convention(env_name)
65
+ env_name.split('-')[0..-2].join('-')
66
+ end
67
+
68
+ def timestamp
69
+ Time.now.strftime "%Y-%m-%d_%H-%M-%S"
70
+ end
71
+
72
+ def extract_name(path)
73
+ path.split('/').last.sub('.cfg.yml','')
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,97 @@
1
+ require 'fileutils'
2
+
3
+ module Jack
4
+ module Config
5
+ class Upload < Transmit
6
+ include Util
7
+
8
+ attr_reader :upload_path, :upload_name
9
+
10
+ def initialize(options={})
11
+ super
12
+ @upload_path = "#{@saved_configs}/#{@env_name}-#{timestamp}.cfg.yml"
13
+ @upload_name = extract_name(@upload_path)
14
+ end
15
+
16
+ def run
17
+ unless local_cfg_exist?
18
+ UI.say "#{local_config_path} does not exist, nothing to upload"
19
+ exit 0
20
+ end
21
+ compare
22
+ if confirm
23
+ upload
24
+ update_env
25
+ end
26
+ end
27
+
28
+ def compare
29
+ Diff.new(@options).run
30
+ end
31
+
32
+ def upload
33
+ return false unless local_cfg_exist?
34
+ UI.say("Copying #{@local_config_path} to #{@upload_path} for the upload")
35
+ cp_to_save_configs
36
+ upload_to_eb
37
+ clean_up
38
+ end
39
+
40
+ def confirm
41
+ UI.say("Are you sure you want to update the environment with your the new config #{@config_path}?".colorize(:yellow))
42
+ UI.say(<<-EOL)
43
+ If the difference is not what you expected, you should say no.
44
+ A blank newline indicates that there was no difference.
45
+ If you want to download the config from the environment and
46
+ overwrite your #{@local_config_path} instead, you can use this command:
47
+ $ jack config download #{@env_name}
48
+ $ jack config help download # for more info
49
+ EOL
50
+ print "yes/no? [no] " unless @options[:silent]
51
+ answer = get_answer
52
+ answer =~ /^y/
53
+ end
54
+
55
+ def get_answer
56
+ return 'y' if @options[:force]
57
+ $stdin.gets
58
+ end
59
+
60
+ def update_env
61
+ UI.say("Updating environment #{@env_name} with template #{upload_name}")
62
+ eb.update_environment(
63
+ environment_name: @env_name,
64
+ template_name: upload_name
65
+ ) unless @options[:noop]
66
+ end
67
+
68
+ def local_cfg_exist?
69
+ File.exist?("#{@root}/#{@local_config_path}")
70
+ end
71
+
72
+ def cp_to_save_configs
73
+ ensure_folder_exist(@saved_configs)
74
+ FileUtils.cp("#{@root}/#{@local_config_path}", @upload_path)
75
+ end
76
+
77
+ def upload_to_eb
78
+ eb_config_put
79
+ end
80
+
81
+ # for specs
82
+ def eb_config_put
83
+ do_cmd("eb config put #{upload_name}", @options)
84
+ end
85
+
86
+ def clean_up
87
+ return if @options[:dirty]
88
+ FileUtils.rm_f(@upload_path)
89
+ end
90
+
91
+ def ensure_folder_exist(folder)
92
+ FileUtils.mkdir_p(folder) unless File.exist?(folder)
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,30 @@
1
+ require "yaml"
2
+
3
+ module Jack
4
+ module Config
5
+ # Class does very specific formatting for the eb config files:
6
+ #
7
+ # * Makes sure that the keys are sorted so we can compare them
8
+ # * It also scripts out the generated DateModified and DateCreated Metadata
9
+ class YamlFormatter
10
+ def process(file)
11
+ data = YAML.load_file(file)
12
+ data = strip_metadata_dates(data)
13
+ dump = YAML.dump(data).gsub("!ruby/object:Hash", '')
14
+ dump = dump.split("\n")[1..-1].join("\n") + "\n" # strip first line
15
+ outfile = "#{file}.sorted"
16
+ File.open(outfile, 'w') { |f| f.write(dump) }
17
+ FileUtils.mv(outfile, file)
18
+ end
19
+
20
+ def strip_metadata_dates(data)
21
+ metadata = data['EnvironmentConfigurationMetadata']
22
+ if metadata
23
+ metadata.delete('DateModified')
24
+ metadata.delete('DateCreated')
25
+ end
26
+ data
27
+ end
28
+ end
29
+ end
30
+ end