jack-eb 0.0.1

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