awx 0.2.0 → 0.3.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: a22d18dbf189673739f5963a622151a85e814a1e
4
- data.tar.gz: 8b61eee5e62db727d1c105df70588e2fa0209434
3
+ metadata.gz: f9b808a6cbb91894ebd76305daa497467f62018a
4
+ data.tar.gz: 368253cb9c5c47013181e6e570b5ce216bf124b9
5
5
  SHA512:
6
- metadata.gz: 21cc5951d290166128b6eaa29b25de3ed4206744625013c2e420996827b47a7bfdfef276a0c5e2dffdba822e2ee353e95ba1115490c895099e29af3a34ace8fa
7
- data.tar.gz: c9723e5ca2518609c52228387e2886ae85a272beed50a9392acd8953b8aa0972452a861ee5f931820fabe25ca39106e4ba0f5ecd39893ba93706dd3ec1cf238c
6
+ metadata.gz: ff832f18916908040ef981c4f6823feeb0c33f7625d61d212036911a064ddfa453da307ab51491ce6e9ddab1f0cdfa8eda24636315bb45f3f9134cb41d43acc0
7
+ data.tar.gz: 90bef958997255122411c66e1801e8cf0300c85625750d8af6a921f3b3161d9cd97f1199637625cac3449de5176db8a9703dd0d31356eb61e31afb1a55bc569a
data/lib/aws/aws.rb ADDED
@@ -0,0 +1,9 @@
1
+ module App
2
+
3
+ class AWS
4
+
5
+ VALID_REGIONS = %w(ap-south-1 eu-west-3 eu-west-2 eu-west-1 ap-northeast-2 ap-northeast-1 sa-east-1 ca-central-1 ap-southeast-1 ap-southeast-2 eu-central-1 us-east-1 us-east-2 us-west-1 us-west-2)
6
+
7
+ end
8
+
9
+ end
data/lib/aws/aws_cli.rb CHANGED
@@ -65,40 +65,48 @@ module App
65
65
  end
66
66
 
67
67
  # Create a CloudFormation Stack.
68
- # @return Hash
69
- def self.cloudformation_stack_create(region, stack_name, s3_url, params: nil, tags: nil, capabilities: [])
68
+ # @return string (StackID)
69
+ def self.cloudformation_stack_create(region, stack_name, s3_url, params: nil, tags: nil, capabilities: [], term_protect: false, term_script: false, timeout: nil)
70
70
  params = params.nil? ? '' : " --parameters '#{params.gsub("'", "\\'")}'"
71
71
  tags = tags.nil? ? '' : " --tags '#{tags.gsub("'", "\\'")}'"
72
72
  capabilities = !capabilities.any? ? '' : " --capabilities #{capabilities.join(' ')}"
73
- command = "cloudformation create-stack --stack-name #{stack_name} --template-url #{s3_url}#{params}#{tags}#{capabilities}"
74
- stack_send = execute_as_proc("Sending CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", command, region, json: true)
73
+ term_protect = term_protect ? ' --enable-termination-protection' : ' --no-enable-termination-protection'
74
+ timeout = timeout.nil? ? '' : " --timeout-in-minutes #{timeout}"
75
+ command = "cloudformation create-stack --stack-name #{stack_name} --template-url #{s3_url}#{params}#{tags}#{capabilities}#{term_protect}#{timeout}"
76
+ App::AWSOutputter::output_cli_command("aws #{command} --region #{region} --profile #{App::AWSProfile::get_profile_name}")
77
+ puts
78
+ stack_send = execute_as_proc("Sending CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", command, region, json: true)
75
79
  begin
76
80
  if stack_send.has_key?('StackId')
77
- Blufin::Terminal::success('Template was accepted by AWS.', "\x1B[38;5;240mStackId \xe2\x80\x94 \x1B[38;5;40m#{stack_send['StackId']}")
78
- system("/usr/bin/open -a '/Applications/Google Chrome.app' https://#{region}.console.aws.amazon.com/cloudformation/home?region=#{region}#/stack/detail?stackId=#{URI::encode(stack_send['StackId'])}")
81
+ Blufin::Terminal::success('Template was accepted by AWS.', ["\x1B[38;5;240mStackId \xe2\x80\x94 \x1B[38;5;40m#{stack_send['StackId']}"])
82
+ stack_url = "https://#{region}.console.aws.amazon.com/cloudformation/home?region=#{region}#/stacks?filter=active&tab=events&stackId=#{URI::encode(stack_send['StackId'])}"
83
+ system("/usr/bin/open -a '/Applications/Google Chrome.app' '#{stack_url}'")
79
84
  else
80
85
  Blufin::Terminal::error("Key not found in response: #{Blufin::Terminal::format_invalid('StackId')}", stack_send.inspect, true)
81
86
  end
82
87
  rescue
83
88
  Blufin::Terminal::error('Stack was not accepted by AWS.', App::AWSCli::format_cli_error(stack_send), true)
84
89
  end
85
- stack_complete = execute_as_proc("Creating CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", "cloudformation wait stack-create-complete --stack-name #{stack_name}", region, json: true)
86
- if stack_complete.to_s.strip == ''
87
- puts
88
- puts " \x1B[38;5;40mCREATE_COMPLETE\x1B[0m"
89
- puts
90
- stack_details = execute_as_proc("Getting CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", "cloudformation describe-stacks --stack-name #{stack_name}", region, json: true)
91
- begin
92
- stack_json = JSON.parse(stack_details.to_json)
93
- raise RuntimeError, 'Not a Hash' unless stack_json.is_a?(Hash)
90
+ unless term_script
91
+ stack_complete = execute_as_proc("Creating CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", "cloudformation wait stack-create-complete --stack-name #{stack_name}", region, json: true)
92
+ if stack_complete.to_s.strip == ''
93
+ puts
94
+ puts " \x1B[38;5;40mCREATE_COMPLETE\x1B[0m"
94
95
  puts
95
- Blufin::Terminal::code_highlight(stack_json.to_yaml, 'yml', 4)
96
- rescue
97
- Blufin::Terminal::error('It seems you Stack was created (but then something went wrong).', stack_details.inspect, false)
96
+ stack_details = execute_as_proc("Getting CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", "cloudformation describe-stacks --stack-name #{stack_name}", region, json: true)
97
+ begin
98
+ stack_json = JSON.parse(stack_details.to_json)
99
+ raise RuntimeError, 'Not a Hash' unless stack_json.is_a?(Hash)
100
+ puts
101
+ Blufin::Terminal::code_highlight(stack_json.to_yaml, 'yml', 4)
102
+ rescue
103
+ Blufin::Terminal::error('It seems you Stack was created (but then something went wrong).', stack_details.inspect, false)
104
+ end
105
+ else
106
+ Blufin::Terminal::error("Something went wrong. Go to: #{Blufin::Terminal::format_highlight("https://#{region}.console.aws.amazon.com/cloudformation/home")} to see what happened.", format_cli_error(stack_complete.to_s), true)
98
107
  end
99
- else
100
- Blufin::Terminal::error("Something went wrong. Go to: #{Blufin::Terminal::format_highlight('https://us-west-2.console.aws.amazon.com/cloudformation/home')} to see what happened.", format_cli_error(stack_complete.to_s), true)
101
108
  end
109
+ stack_send['StackId']
102
110
  end
103
111
 
104
112
  # Use this when a common such as "aws do-something" returns an error (such as: Stack [cognito-public-pool-go-eat-local-albert] already exists).
@@ -122,12 +130,10 @@ module App
122
130
  raise RuntimeError, 'Must provide region.' if region.nil? || region.strip == ''
123
131
  raise RuntimeError, "Invalid region: #{region}" unless get_regions.include?(region) || region == REGION_SKIP
124
132
  begin
125
- region = region == REGION_SKIP ? '' : " --region #{region}"
126
- aws_credentials = App::AWSConfig.get_credentials(App::AWSConfig::AWS_PROFILE_ALBERT_CLI)
127
- region = aws_credentials.region if region.nil?
128
- puts "\x1B[38;5;70m$ \x1B[38;5;240maws #{command}#{region}\x1B[0m" if verbose
133
+ region = region == REGION_SKIP ? '' : " --region #{region}"
134
+ puts "\x1B[38;5;70m$ \x1B[38;5;240maws #{command}#{region} --profile #{App::AWSProfile::get_profile_name}\x1B[0m" if verbose
129
135
  if json
130
- result = `aws #{command}#{region} 2>/tmp/execute-output-aws`
136
+ result = `aws #{command}#{region} --profile #{App::AWSProfile::get_profile_name} 2>/tmp/execute-output-aws`
131
137
  # If no JSON, simply return the output.
132
138
  return `cat /tmp/execute-output-aws` if result == ''
133
139
  begin
@@ -136,12 +142,12 @@ module App
136
142
  raise RuntimeError, "JSON Parsing Failed:\n\n#{e.message}"
137
143
  end
138
144
  else
139
- result = system("aws #{command}#{region} &>/dev/null")
140
- raise RuntimeError, 'This command this not return a status code of 0 (Success).' unless result
145
+ result = system("aws #{command}#{region} --profile #{App::AWSProfile::get_profile_name} 1>/dev/null 2>/tmp/execute-output-aws")
146
+ `cat /tmp/execute-output-aws` unless result
141
147
  return result
142
148
  end
143
149
  rescue => e
144
- Blufin::Terminal::error("Command Failed: #{Blufin::Terminal::format_command("aws #{command}#{region}")}", e.message, true)
150
+ Blufin::Terminal::error("Command Failed: #{Blufin::Terminal::format_command("aws #{command}#{region} --profile #{App::AWSProfile::get_profile_name}")}", e.message, true)
145
151
  end
146
152
  end
147
153
 
@@ -149,7 +155,7 @@ module App
149
155
  # Set JSON to TRUE if you expect JSON output back, otherwise return value will be boolean (TRUE if successful).
150
156
  # Highly recommended to keep verbose set to FALSE.
151
157
  # @return void
152
- def self.execute_as_proc(title, command, region, json: false, verbose: false, catch_exception: false)
158
+ def self.execute_as_proc(title, command, region, json: false, verbose: false)
153
159
  output = nil
154
160
  threads = []
155
161
  threads << Thread.new {
@@ -157,7 +163,7 @@ module App
157
163
  }
158
164
  sleep(0.1)
159
165
  puts if verbose
160
- Blufin::Terminal::execute_proc("AWS - #{title}", Proc.new { threads.each { |thread| thread.join } })
166
+ Blufin::Terminal::execute_proc("AWS \xe2\x80\x94 #{title}", Proc.new { threads.each { |thread| thread.join } })
161
167
  output
162
168
  end
163
169
 
@@ -2,15 +2,10 @@ module App
2
2
 
3
3
  class AWSCloudFormation
4
4
 
5
- S3_BUCKET_CLOUDFORMATION = 'blufin-cloudformation-templates'
6
- S3_BUCKET_CLOUDFORMATION_REGION = 'us-west-2'
7
- PATH_CLOUDFORMATION = 'aws-cloudformation'
8
- FILE_CLOUDFORMATION_DEFAULTS = 'cloudformation.rb'
9
-
10
5
  # Gets the path to the root of the cloudformation templates in blufin-secrets repo.
11
6
  # @return string
12
- def self.get_cloudformation_path(path = PATH_CLOUDFORMATION)
13
- path = "#{App::Config.param(ConfigUnique::PATH_TO_REPO_SECRETS)}/#{path}"
7
+ def self.get_cloudformation_path
8
+ path = App::AWSProfile::get_profile['CloudFormation']['TemplatePath']
14
9
  Blufin::Terminal::error("CloudFormation path not found: #{Blufin::Terminal::format_directory(path)}", 'This probably means directories got renamed or code got changed.', true) unless Blufin::Files::path_exists(path)
15
10
  path
16
11
  end
@@ -19,48 +14,76 @@ module App
19
14
  # Returns the S3 URL.
20
15
  # @return string
21
16
  def self.upload_cloudformation_template(template_category, template_name, description)
22
- source = "#{get_cloudformation_path}/#{template_category}/#{template_name}/template.yml"
17
+ source = "#{get_cloudformation_path}/#{template_category}/#{template_name}/template.yml"
18
+ tmp_file = "/tmp/aws-cf-upload-#{template_category}-#{template_name}-#{Blufin::Strings::random_string}.yml"
23
19
  raise RuntimeError, "File does not exist: #{source}" unless Blufin::Files::file_exists(source)
24
- yml_data = YAML.load_file(File.expand_path(source))
25
- yml_data['Description'] = description
26
- description_written = false
27
- new_yaml = {}
28
- yml_data.keys.each do |key|
29
- if %w(AWSTemplateFormatVersion).include?(key)
30
- new_yaml[key] = yml_data[key]
20
+ Blufin::Terminal::execute("cp #{source} #{tmp_file}", text: "Preparing template: \x1B[38;5;240m#{tmp_file}\x1B[0m")
21
+ # Add description to final YML file.
22
+ Blufin::Files::write_line_to_file(tmp_file, "Description: \"#{description.gsub('"', '\"')}\"", /AWSTemplateFormatVersion:\s*("|')?[0-9\-]+("|')?/i)
23
+ # This block of code removes the 2nd description tag.
24
+ new_lines = []
25
+ description_found = false
26
+ parsing_parameters = true
27
+ Blufin::Files::read_file(tmp_file).each do |line|
28
+ line = line.gsub("\n", '')
29
+ if line.strip =~ /^description:/i
30
+ new_lines << line unless description_found
31
+ description_found = true
31
32
  else
32
- unless description_written
33
- description_written = true
34
- new_yaml['Description'] = description
33
+ parsing_parameters = true if line.strip =~ /^parameters:$/i
34
+ if parsing_parameters
35
+ # AWS Template Anatomy: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html
36
+ parsing_parameters = false if line.strip =~ /^(Metadata|Mappings|Conditions|Transform|Resources|Outputs)+:$/
37
+ # This skips all the parameter defaults (as they may contain weird data which won't pass regex validation when initially sent to AWS).
38
+ next if line.strip =~ /^default:/i && parsing_parameters
35
39
  end
36
- new_yaml[key] = yml_data[key] unless key == 'Description'
40
+ new_lines << line
37
41
  end
38
42
  end
39
- tmp_file = "/tmp/aws-cf-upload-#{template_category}-#{template_name}.yml"
40
- Blufin::Files::write_file(tmp_file, convert_string_to_line_array(new_yaml.to_yaml))
41
- App::AWSCli::s3_upload(tmp_file, S3_BUCKET_CLOUDFORMATION, get_template_filename(template_category, template_name))
43
+ Blufin::Files::write_file(tmp_file, new_lines)
44
+ template_filename = "#{template_category}-#{template_name}-#{DateTime.now.strftime('%Y%m%d-%H%M%S')}.yml"
45
+ bucket_path = get_s3_bucket_path
46
+ bucket_path = bucket_path == '' ? '' : "#{bucket_path}/"
47
+ App::AWSCli::s3_upload(tmp_file, App::AWSProfile::get_profile['CloudFormation']['S3Bucket'], "#{bucket_path}#{template_filename}")
48
+ # Return the S3 bucket URL.
49
+ "#{get_s3_bucket_url}/#{template_filename}"
42
50
  end
43
51
 
44
- # Gets the S3 bucket URL.
52
+ # Returns S3 bucket URL based on config parameters.
45
53
  # @return string
46
- def self.get_cloudformation_s3_bucket_url(template_category, template_name)
47
- "https://#{S3_BUCKET_CLOUDFORMATION}.s3-#{S3_BUCKET_CLOUDFORMATION_REGION}.amazonaws.com/#{get_template_filename(template_category, template_name)}"
54
+ def self.get_s3_bucket_url
55
+ bucket_path = get_s3_bucket_path
56
+ bucket_path = bucket_path == '' ? '' : "/#{bucket_path}"
57
+ "https://#{App::AWSProfile::get_profile['CloudFormation']['S3Bucket']}.s3-#{App::AWSProfile::get_profile['CloudFormation']['S3BucketRegion']}.amazonaws.com#{bucket_path}"
48
58
  end
49
59
 
50
- # Converts cognito/private-pool to -> cognito-private-pool.yml
60
+ # Returns the S3 bucket path based on config parameters.
51
61
  # @return string
52
- def self.get_template_filename(template_category, template_name)
53
- "#{template_category}-#{template_name}.yml"
62
+ def self.get_s3_bucket_path
63
+ bucket_path = App::AWSProfile::get_profile['CloudFormation']['S3BucketPath']
64
+ bucket_path.nil? || bucket_path.to_s.strip == '' ? '' : bucket_path
54
65
  end
55
66
 
56
- # Converts a string to an Array of lines to a string.
57
- # @return String
58
- # TODO - Must move Blufin::YmlCommon from blufin -> blufin-lib. Not sure what the damage will be... 07/08/2019.
59
- def self.convert_string_to_line_array(string)
60
- raise RuntimeError, "Expected String, instead got: #{string.class}" unless string.is_a?(String)
61
- array_of_lines = []
62
- string.split("\n").each { |line| array_of_lines << line.gsub("\n", '') }
63
- array_of_lines
67
+ # Returns an array of cloudformation stack-names.
68
+ # @return Array of Hashes
69
+ def self.get_stacks
70
+ results = []
71
+ json = Blufin::Terminal::execute('awx l -r CloudFormationStacks -j', capture: true, text: "AWS \xe2\x80\x94 Getting CloudFormation Stacks...")
72
+ begin
73
+ data = JSON.parse(json)
74
+ rescue => e
75
+ puts
76
+ puts json
77
+ Blufin::Terminal::error('Failed to parse AWS response JSON.', e.message)
78
+ end
79
+ data.each do |stack|
80
+ results << {
81
+ :name => stack['StackName'],
82
+ :region => stack['region']
83
+ }
84
+ end
85
+ results.sort_by! { |hsh| hsh[:name] }
86
+ results
64
87
  end
65
88
 
66
89
  end
@@ -91,7 +91,7 @@ module App
91
91
  column('Max-L', :width => column_short, :color => HEADER_COLOR)
92
92
  column('Min-V', :width => column_short, :color => HEADER_COLOR)
93
93
  column('Max-V', :width => column_short, :color => HEADER_COLOR)
94
- column('Cached Value(s)', :width => remaining, :color => HEADER_COLOR)
94
+ column('Cached/Default Value(s)', :width => remaining, :color => HEADER_COLOR)
95
95
  column('', :width => 2, :color => HEADER_COLOR)
96
96
  end
97
97
  row do
@@ -109,7 +109,13 @@ module App
109
109
  mav = data[:max_value]
110
110
  cop = 'light-green'
111
111
  cop = 'purple' if data[:type_internal] == :autocomplete
112
- cop = 'yellow' if data[:type_internal] == :system || [AppCommand::AWSCloudFormationCreate::OPTION_STACK_NAME, AppCommand::AWSCloudFormationCreate::OPTION_DESCRIPTION].include?(data[:parameter])
112
+ cop = 'light-grey' if data[:type_internal] == :system || [
113
+ AppCommand::AWSCloudFormationCreate::OPTION_STACK_NAME,
114
+ AppCommand::AWSCloudFormationCreate::OPTION_PROJECT_ID,
115
+ AppCommand::AWSCloudFormationCreate::OPTION_DESCRIPTION,
116
+ AppCommand::AWSCloudFormationCreate::OPTION_TERM_PROTECT,
117
+ AppCommand::AWSCloudFormationCreate::OPTION_TIMEOUT
118
+ ].include?(data[:parameter])
113
119
  # In case you want to change color in future, currently this is redundant.
114
120
  cod = data[:type_internal] == :system ? 'default' : 'default'
115
121
  cot = data[:type_internal] == :system ? 'default' : 'default'
@@ -152,10 +158,15 @@ module App
152
158
  # @return void
153
159
  def self.get_formatter(key = nil, resource: nil, color: 'default')
154
160
  formatters = {
161
+ 'cloudformation-stack' => Proc.new { |n|
162
+ [n.gsub(/^arn:aws:cloudformation:[a-z]{2}-[a-z]{2,12}-\d+\D?:\d{10,14}:stack\//, ''), color]
163
+ },
155
164
  'cloudfront-status' => Proc.new { |n|
156
165
  case n
157
166
  when 'Deployed'
158
167
  color = 'green'
168
+ when 'InProgress'
169
+ color = 'orange'
159
170
  else
160
171
  Blufin::Terminal::output("Add something to aws_outputter switch statement for: #{n}", Blufin::Terminal::MSG_TODO)
161
172
  color = 'default'
@@ -188,6 +199,7 @@ module App
188
199
  color = 'dark-grey'
189
200
  when 'terminated'
190
201
  color = 'red'
202
+
191
203
  else
192
204
  Blufin::Terminal::output("Add something to aws_outputter switch statement for: #{n}", Blufin::Terminal::MSG_TODO)
193
205
  color = 'default'
@@ -203,11 +215,15 @@ module App
203
215
  region = n.ljust(10, ' ')
204
216
  [region, region_color]
205
217
  },
218
+ 'route-53-domain-name' => Proc.new { |n|
219
+ [n.gsub(/\.$/, ''), color]
220
+ },
206
221
  'route-53-hosted-zone-id' => Proc.new { |n|
207
222
  zone_color = color
208
223
  ns = n.split('/')
209
224
  [ns[ns.length - 1], zone_color]
210
225
  },
226
+
211
227
  }
212
228
  raise RuntimeError, "Key not found: #{key}" unless key.nil? || formatters.has_key?(key)
213
229
  return formatters.keys if key.nil?
@@ -242,6 +258,21 @@ module App
242
258
  (width == '*') ? wildcard_width : width
243
259
  end
244
260
 
261
+ # Standardized way of outputting a command.
262
+ # @return void
263
+ def self.output_cli_command(command, path = nil)
264
+ puts " \x1B[38;5;70m$ \x1B[38;5;240m#{command}\x1B[0m" if path.nil?
265
+ puts " \x1B[38;5;70m$ \x1B[38;5;240m#{command} [\x1B[38;5;246m#{path}\x1B[240m]\x1B[0m" unless path.nil?
266
+ end
267
+
268
+ # Standardized way of rendering selection output.
269
+ # @return string
270
+ def self.render_selection(primary, secondary = nil, tertiary = nil)
271
+ return "#{Blufin::Terminal::format_action(primary)} \x1B[38;5;240m[#{Blufin::Terminal::format_highlight(secondary)}\x1B[38;5;240m]\x1B[38;5;240m[#{Blufin::Terminal::format_highlight(tertiary)}\x1B[38;5;240m]" if !tertiary.nil? && !secondary.nil?
272
+ return "#{Blufin::Terminal::format_action(primary)} \x1B[38;5;240m[#{Blufin::Terminal::format_highlight(secondary)}\x1B[38;5;240m]" unless secondary.nil?
273
+ return "#{Blufin::Terminal::format_action(primary)}" if secondary.nil?
274
+ end
275
+
245
276
  end
246
277
 
247
278
  end
@@ -0,0 +1,116 @@
1
+ module App
2
+
3
+ class AWSProfile
4
+
5
+ @@profiles = nil
6
+ @@profile = nil
7
+ @@credentials = nil
8
+
9
+ FILE_AWS_CONFIG = File.expand_path('~/.aws/config')
10
+ FILE_AWS_CREDENTIALS = File.expand_path('~/.aws/credentials')
11
+ PROFILE_DEFAULT = 'DefaultProfile'
12
+ PROFILE = 'Profile'
13
+ PROFILES = 'Profiles'
14
+ CLOUDFORMATION = 'CloudFormation'
15
+
16
+ # Reads the config data and decides what profile to use.
17
+ # @return void
18
+ def self.init(config_data)
19
+
20
+ raise RuntimeError, 'Cannot run App::AWSProfile::init more than once.' unless @@profiles.nil? && @@profile.nil? && @@credentials.nil?
21
+
22
+ @@profiles = {}
23
+ @@profile = {}
24
+
25
+ first_key = nil
26
+
27
+ # Put all the profiles in a global Hash.
28
+ config_data[PROFILES].each do |profile|
29
+ first_key = profile[PROFILE] if first_key.nil?
30
+ @@profiles[profile[PROFILE]] = profile
31
+ end
32
+
33
+ if @@profiles.length == 1
34
+ @@profile = @@profiles[first_key]
35
+ elsif @@profiles.length > 1
36
+ if config_data[PROFILE_DEFAULT].nil?
37
+ Blufin::Terminal::error('No default profile found.', "When more than 1 profile is specified, you must also specify a #{Blufin::Terminal::format_highlight('DefaultProfile:')}", true)
38
+ elsif !@@profiles.keys.include?(config_data[PROFILE_DEFAULT])
39
+ Blufin::Terminal::error("Invalid profile: #{Blufin::Terminal::format_invalid(config_data[PROFILE_DEFAULT])}. Available profiles are:", @@profiles.keys, true)
40
+ else
41
+ @@profile = @@profiles[config_data[PROFILE_DEFAULT]]
42
+ end
43
+ else
44
+ raise RuntimeError, 'No profiles found.'
45
+ end
46
+
47
+ errors = []
48
+
49
+ # Validate CloudFormation data (if exists)
50
+ if @@profile.has_key?(CLOUDFORMATION)
51
+ cloudformation_template_path = @@profile[CLOUDFORMATION]['TemplatePath']
52
+ s3_region = @@profile[CLOUDFORMATION]['S3BucketRegion']
53
+ default_regions = @@profile[CLOUDFORMATION]['Defaults']['Regions']
54
+ errors << "Path not found: #{Blufin::Terminal::format_invalid(cloudformation_template_path)}" unless Blufin::Files::path_exists(cloudformation_template_path)
55
+ errors << "Invalid region: #{Blufin::Terminal::format_invalid(s3_region)}" unless App::AWS::VALID_REGIONS.include?(s3_region)
56
+ errors << "Need atleast 1 default region for: #{Blufin::Terminal::format_invalid('Profiles[].CloudFormation.Defaults.Regions')}" if default_regions.nil? || !default_regions.any?
57
+ default_regions.each do |default_region|
58
+ errors << "Invalid region: #{Blufin::Terminal::format_invalid(default_region)}" unless App::AWS::VALID_REGIONS.include?(default_region)
59
+ end
60
+ end
61
+
62
+ # Check the credentials exist.
63
+ if Blufin::Files::file_exists(FILE_AWS_CREDENTIALS)
64
+ @@aws_credentials = App::AWSCredentials.new
65
+ profile = @@profile[PROFILE]
66
+ config = Blufin::Files::file_exists(FILE_AWS_CONFIG) ? ParseConfig.new(FILE_AWS_CONFIG) : nil
67
+ credentials = ParseConfig.new(FILE_AWS_CREDENTIALS)
68
+ unless credentials.params[profile].nil?
69
+ # Currently not used/required (but here just in case).
70
+ unless config.nil? || config.params[profile].nil?
71
+ @@aws_credentials.region = config.params[profile]['region'] unless config.params[profile]['region'].nil?
72
+ @@aws_credentials.output = config.params[profile]['output'] unless config.params[profile]['output'].nil?
73
+
74
+ end
75
+ @@aws_credentials.aws_key = credentials.params[profile]['aws_access_key_id'] unless credentials.params[profile]['aws_access_key_id'].nil?
76
+ @@aws_credentials.aws_secret = credentials.params[profile]['aws_secret_access_key'] unless credentials.params[profile]['aws_secret_access_key'].nil?
77
+ end
78
+ errors << "aws-cli error. Cannot find #{profile}: #{Blufin::Terminal::format_invalid('aws_access_key_id')} in: #{Blufin::Terminal::format_directory(FILE_AWS_CREDENTIALS)}" if @@aws_credentials.aws_key.nil?
79
+ errors << "aws-cli error. Cannot find #{profile}: #{Blufin::Terminal::format_invalid('aws_secret_access_key')} in: #{Blufin::Terminal::format_directory(FILE_AWS_CREDENTIALS)}" if @@aws_credentials.aws_secret.nil?
80
+ else
81
+ errors << "aws-cli error. Cannot find file: #{Blufin::Terminal::format_invalid(FILE_AWS_CREDENTIALS)}"
82
+ end
83
+
84
+ # If anything is wrong, output error(s).
85
+ Blufin::Config::invalid_configuration(App::GEM_NAME, errors) if errors.any?
86
+
87
+ end
88
+
89
+ # Gets the active profile.
90
+ # @return Hash
91
+ def self.get_profile
92
+ @@profile
93
+ end
94
+
95
+ # Convenience method to just get the profile name.
96
+ # @return string
97
+ def self.get_profile_name
98
+ @@profile[PROFILE]
99
+ end
100
+
101
+ # Returns an Array of all available profile names (not the entire profile).
102
+ # @return Array
103
+ def self.get_profile_names
104
+ @@profiles.keys
105
+ end
106
+
107
+ # Gets AWS credentials from ~/.aws directory for given profile.
108
+ # If credentials don't exist (or are missing information) -- nil is returned.
109
+ # @return App::AWSCredentials
110
+ def self.get_credentials
111
+ @@aws_credentials
112
+ end
113
+
114
+ end
115
+
116
+ end